Documentation Index
Fetch the complete documentation index at: https://mintlify.com/DevMauricio03/n8n-whatsapp-ai-agent/llms.txt
Use this file to discover all available pages before exploring further.
The entire n8n WhatsApp AI Agent platform is defined in a single docker/docker-compose.yml.example file (copy it to docker/docker-compose.yml before use). It orchestrates seven services — postgres, redis, n8n, chatwoot-prepare, chatwoot-rails, chatwoot-sidekiq, and caddy — all connected to a shared internal bridge network called platform_net. Only the Caddy reverse proxy publishes ports to the host, so all other services remain isolated from direct external access.
Services
postgres
Provides the shared PostgreSQL instance for the entire stack. The pgvector image adds the vector-similarity extension required by n8n’s AI memory nodes. Two initialization scripts in docker/initdb/ run automatically on first start: 01-create-databases.sql creates the n8n, chatwoot, and agent databases, and 02-agent-schema.sql creates the bd_clientes table and its phone-number index in the agent database.
| Property | Value |
|---|
| Image | ${POSTGRES_IMAGE} (e.g. pgvector/pgvector:pg15) |
| Container name | platform-postgres |
| Restart policy | unless-stopped |
| Volume | postgres_data:/var/lib/postgresql/data |
| Init scripts | ./initdb → /docker-entrypoint-initdb.d (read-only) |
| Health check | pg_isready -U ${POSTGRES_USER} -d postgres every 10 s, 10 retries |
| Network | platform_net (internal only) |
redis
Provides the Redis instance used by Chatwoot Sidekiq as a job queue and by n8n for optional caching. Persistence is enabled via --appendonly yes, so the queue survives container restarts. The --requirepass flag enforces authentication with REDIS_PASSWORD.
| Property | Value |
|---|
| Image | ${REDIS_IMAGE} (e.g. redis:7-alpine) |
| Container name | platform-redis |
| Restart policy | unless-stopped |
| Volume | redis_data:/data |
| Health check | redis-cli -a ${REDIS_PASSWORD} PING every 10 s, 10 retries |
| Network | platform_net (internal only) |
n8n
Hosts the n8n workflow automation engine. The service waits for both postgres and redis to pass their health checks before starting. It connects to the n8n database in PostgreSQL and exposes port 5678 only on platform_net — Caddy handles all external TLS traffic. All workflow environment variables (WHATSAPP_GRAPH_API_VERSION, WHATSAPP_PHONE_NUMBER_ID, etc.) are passed directly into the container’s environment.
| Property | Value |
|---|
| Image | ${N8N_IMAGE} (e.g. docker.n8n.io/n8nio/n8n:1) |
| Container name | platform-n8n |
| Restart policy | unless-stopped |
| Depends on | postgres (healthy), redis (healthy) |
| Database | PostgreSQL n8n at postgres:5432 |
| Volume | n8n_data:/home/node/.n8n |
| Exposed port | 5678 (internal network only) |
| Network | platform_net (internal only) |
chatwoot-prepare
A one-shot initialization container that runs bundle exec rails db:chatwoot_prepare to migrate the Chatwoot schema in the chatwoot database. It uses the same environment block (&chatwoot_environment) as the two long-running Chatwoot containers and sets restart: "no" so it exits cleanly after migration rather than restarting.
| Property | Value |
|---|
| Image | ${CHATWOOT_IMAGE} |
| Container name | platform-chatwoot-prepare |
| Restart policy | "no" |
| Depends on | postgres (healthy), redis (healthy) |
| Network | platform_net (internal only) |
chatwoot-rails
The main Chatwoot web process. Starts after chatwoot-prepare completes successfully and listens on port 3000 (internal only). Caddy proxies all external HTTPS traffic for CHATWOOT_DOMAIN to this service.
| Property | Value |
|---|
| Image | ${CHATWOOT_IMAGE} |
| Container name | platform-chatwoot-rails |
| Restart policy | unless-stopped |
| Depends on | chatwoot-prepare (completed successfully) |
| Volume | chatwoot_storage:/app/storage |
| Exposed port | 3000 (internal network only) |
| Network | platform_net (internal only) |
chatwoot-sidekiq
The Chatwoot background job processor. Runs bundle exec sidekiq and shares the chatwoot_storage volume with chatwoot-rails so both processes access the same uploaded files. Also waits for chatwoot-prepare to complete before starting.
| Property | Value |
|---|
| Image | ${CHATWOOT_IMAGE} |
| Container name | platform-chatwoot-sidekiq |
| Restart policy | unless-stopped |
| Depends on | chatwoot-prepare (completed successfully) |
| Volume | chatwoot_storage:/app/storage |
| Network | platform_net (internal only) |
caddy
The sole public-facing service. Caddy terminates TLS using automatically provisioned Let’s Encrypt certificates and reverse-proxies traffic to n8n:5678 and chatwoot-rails:3000 based on the incoming domain. It mounts the Caddyfile.example as read-only so configuration changes require an explicit file update and container restart.
| Property | Value |
|---|
| Image | ${CADDY_IMAGE} (e.g. caddy:2-alpine) |
| Container name | platform-caddy |
| Restart policy | unless-stopped |
| Depends on | n8n, chatwoot-rails |
| Published ports | 80:80, 443:443, 443:443/udp (HTTP/3) |
| Volumes | ./Caddyfile.example (read-only), caddy_data, caddy_config |
| Network | platform_net |
Volumes
All persistent data is stored in named Docker volumes. These volumes live on the host under Docker’s default volume path and survive container restarts and image upgrades.
| Volume | Contents |
|---|
postgres_data | PostgreSQL data directory — n8n, chatwoot, and agent databases |
redis_data | Redis append-only log — persists the Sidekiq job queue across restarts |
n8n_data | n8n application data — encryption keys, settings, and node module cache |
chatwoot_storage | Chatwoot file uploads and attachments — shared between chatwoot-rails and chatwoot-sidekiq |
caddy_data | Let’s Encrypt certificates and ACME account state — prevents re-issuance on restart |
caddy_config | Caddy’s runtime configuration cache |
Running docker compose down -v deletes all named volumes, including postgres_data and n8n_data. This permanently destroys your databases, workflow history, and encrypted credentials. Never run down -v on a production stack. Use docker compose down (without -v) to stop services while preserving data.
Network
All services join a single bridge network named platform_net. The network is defined explicitly with name: platform_net and driver: bridge so it gets a predictable name regardless of the Compose project name.
Internal service-to-service communication uses Docker’s built-in DNS resolution — services reach each other by their service name (e.g. postgres, redis, n8n, chatwoot-rails). External traffic enters only through Caddy on ports 80, 443, and 443/udp (HTTP/3).
Caddyfile Routing
docker/Caddyfile.example configures two virtual hosts — one for each public domain — and enables automatic HTTPS through Let’s Encrypt. The {$VARIABLE} syntax reads values from the environment variables passed to the Caddy container.
{
email {$LETSENCRYPT_EMAIL}
}
{$N8N_DOMAIN} {
encode zstd gzip
reverse_proxy n8n:5678
}
{$CHATWOOT_DOMAIN} {
encode zstd gzip
reverse_proxy chatwoot-rails:3000
}
Both sites use encode zstd gzip for response compression. Caddy automatically redirects HTTP to HTTPS and renews certificates before they expire.
Before starting the stack, copy Caddyfile.example to Caddyfile (or update the volume mount path in your docker-compose.yml) so that changes you make to the routing configuration are tracked separately from the example file.
Common Compose Commands
All commands below use --env-file .env to load secrets and -f docker/docker-compose.yml to point at the stack definition. Run them from the project root.
Validate the resolved configuration — confirms that all variable substitutions succeed without starting any containers:
docker compose --env-file .env -f docker/docker-compose.yml config
Pull all images — downloads every image defined in the stack before the first start:
docker compose --env-file .env -f docker/docker-compose.yml pull
Start the stack in detached mode:
docker compose --env-file .env -f docker/docker-compose.yml up -d
Check service status and health:
docker compose --env-file .env -f docker/docker-compose.yml ps
Stream logs from a specific service (replace <service> with e.g. n8n, caddy, chatwoot-rails):
docker compose --env-file .env -f docker/docker-compose.yml logs --tail=100 <service>
Stop services without removing volumes:
docker compose --env-file .env -f docker/docker-compose.yml down