Contexto
Me encontré con un error persistente de autenticación de API al ejecutar Chatwoot en una implementación de CapRover. Mi objetivo era usar el API de Chatwoot para automatizar flujos de trabajo de mensajería. Sin embargo, cada solicitud de API que enviaba desde cualquier fuente, incluso desde curl, fallaba, a pesar de usar el api_access_token correcto.
Tras investigar, sospeché que el problema no estaba en Chatwoot en sí ni en mis credenciales, sino en el proxy inverso Nginx que CapRover utiliza para gestionar el tráfico entrante.
El Problema
Todas las solicitudes de API a la instancia de Chatwoot fallaban con un estado 401 Unauthorized y la siguiente respuesta de error en JSON:
{
"error": "You need to sign in or sign up before continuing."
}
Esto indicaba que la aplicación Chatwoot no estaba recibiendo los encabezados (headers) de autenticación correctamente. El problema radicaba en el comportamiento predeterminado de Nginx, que elimina silenciosamente los encabezados que contienen guiones bajos (_), una convención de la que depende la API de Chatwoot para sus tokens.
Entorno
- Aplicación: Chatwoot (v3.0 y posteriores)
- Plataforma de Despliegue: CapRover en un servidor en la nube
- Servidor Web: Nginx (gestionado por CapRover)
Solución
La solución consiste en personalizar la configuración de Nginx para la aplicación Chatwoot dentro de CapRover para permitir explícitamente encabezados con guiones bajos. Esto asegura que el api_access_token llegue a la aplicación Chatwoot.
Pasos a seguir
-
Accede al Dashboard de CapRover: Inicia sesión en tu instancia de CapRover.
-
Navega a la Aplicación de Chatwoot: Ve a la sección Apps y selecciona tu aplicación chatwoot-web.
-
Edita la Configuración de Nginx: Dirígete a la pestaña HTTP Settings y busca el área de texto Custom Nginx Config.
-
Añade la directiva
underscores_in_headers: Debes añadir una sola línea al bloqueserverprincipal. Un buen lugar es justo después de la directivaserver_name.
Aquí tienes la configuración de Nginx completa y modificada. Puedes reemplazar todo el contenido del área de texto con el bloque de abajo:
<%
if (s.forceSsl) {
%>
server {
listen 80;
server_name <%-s.publicDomain%>;
# Usado por Lets Encrypt
location /.well-known/acme-challenge/ {
root <%-s.staticWebRoot%>;
}
# Usado por CapRover para health check
location /.well-known/captain-identifier {
root <%-s.staticWebRoot%>;
}
location / {
return 302 https://$http_host$request_uri;
}
}
<%
}
%>
server {
<%
if (!s.forceSsl) {
%>
listen 80;
<%
}
if (s.hasSsl) {
%>
listen 443 ssl;
http2 on;
ssl_certificate <%-s.crtPath%>;
ssl_certificate_key <%-s.keyPath%>;
<%
}
if (s.logAccessPath) {
%>
access_log <%-s.logAccessPath%>;
<%
}
%>
client_max_body_size 500m;
server_name <%-s.publicDomain%>;
# <<< ESTA ES LA SOLUCIÓN >>>
# Permitir encabezados con guiones bajos para la API de Chatwoot (ej. api_access_token)
underscores_in_headers on;
resolver 127.0.0.11 valid=10s;
set $upstream http://<%-s.localDomain%>:<%-s.containerHttpPort%>;
location / {
<%
if (s.redirectToPath) {
%>
return 302 <%-s.redirectToPath%>$request_uri;
<%
} else {
%>
<%
if (s.httpBasicAuthPath) {
%>
auth_basic "Restricted Access";
auth_basic_user_file <%-s.httpBasicAuthPath%>;
<%
}
%>
proxy_pass $upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
<%
if (s.websocketSupport) {
%>
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
<%
}
%>
<%
}
%>
}
# Usado por Lets Encrypt
location /.well-known/acme-challenge/ {
root <%-s.staticWebRoot%>;
}
# Usado por CapRover para health check
location /.well-known/captain-identifier {
root <%-s.staticWebRoot%>;
}
error_page 502 /captain_502_custom_error_page.html;
location = /captain_502_custom_error_page.html {
root <%-s.customErrorPagesDirectory%>;
internal;
}
}
-
Guardar y Actualizar: Haz clic en el botón Save & Update. CapRover validará y desplegará la nueva configuración, reiniciando la aplicación.
-
Prueba la Conexión de la API: Vuelve a ejecutar tu solicitud de API. El error
401 Unauthorizeddebería haber desaparecido y la conexión debería funcionar como se espera.
¿Por qué funciona esto?
El problema es un conflicto entre la política de seguridad predeterminada de Nginx y el diseño de la API de Chatwoot.
- Comportamiento predeterminado de Nginx: Para evitar posibles ambigüedades y problemas de seguridad (como conflictos con variables CGI), la configuración por defecto de Nginx ignora silenciosamente cualquier encabezado HTTP que contenga guiones bajos (
_). - Requisito de la API de Chatwoot: La API de Chatwoot, como muchas aplicaciones construidas sobre Ruby on Rails, utiliza encabezados con guiones bajos (ej.
api_access_token) para la autenticación.
Al añadir la directiva underscores_in_headers on;, anulamos el comportamiento predeterminado de Nginx y le indicamos que pase estos encabezados a la aplicación Chatwoot. Una vez que la aplicación recibe el token correcto, puede autenticar la solicitud con éxito.
Notas Adicionales
Este es un problema común para otras aplicaciones desplegadas detrás de Nginx, no solo para Chatwoot. Si te enfrentas a errores de autenticación de API inexplicables, verificar cómo el proxy maneja los encabezados es un buen paso de depuración.
Esta corrección debe aplicarse a la aplicación chatwoot-web, que es el punto de entrada público, y no a la aplicación chatwoot-worker.
Conclusión
Este pequeño ajuste en Nginx resolvió por completo el problema de autenticación de la API para mi instancia de Chatwoot en CapRover. Espero que esta guía detallada ahorre a otros la frustración de depurar este problema.
¡Feliz automatización!