Skip to main content

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.
PropertyValue
Image${POSTGRES_IMAGE} (e.g. pgvector/pgvector:pg15)
Container nameplatform-postgres
Restart policyunless-stopped
Volumepostgres_data:/var/lib/postgresql/data
Init scripts./initdb/docker-entrypoint-initdb.d (read-only)
Health checkpg_isready -U ${POSTGRES_USER} -d postgres every 10 s, 10 retries
Networkplatform_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.
PropertyValue
Image${REDIS_IMAGE} (e.g. redis:7-alpine)
Container nameplatform-redis
Restart policyunless-stopped
Volumeredis_data:/data
Health checkredis-cli -a ${REDIS_PASSWORD} PING every 10 s, 10 retries
Networkplatform_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.
PropertyValue
Image${N8N_IMAGE} (e.g. docker.n8n.io/n8nio/n8n:1)
Container nameplatform-n8n
Restart policyunless-stopped
Depends onpostgres (healthy), redis (healthy)
DatabasePostgreSQL n8n at postgres:5432
Volumen8n_data:/home/node/.n8n
Exposed port5678 (internal network only)
Networkplatform_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.
PropertyValue
Image${CHATWOOT_IMAGE}
Container nameplatform-chatwoot-prepare
Restart policy"no"
Depends onpostgres (healthy), redis (healthy)
Networkplatform_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.
PropertyValue
Image${CHATWOOT_IMAGE}
Container nameplatform-chatwoot-rails
Restart policyunless-stopped
Depends onchatwoot-prepare (completed successfully)
Volumechatwoot_storage:/app/storage
Exposed port3000 (internal network only)
Networkplatform_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.
PropertyValue
Image${CHATWOOT_IMAGE}
Container nameplatform-chatwoot-sidekiq
Restart policyunless-stopped
Depends onchatwoot-prepare (completed successfully)
Volumechatwoot_storage:/app/storage
Networkplatform_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.
PropertyValue
Image${CADDY_IMAGE} (e.g. caddy:2-alpine)
Container nameplatform-caddy
Restart policyunless-stopped
Depends onn8n, chatwoot-rails
Published ports80:80, 443:443, 443:443/udp (HTTP/3)
Volumes./Caddyfile.example (read-only), caddy_data, caddy_config
Networkplatform_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.
VolumeContents
postgres_dataPostgreSQL data directory — n8n, chatwoot, and agent databases
redis_dataRedis append-only log — persists the Sidekiq job queue across restarts
n8n_datan8n application data — encryption keys, settings, and node module cache
chatwoot_storageChatwoot file uploads and attachments — shared between chatwoot-rails and chatwoot-sidekiq
caddy_dataLet’s Encrypt certificates and ACME account state — prevents re-issuance on restart
caddy_configCaddy’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

Build docs developers (and LLMs) love