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.

A backup is not valid until it has been successfully restored in an isolated environment. This is the foundational principle behind every procedure in this guide. Storing a dump file is not a backup strategy — running through the full restore process on a clean server and confirming that n8n, Chatwoot, and the agent workflow all operate correctly is the only way to know that your data is actually recoverable. Schedule recovery tests regularly, not only after incidents.

What to back up

The following eight categories must all be included in your backup strategy. Missing any one of them can make a full recovery impossible.
  • PostgreSQL databases — the three databases created by the initdb/ scripts: n8n (workflow definitions, credentials, execution history), chatwoot (conversation history, contacts, agent accounts), and agent (customer data used by the AI workflow).
  • n8n_data volume — binary file data referenced by n8n workflows, including any files processed or generated during executions.
  • chatwoot_storage volume — attachments, avatars, and other uploaded files managed by Chatwoot.
  • Redis AOF data — the append-only file that persists Redis state between restarts, if you need to recover the Human Handoff flags and any other short-lived state that Redis holds.
  • .env and encryption keys — the environment file and all secrets it contains must be stored in a separate, encrypted secrets store. Never commit .env to the repository.
  • Caddy configuration files — your production Caddyfile and any TLS-related configuration.
  • Infrastructure files — your working copies of docker-compose.yml, any override files, and initdb/ scripts.
  • Exact image versions — record the specific image tags or digests that are currently running (from docker compose ps or the *_IMAGE variables in .env) so you can reproduce the exact stack during a recovery.

PostgreSQL backup

PostgreSQL holds the most critical and irreplaceable data in the stack. Back it up daily and before every release. Create a local directory to store backup files before running the first dump:
mkdir -p backups
Dump all databases in a single operation using pg_dumpall. The command runs inside the running postgres container and writes the SQL output to a local file:
docker compose --env-file .env -f docker/docker-compose.yml \
  exec -T postgres sh -lc 'pg_dumpall -U "$POSTGRES_USER"' \
  > backups/postgres-all.sql
The $POSTGRES_USER variable is read from the container’s environment, which is populated from your .env file. If you customised the database user from the default platform, no change to this command is needed as long as .env is correct. To restore the dump into a clean PostgreSQL instance:
docker compose --env-file .env -f docker/docker-compose.yml \
  exec -T postgres sh -lc 'psql -U "$POSTGRES_USER"' \
  < backups/postgres-all.sql
Run the restore command against a fresh instance where the initdb/ scripts have not yet run, so that existing objects do not conflict with the objects being recreated from the dump.
Do not store production backup files inside the repository. SQL dumps contain all database content, including customer phone numbers, conversation history, and any other personally identifiable information held in Chatwoot and the agent database. Store backups in an encrypted, access-controlled location that is separate from the codebase.

Volumes backup

The n8n_data and chatwoot_storage volumes contain binary files that are not captured by a PostgreSQL dump. These must be backed up separately. Stop writes to the volumes before copying them, or schedule a maintenance window to prevent data inconsistency during the copy. For production environments, use your VPS provider’s snapshot feature or a dedicated backup tool that supports consistent, encrypted snapshots of block storage. Provider snapshots are generally faster and more reliable than manual tar copies of live volumes. After taking a snapshot or copy, verify that the files are readable and that the sizes match what you expect. An empty or truncated volume backup is as dangerous as no backup at all.

Redis backup

Redis is configured with append-only file (AOF) persistence, which means it writes every command to disk as it is received. Before taking a Redis backup, force a rewrite of the AOF file to ensure it is compact and consistent:
docker compose --env-file .env -f docker/docker-compose.yml \
  exec redis sh -lc 'redis-cli -a "$REDIS_PASSWORD" BGREWRITEAOF'
After the rewrite completes, copy the AOF file from the Redis container or from the underlying volume.
Redis in this stack holds primarily short-lived state: Human Handoff flags with a TTL and any temporary values written by workflow executions. Before restoring Redis from a backup during a recovery event, evaluate whether it is safer and simpler to start Redis with an empty state. Restoring a stale AOF file might cause Human Handoff flags to remain set for conversations that were already closed, which would prevent the AI from responding to those contacts. Starting clean is often the better option unless you have a specific reason to preserve Redis state.

Suggested backup frequency

The frequencies in this table are a starting point. The right cadence for your deployment depends on your Recovery Point Objective (RPO — how much data you can afford to lose) and your Recovery Time Objective (RTO — how long a recovery can take). Define those values with your business stakeholders before finalising the backup schedule.
ElementInitial frequency
PostgreSQLDaily and before each release
Volumes (n8n_data, chatwoot_storage)Daily or on each significant change
Configuration (.env, Caddyfile, Compose files)On each change
Restore testMonthly and before major changes

Recovery test procedure

Run this procedure on a schedule and whenever you make a significant change to the infrastructure. The goal is to confirm that every piece of a backup can be reassembled into a working stack within your RTO.
1

Create an isolated server or project

Provision a clean VPS or container environment that is completely separate from production. It must not share any network access, credentials, or storage with the live stack.
2

Use test domains and credentials

Configure the isolated environment with test domain names and freshly generated credentials. Do not point test domains at production services or reuse production API keys.
3

Restore PostgreSQL and volumes

Copy the backup files to the isolated server. Restore the PostgreSQL dump using the restore command from the PostgreSQL backup section. Restore the volume snapshots or archive files to the correct mount points before starting the containers.
4

Confirm access to n8n and Chatwoot

Start the stack and verify that the n8n editor loads, existing workflows are present, and the Chatwoot interface shows conversation history from the restored data.
5

Check encrypted credentials

In n8n, open the Credentials section and confirm that the stored credentials (WhatsApp API, Google Drive, database connections) can be decrypted correctly. Decryption depends on the N8N_ENCRYPTION_KEY in .env — confirm the correct key was included in the restore.
6

Run BAK-01 and the minimum test set

Execute test case BAK-01 (Restoration in an isolated environment — services and data recovered) and the minimum pre-release test set from the Testing guide. All critical paths must pass before the recovery test is considered successful.
7

Record the results

Write a recovery test record that includes the date, the duration of the full restore procedure, any errors encountered, any steps that were missing or unclear, and the name of the person who performed the test. Use the findings to improve the backup and restore procedures before the next scheduled test.

Build docs developers (and LLMs) love