SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor

Instalar Chatwoot en VPS con Docker y Traefik

Guía para desplegar Chatwoot mediante Docker Compose. Incluye configuración de SMTP, persistencia de Postgres, gestión de backups y actualización segura de contenedores en producción.

Lo que está construyendo

Para alojar Chatwoot en un VPS, ejecutará cuatro contenedores: un proceso web de Rails, un trabajador en segundo plano de Sidekiq, PostgreSQL con la extensión pgvector y Redis. Chatwoot es una plataforma de atención al cliente de código abierto, por lo que obtendrá una bandeja de entrada compartida para el equipo y un widget de chat para su sitio web en un servidor bajo su control. La instalación toma aproximadamente veinte minutos. Todo lo posterior, como la entrega de correo, las copias de seguridad, las actualizaciones y el dimensionamiento, es lo que determinará si el sistema seguirá funcionando dentro de un año.

Cada contenedor tiene una función específica. Rails sirve el panel de control del agente y la API (interfaz de programación de aplicaciones) del widget. Sidekiq ejecuta las tareas lentas: enviar correos electrónicos, consultar canales conectados, ejecutar reglas de automatización y generar informes. Postgres almacena las conversaciones, los contactos, las cuentas de los agentes y cada configuración que modifique en el panel. Redis mantiene las colas de Sidekiq y el canal de publicación/suscripción de ActionCable, que envía un mensaje nuevo a un panel abierto sin necesidad de recargar la página. En este caso, Redis no es una caché desechable, ya que perder su contenido implica perder los trabajos en cola.

La imagen de Postgres en el archivo compose original es pgvector/pgvector:pg16 en lugar de la imagen estándar postgres, debido a que el esquema de Chatwoot habilita la extensión vector para sus funciones de IA. Si utiliza la imagen estándar de Postgres, la primera ejecución de la base de datos se detendrá con un error ERROR: extension "vector" is not available, ya que el archivo de control de la extensión no se encuentra en esa imagen. Utilice la imagen que proporciona el desarrollador.

Esta guía asume que Docker y un proxy inverso ya funcionan en el servidor. Si no es así, comience por Docker Compose en un VPS y regrese después.

¿Cuánta capacidad necesita un VPS para alojar Chatwoot?

A fecha de octubre de 2026, la página de requisitos del proyecto indica 4 GB de RAM y 4 núcleos de CPU como mínimo, y estima que esa configuración admite hasta 10,000 conversaciones al día. Para 8 GB y 8 núcleos, estima hasta 20,000 conversaciones al día. También solicita al menos 1 GB de swap y explica el motivo: evitar que la máquina se quede sin memoria durante una actualización. Reserve entre 5 GB y 10 GB de disco para Postgres, sin contar las cargas de archivos.

Ahora, la parte directa. Un VPS de 2 GB iniciará Chatwoot y puede funcionar bien con dos agentes y una bandeja de entrada con poca actividad. Falla en dos situaciones. La primera es Sidekiq, cuyo consumo en un servidor ocupado supera 1 GB según el proyecto. Un pico de correo electrónico o una tarea de informes puede llevar al servidor más allá de su memoria disponible antes de que Rails, Postgres y Redis consuman su parte. La segunda es la actualización, porque db:chatwoot_prepare inicia un proceso de Rails nuevo para aplicar las migraciones. En esta imagen, el arranque de Rails consume cientos de megabytes antes de realizar cualquier trabajo útil.

No verá primero una advertencia clara. El terminador de procesos por falta de memoria del kernel envía SIGKILL al proceso que selecciona, normalmente el más grande. Docker detecta que el contenedor ha terminado y restart: always lo inicia de nuevo. docker compose ps --all muestra entonces un contenedor que se reinicia continuamente o permanece en Exited (137), donde 137 significa que el proceso terminó por la señal 9. Si omite --all, un contenedor detenido ni siquiera aparece en la lista. El código de salida 137 por sí solo no demuestra que la causa fuera la memoria, porque docker kill envía la misma señal. Confírmelo con sudo dmesg -T | grep -i "killed process", que identifica el proceso seleccionado por el kernel.

Si 4 GB quedan fuera del presupuesto, puede ejecutar el sistema con 2 GB y 2 GB de swap, pero debe aceptar que los tiempos de respuesta empeorarán con carga. La swap sirve como margen para evitar quedarse sin memoria, pero no es una garantía. Un pico suficientemente grande todavía puede hacer que se termine un contenedor. En cualquier caso, conviene establecer un límite de memoria estricto para cada servicio. Así, el worker no puede provocar también la caída de la base de datos. Consulte los límites de memoria en Docker Compose.

Las cargas de archivos son el componente que crece sin un límite establecido por usted. Cada captura de pantalla que adjunta un cliente se almacena en el volumen de almacenamiento y permanece allí. Por tanto, supervise docker system df -v en lugar de asumir que la base de datos es la que ha llenado el disco.

Obtenga el archivo de Compose y fije una etiqueta de versión

mkdir -p ~/chatwoot && cd ~/chatwoot
wget -O .env https://raw.githubusercontent.com/chatwoot/chatwoot/develop/.env.example
wget -O docker-compose.yaml https://raw.githubusercontent.com/chatwoot/chatwoot/develop/docker-compose.production.yaml
chmod 600 .env

El archivo que acaba de descargar indica image: chatwoot/chatwoot:latest. Cámbielo antes de hacer cualquier otra cosa.

services:
  base: &base
    image: chatwoot/chatwoot:v4.18.0
    env_file: .env
    volumes:
      - storage_data:/app/storage

latest significa que el siguiente docker compose pull le entrega lo que se haya publicado esa mañana. Puede ser una versión principal con migraciones que no se documentaron. En la práctica, las migraciones de Chatwoot no se pueden revertir. Un salto accidental exige restaurar una copia de seguridad; no se puede deshacer. Fije la etiqueta y cámbiela de forma deliberada. v4.18.0 era la versión actual en octubre de 2026, y sus notas de la versión la recomiendan por sus correcciones de seguridad. Consulte la página de versiones para saber qué etiqueta debe fijar hoy. Todo componente que administre una base de datos requiere la misma precaución. Por eso, alojar el rastreador de entrenamientos openGym comienza fijando una etiqueta de git, aunque es una aplicación mucho más pequeña que esta.

El servicio base es un ancla YAML que rails y sidekiq combinan mediante una combinación. Por tanto, cambiar la etiqueta en un solo lugar la cambia para ambos. Mientras esté en el archivo, elimine la línea version: '3' de la parte superior. Las versiones modernas de Compose la ignoran y muestran the attribute 'version' is obsolete, it will be ignored en cada comando.

Complete el archivo .env

Genere primero el secreto. El proveedor recomienda un valor alfanumérico, ya que los caracteres especiales pueden corromperse cuando el valor pasa a través de una shell o un analizador YAML.

head /dev/urandom | tr -dc A-Za-z0-9 | head -c 63 ; echo ''

A continuación, defina estas claves en .env.

SECRET_KEY_BASE=<the 63 characters you just generated>
FRONTEND_URL=https://support.example.com
FORCE_SSL=true
DEFAULT_LOCALE=en
ENABLE_ACCOUNT_SIGNUP=true

POSTGRES_HOST=postgres
POSTGRES_USERNAME=postgres
POSTGRES_PASSWORD=<long random string>
POSTGRES_DATABASE=chatwoot

REDIS_URL=redis://redis:6379
REDIS_PASSWORD=<a different long random string>

RAILS_ENV=production
INSTALLATION_ENV=docker
ACTIVE_STORAGE_SERVICE=local

POSTGRES_HOST=postgres y redis://redis:6379 son los nombres de los servicios de Compose, los cuales se resuelven en la red predeterminada del proyecto. FRONTEND_URL no es un elemento decorativo. Chatwoot construye la URL del script del widget y cada enlace dentro de los correos electrónicos salientes; por lo tanto, un valor incorrecto provocará que los enlaces de restablecimiento de contraseña apunten a un host que no responde.

Ahora, la trampa en el archivo del proveedor. El servicio postgres no lee .env. Contiene su propio bloque environment con POSTGRES_PASSWORD= vacío, por lo que establecer la contraseña solo en .env deja a la base de datos sin contraseña y a la aplicación con una. Apunte el servicio a la misma variable:

  postgres:
    image: pgvector/pgvector:pg16
    restart: always
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=chatwoot
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}

Compose lee .env desde el directorio del proyecto para la sustitución de ${...}, por lo que ambos lados obtienen ahora la misma cadena. Si esto es incorrecto, Rails se detendrá con PG::ConnectionBad: FATAL: password authentication failed for user "postgres".

Un comportamiento sorprende a casi todo el mundo: la imagen de Postgres solo aplica POSTGRES_PASSWORD cuando inicializa un directorio de datos vacío. Cambiar el valor posteriormente no tiene efecto, ya que initdb nunca se ejecuta una segunda vez. Si ya ha iniciado el stack una vez, cámbielo directamente dentro de la base de datos.

docker compose exec postgres psql -U postgres -c "ALTER USER postgres WITH PASSWORD 'the-new-password';"

ENABLE_ACCOUNT_SIGNUP=true es temporal. Abre el formulario de registro público para que pueda crear la primera cuenta. Establézcalo en false y ejecute docker compose up -d de nuevo tan pronto como su cuenta exista, o cualquier persona que encuentre la URL podrá registrarse en su mesa de ayuda. A partir de ese momento, los agentes llegan mediante invitación y sus contraseñas residen solo en esta aplicación, lo cual es aceptable hasta que ejecute media docena de servicios y se canse de gestionar una lista de cuentas separada en cada uno; en ese punto, un proveedor de identidad autohospedado como Authentik es la pieza que los reemplaza.

.env contiene ahora todos los secretos de este stack en texto plano, así que manténgalo en modo 600 y fuera de git. Cómo lee Compose los archivos env y dónde se filtran los secretos cubre los riesgos, incluida la diferencia entre env_file y environment.

Ponga Chatwoot detrás de su Traefik existente

No cree un segundo proxy inverso para una sola aplicación. Si Traefik ya termina TLS (seguridad de la capa de transporte) para otros contenedores en este servidor, Chatwoot se une a él mediante un bloque de etiquetas. Si aún no lo tiene, configúrelo una vez siguiendo Traefik frente a varias aplicaciones de Docker Compose, y luego regrese aquí.

Mantenga el docker-compose.yaml del proveedor lo más parecido posible al original para poder compararlo con una versión más reciente más adelante, y coloque sus cambios en un archivo de anulación. Compose combina docker-compose.override.yaml automáticamente, y dividir Compose en varios archivos explica las reglas de combinación.

services:
  rails:
    networks:
      - default
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.chatwoot.rule=Host(`support.example.com`)"
      - "traefik.http.routers.chatwoot.entrypoints=websecure"
      - "traefik.http.routers.chatwoot.tls.certresolver=letsencrypt"
      - "traefik.http.services.chatwoot.loadbalancer.server.port=3000"

networks:
  proxy:
    external: true

Utilice sus propios nombres de entrypoint y certresolver. El contenedor debe estar en la misma red de Docker que Traefik, que es lo que hace la entrada proxy, y también debe permanecer en default o perderá la conexión con Postgres y Redis. Esa segunda línea es la que la gente suele olvidar.

Deje el bloque ports: intacto. El proveedor lo vincula a 127.0.0.1:3000, que es solo para loopback, por lo que no es accesible desde Internet y sigue siendo útil para realizar pruebas desde dentro del servidor con curl -I http://127.0.0.1:3000.

El panel de control del agente mantiene un websocket abierto a /cable para la entrega de mensajes en tiempo real. Traefik reenvía la actualización HTTP sin configuración adicional, por lo que no hay nada que añadir. Si más adelante coloca una CDN u otro proxy frente a Traefik, permita los websockets allí, ya que el síntoma es un panel de control que se carga normalmente mientras los mensajes nuevos solo aparecen después de una actualización manual.

Inicializar la base de datos e iniciar el stack

Inicie primero los servicios de datos y permita que Postgres finalice su primera ejecución.

docker compose up -d postgres redis
docker compose logs postgres | tail -n 5

Espere a database system is ready to accept connections. A continuación, cree el esquema.

docker compose run --rm rails bundle exec rails db:chatwoot_prepare

Esto crea la base de datos si no existe y, posteriormente, carga el esquema y los datos iniciales predeterminados. El proceso imprime las líneas de migración y finaliza correctamente. Si el proceso se queda imprimiendo postgres:5432 - no response, el punto de entrada está esperando una base de datos que aún no acepta conexiones, lo cual, en una primera ejecución, suele significar que initdb sigue trabajando. Espere, revise los registros de Postgres y vuelva a ejecutarlo. Si se detiene en la extensión vector, significa que reemplazó la imagen pgvector con la versión estándar de Postgres.

docker compose up -d
docker compose ps
docker compose logs --tail 30 rails

Los cuatro contenedores deberían mostrar Up y el registro de rails debería terminar con una línea de Puma escuchando en http://0.0.0.0:3000. Luego, verifique la ruta pública:

curl -sI https://support.example.com | head -n 1

HTTP/2 200 significa que toda la cadena funciona. Un error 404 de Traefik indica que la regla de enrutamiento no coincidió, generalmente debido a un error tipográfico en el nombre de host. Un error 502 significa que Traefik encontró el router pero no pudo alcanzar el contenedor, lo cual casi siempre se debe a la falta de la red proxy o a que el loadbalancer.server.port no es 3000.

Abra la URL, cree su cuenta en /app/auth/signup, configure ENABLE_ACCOUNT_SIGNUP=false y ejecute docker compose up -d para cerrar el formulario.

Por qué fallan los restablecimientos de contraseña y las conversaciones por correo sin SMTP

Chatwoot sin la configuración de SMTP (protocolo simple de transferencia de correo) es una mesa de soporte que no puede enviar mensajes, y eso rompe más que las notificaciones. Los restablecimientos de contraseña dejan de funcionar, por lo que un administrador que pierde el acceso no puede recuperarlo. Las invitaciones a agentes dejan de funcionar porque una invitación se envía por correo. Las respuestas a un cliente en una conversación por correo dejan de funcionar, por lo que la conversación sólo funciona en un sentido. Este es el paso que muchos omiten y descubren durante su peor semana.

El mecanismo es sencillo. Si no se define SMTP_ADDRESS, Chatwoot cambia ActionMailer al método de entrega sendmail. La documentación oficial lo describe como su configuración de Postfix, que es la opción predeterminada desde v2.12.0, y sus instrucciones instalan Postfix en el servidor mediante sudo apt install -y postfix. Esta configuración de Docker no hace eso, por lo que no hay ningún servidor de correo configurado al que ese método de entrega pueda entregar los mensajes. El correo se envía desde un trabajo en segundo plano, por lo que cualquier error producido por el método de entrega aparece en el registro de Sidekiq y nunca en el registro de Rails. Mientras tanto, la persona que hace clic en "forgot password" ve una confirmación tranquilizadora, pero no recibe nada.

MAILER_SENDER_EMAIL=Support <support@example.com>
SMTP_DOMAIN=example.com
SMTP_ADDRESS=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=support@example.com
SMTP_PASSWORD=<the relay password>
SMTP_AUTHENTICATION=plain
SMTP_ENABLE_STARTTLS_AUTO=true

Use el puerto 587 con STARTTLS. Este protocolo abre la conexión en texto sin cifrar y la actualiza a una conexión cifrada antes de la autenticación. La mayoría de los proveedores de VPS bloquean el puerto saliente 25 para limitar el spam, por lo que un relay en el puerto 587 suele ser la única opción que permite establecer la conexión. SMTP_DOMAIN es el dominio que anuncia su servidor durante la conversación SMTP, y algunos relays rechazan las discrepancias.

Aplique la configuración y supervise el worker:

docker compose up -d rails sidekiq
docker compose logs -f sidekiq

Inicie un restablecimiento de contraseña desde la página de inicio de sesión. Una entrega correcta muestra que el trabajo del mailer finaliza normalmente en el registro de Sidekiq. Un fallo muestra la clase de excepción y después Sidekiq vuelve a intentarlo con un intervalo creciente, por lo que un relay defectuoso produce el mismo error cada pocos minutos durante horas.

Hay dos rechazos habituales, y ninguno es un error de Chatwoot. 535 Authentication failed significa que el nombre de usuario o la contraseña no son correctos para ese relay. Muchos proveedores exigen una contraseña de aplicación en lugar de la contraseña de la cuenta. 550 Sender address rejected significa que MAILER_SENDER_EMAIL es una dirección desde la que el relay no permite enviar, por lo que debe ser un buzón o un dominio que haya verificado con el proveedor.

Recibir correo en una conversación es una tarea independiente. Requiere MAILER_INBOUND_EMAIL_DOMAIN y RAILS_INBOUND_EMAIL_SERVICE, además de un servidor de correo que entregue los mensajes entrantes a Chatwoot. Alquilar un relay es la opción más rápida. Si prefiere administrar toda la ruta del correo, administrar su propio servidor de correo con Mailcow explica lo que implica realmente ese compromiso.

Qué respaldar y cómo verificar que la restauración funciona

Una copia de seguridad de Chatwoot consta de cuatro partes; omitir cualquiera de ellas convierte una restauración en una reconstrucción.

  • La base de datos Postgres, que contiene conversaciones, contactos, cuentas de agentes y cada configuración.
  • El volumen storage_data, ya que ACTIVE_STORAGE_SERVICE=local escribe los archivos subidos al disco y solo mantiene una fila de referencia en Postgres.
  • El archivo .env, ya que contiene SECRET_KEY_BASE y las claves ACTIVE_RECORD_ENCRYPTION_*.
  • Los archivos compose, ya que registran la etiqueta de imagen exacta con la que coincide el esquema de su base de datos.

Si restaura solo la base de datos, cada conversación volverá con archivos adjuntos rotos, porque las filas apuntan a archivos que ya no están en el disco.

cd ~/chatwoot
docker compose exec -T postgres pg_dump -U postgres -Fc chatwoot > db-$(date +%F).dump

-T es importante. Sin él, Compose asigna un pseudo terminal, el cual reescribe los bytes de nueva línea en el flujo, resultando en un archivo de volcado que pg_restore rechaza. -Fc es el formato personalizado, el cual comprime y permite que pg_restore trabaje de forma selectiva.

docker run --rm -v chatwoot_storage_data:/data:ro -v "$PWD":/backup alpine \
  tar czf /backup/storage-$(date +%F).tgz -C /data .

El nombre del volumen es el nombre de su directorio de proyecto más _storage_data. Confírmelo con docker volume ls | grep storage_data antes de confiar en ese comando, ya que Docker crea un volumen vacío en lugar de fallar cuando usted nombra uno que no existe. Obtendría un archivo válido y vacío sin ningún error. Verifique el tamaño después con ls -lh storage-*.tgz.

Ambos archivos residen ahora en el mismo disco que aquello que protegen, lo cual no le protege de nada. Envíelos fuera del servidor y cifrelos, ya que un volcado de base de datos contiene cada mensaje de cliente en texto plano. Copias de seguridad externas cifradas con restic cubre el aspecto de la programación y retención.

El simulacro de restauración, ejecútelo antes de necesitarlo

Restaure en un segundo VPS, no en el de producción. Copie .env, los archivos compose y ambos archivos comprimidos, luego ejecute:

docker compose up -d postgres
docker compose exec -T postgres pg_restore -U postgres -d chatwoot --clean --if-exists < db-2026-08-10.dump
docker run --rm -v chatwoot_storage_data:/data -v "$PWD":/backup alpine \
  sh -c 'rm -rf /data/* && tar xzf /backup/storage-2026-08-10.tgz -C /data'
docker compose up -d

--clean --if-exists elimina los objetos existentes antes de cargar, así que apunte solo a una base de datos que esté dispuesto a perder. Luego inicie sesión y abra una conversación que tenga un archivo adjunto. Si la lista de mensajes carga y el archivo se descarga, la copia de seguridad es real.

Una restauración con un SECRET_KEY_BASE diferente invalida cada cookie de sesión, por lo que todos los usuarios cerrarán sesión. Una restauración con claves ACTIVE_RECORD_ENCRYPTION_* diferentes es peor: Chatwoot no puede descifrar las columnas que contienen las credenciales de los canales y genera ActiveRecord::Encryption::Errors::Decryption. Es por eso que .env está en la lista de respaldo.

Cómo actualizar Chatwoot a una nueva etiqueta

El orden es más importante que los comandos en sí.

  1. Lea las notas de la versión entre su etiqueta actual y la de destino, buscando pasos manuales obligatorios.
  2. Realice un volcado de base de datos y un archivo de almacenamiento nuevos, y verifique que el tamaño de ambos archivos parezca correcto.
  3. Edite la etiqueta de la imagen en el servicio base dentro de docker-compose.yaml.
  4. Descargue la nueva imagen, detenga el stack, ejecute las migraciones y vuelva a iniciar.
docker compose pull
docker compose down
docker compose run --rm rails bundle exec rails db:chatwoot_prepare
docker compose up -d
docker compose images

Descargue la imagen antes de migrar, ya que la migración debe ejecutarse desde la nueva imagen: la imagen antigua no contiene los nuevos archivos de migración. Detenga el stack antes de migrar, ya que el código antiguo y el nuevo esquema son incompatibles; un proceso de Rails antiguo en ejecución puede generar errores o escribir filas que el nuevo esquema no aceptará. Detener el servicio también libera la memoria necesaria para la migración, que es la razón principal por la que el desarrollador recomienda el uso de swap.

docker compose images imprime la etiqueta que cada contenedor está ejecutando realmente, lo que permite detectar casos en los que editó la etiqueta pero olvidó descargar la imagen.

No salte entre muchas versiones a la vez. El consejo del desarrollador para una instalación antigua es avanzar a través de etiquetas intermedias, ya que las migraciones se eliminan una vez que se integran en el esquema base; por lo tanto, una base de datos muy antigua puede llegar a un estado sin ruta de actualización. Avance una versión menor a la vez y ejecute el paso de preparación después de cada una.

Si Rails inicia antes de que se ejecute la migración, se negará a servir peticiones y registrará ActiveRecord::PendingMigrationError: Migrations are pending. Con restart: always configurado, el contenedor se reiniciará cíclicamente, por lo que docker compose ps mostrará un tiempo de actividad que se restablece cada pocos segundos. Ejecute el paso de preparación y el error desaparecerá.

Revertir cambios significa volver a colocar la etiqueta antigua y restaurar el volcado. No existe una ruta de migración inversa en la que pueda confiar, razón por la cual el paso 2 es fundamental.

Modos de fallo y mensajes que verá

502 Bad Gateway de Traefik. El router coincidió, pero el backend no respondió. Compruebe que docker compose ps muestre rails como Up. Después, ejecute docker network inspect proxy y confirme que el contenedor de rails aparezca en su lista de contenedores. Un contenedor que no está conectado no es visible para Traefik. Por eso la petición coincide con un router, pero no llega a ningún destino.

El panel se carga, pero los mensajes nuevos requieren actualizar la página. La conexión websocket a /cable no está pasando, o FRONTEND_URL no coincide con la dirección de la barra del navegador. Si no coinciden, la página intenta abrir una conexión websocket a otro origen y el navegador la bloquea.

FATAL: password authentication failed for user "postgres". La contraseña de .env y la almacenada en el volumen de datos de Postgres son diferentes. Corríjalo con ALTER USER dentro del contenedor en ejecución. Editar .env de nuevo no cambia una base de datos que ya se ha inicializado.

NOAUTH Authentication required. Redis se está ejecutando con --requirepass, pero la aplicación se conectó sin contraseña. Por tanto, REDIS_PASSWORD falta en .env o no se cargó. Pruebe directamente la contraseña que espera Redis con docker compose exec redis sh -c 'redis-cli -a "$REDIS_PASSWORD" ping'. Debería responder PONG. Las comillas simples son importantes: hacen que la variable se expanda dentro del contenedor, que lee .env, en lugar de hacerlo en su propio shell, donde normalmente está vacía.

Los contenedores terminan con el código 137. Ese código corresponde a SIGKILL. En un equipo pequeño, lo habitual es que la señal la envíe el terminador del kernel por falta de memoria. Sin embargo, docker kill también envía la misma señal, así que compruebe sudo dmesg -T | grep -i "killed process" antes de atribuirlo a la memoria. Si el problema es la memoria, añada swap, establezca límites de memoria por servicio o cambie a un plan más grande.

FAQ

¿Cuánta RAM necesita un VPS de Chatwoot autohospedado?

En octubre de 2026, el proyecto upstream solicita 4 GB de RAM y 4 núcleos de CPU como mínimo, con una capacidad indicada de hasta 10,000 conversaciones al día, y 8 GB con 8 núcleos para hasta 20,000. Añada al menos 1 GB de swap, porque una actualización ejecuta un segundo proceso de Rails para aplicar las migraciones y es ahí donde los servidores pequeños se quedan sin memoria. Un VPS de 2 GB arranca y funciona para un par de agentes, pero Sidekiq por sí solo puede superar 1 GB bajo carga. Por tanto, espere que se detengan contenedores con el código de salida 137 durante los periodos de actividad y las actualizaciones.

¿Por qué nunca llegan los correos de restablecimiento de contraseña de Chatwoot?

Porque no se ha definido SMTP_ADDRESS. Chatwoot recurre entonces a la entrega mediante sendmail, que el proyecto upstream contempla para un servidor Postfix instalado en el host, y esta configuración de Docker no tiene ninguno. El trabajo se ejecuta en Sidekiq, por lo que cualquier error de entrega aparece en el registro de Sidekiq mientras el navegador sigue mostrando un mensaje de éxito. Defina SMTP_ADDRESS, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD y MAILER_SENDER_EMAIL en .env, reinicie los servicios rails y sidekiq y, después, supervise docker compose logs -f sidekiq mientras inicia un restablecimiento.

¿Qué debo incluir en la copia de seguridad para restaurar Chatwoot?

La base de datos de Postgres, el volumen de Docker storage_data, el archivo .env y los archivos de compose. La base de datos por sí sola no es suficiente, porque los archivos subidos se almacenan en el volumen y Postgres sólo conserva referencias a ellos. Por tanto, una restauración basada únicamente en la base de datos produce conversaciones con archivos adjuntos dañados. .env es importante porque un SECRET_KEY_BASE diferente cierra la sesión de todos los usuarios, y unas claves ACTIVE_RECORD_ENCRYPTION_* diferentes hacen que las columnas cifradas no se puedan leer.

¿Cómo actualizo Chatwoot sin dañar la base de datos?

Haga una copia de seguridad, cambie la etiqueta de imagen en el archivo de compose y ejecute docker compose pull, docker compose down, docker compose run --rm rails bundle exec rails db:chatwoot_prepare y docker compose up -d. Descargue primero la imagen, porque las migraciones deben ejecutarse desde la imagen nueva. Detenga antes el stack, porque ejecutar código antiguo contra un esquema nuevo provoca errores. En una instalación antigua, avance una versión menor cada vez, ya que las migraciones se eliminan cuando se integran en el esquema base.

¿Puedo usar la imagen estándar de postgres en lugar de pgvector?

No. El esquema de Chatwoot habilita la extensión vector, por lo que la imagen postgres estándar falla durante db:chatwoot_prepare con ERROR: extension "vector" is not available, porque esa imagen no contiene el archivo de control de la extensión. Mantenga pgvector/pgvector:pg16 del archivo de compose upstream o use otra imagen que incluya pgvector para su versión principal de Postgres.