Backup và restore n8n tự động gồm database credentials và workflow JSON

Bạn đã bỏ hàng giờ để tạo workflow n8n tự động hóa cho hệ thống VPS của mình? Rồi một ngày server gặp sự cố, Docker container bị lỗi, hoặc vô tình xóa nhầm, nếu không có bản backup đầy đủ thì toàn bộ công sức coi như mất trắng. Bài viết này hướng dẫn bạn thiết lập script backup tự động cho n8n, bao gồm toàn bộ database PostgreSQL (chứa credentials, workflow lưu trạng thái), file .encryptionKey (thứ bắt buộc để restore được credential), và export các workflow ra file JSON. Tất cả chạy qua cron hoặc systemd timer, bạn có thể yên tâm rằng dữ liệu luôn được sao lưu hàng ngày.
Yêu cầu trước khi bắt đầu
- VPS chạy Ubuntu 24.04 LTS hoặc Debian 12, có quyền sudo/root.
- n8n đang chạy với Docker Compose, sử dụng PostgreSQL làm database backend (không dùng SQLite mặc định). Cần bản đã chuyển n8n từ SQLite sang PostgreSQL.
- Đã biết cách dùng
docker compose(v2, không phảidocker-composecũ) và cron. - Đường dẫn thư mục chứa docker-compose của n8n (ví dụ
/opt/n8n). Nếu chưa cài, tham khảo bài cài đặt n8n trên VPS Ubuntu 24.04 bằng Docker Compose. - Biết tên container n8n và PostgreSQL (ví dụ
n8nvàn8n-postgres).
Vì sao backup n8n cần đủ ba thành phần?
Nhiều người chỉ copy thư mục hoặc export workflow JSON, nhưng khi restore thì credential bị lỗi ngay. n8n lưu credential (kết nối tới Telegram, Gmail, database...) dưới dạng mã hóa trong database PostgreSQL, và khóa giải mã chính là file .encryptionKey được mount vào container. Nếu bạn mất file này, mọi credential trở nên vô dụng. Ngoài ra, workflow được lưu trong database, nhưng việc export ra JSON giúp bạn có bản sao lưu dễ đọc, dễ import lại thủ công vào bản n8n khác. Vậy nên một backup hoàn chỉnh gồm:
- Database dump của PostgreSQL (lưu mọi thứ: workflow, credential, execution history).
- File .encryptionKey (thường đặt cùng thư mục với
docker-compose.yml). - Workflow JSON export từ n8n (bản copy dễ khôi phục riêng lẻ).
Bước 1 - Xác định cấu trúc thư mục và file
Giả sử thư mục gốc n8n của bạn là /opt/n8n. Trong đó có file .env chứa biến môi trường, file .encryptionKey (nếu bạn đặt khóa thủ công bằng biến N8N_ENCRYPTION_KEY trong .env), và file docker-compose.yml. Container PostgreSQL của bạn tên là n8n-postgres, container n8n tên n8n. Nếu bạn dùng tên khác, sửa lại trong script sau.
Kiểm tra container đang chạy:
docker ps --format "table {{.Names}}\t{{.Image}}"
Output mong đợi sẽ có dạng:
NAMES IMAGE
n8n n8nio/n8n
n8n-postgres postgres:15
Bước 2 - Script backup tự động full
Tạo file /usr/local/bin/n8n-backup.sh với nội dung sau. Script này thực hiện 3 việc: dump database, copy encryption key, export workflow JSON, sau đó nén lại thành file .tar.gz có timestamp.
#!/bin/bash
set -e
# Cấu hình - sửa theo môi trường của bạn
N8N_DIR="/opt/n8n"
BACKUP_DIR="/var/backups/n8n"
DB_CONTAINER="n8n-postgres"
N8N_CONTAINER="n8n"
DB_NAME="n8n"
DB_USER="n8n"
DB_PASS="your_db_password_here" # Thay bằng password thật
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/n8n_backup_${TIMESTAMP}.tar.gz"
# Tạo thư mục backup
mkdir -p "${BACKUP_DIR}"
# 1. Dump database PostgreSQL từ container
echo ">>> Dumping database..."
docker exec "${DB_CONTAINER}" pg_dump -U "${DB_USER}" "${DB_NAME}" > "${BACKUP_DIR}/n8n_db_${TIMESTAMP}.sql"
if [ $? -ne 0 ]; then
echo "ERROR: Database dump failed!"
exit 1
fi
# 2. Copy encryption key (nếu tồn tại)
echo ">>> Copying encryption key..."
if [ -f "${N8N_DIR}/.encryptionKey" ]; then
cp "${N8N_DIR}/.encryptionKey" "${BACKUP_DIR}/.encryptionKey_${TIMESTAMP}"
elif [ -f "${N8N_DIR}/.env" ] && grep -q "N8N_ENCRYPTION_KEY" "${N8N_DIR}/.env"; then
# Nếu key nằm trong .env, copy file .env
cp "${N8N_DIR}/.env" "${BACKUP_DIR}/.env_${TIMESTAMP}"
else
echo "WARNING: No encryption key found! Credentials will not be restorable."
fi
# 3. Export workflow JSON qua API n8n
echo ">>> Exporting workflows to JSON..."
docker exec "${N8N_CONTAINER}" n8n export:workflow --all --output=/home/node/.n8n/workflows_export_${TIMESTAMP}.json 2>/dev/null || {
# Fallback: dùng curl nếu n8n đang chạy với API
echo "Trying API export..."
docker exec "${N8N_CONTAINER}" curl -s -u "${DB_USER}:${DB_PASS}" http://localhost:5678/rest/workflows | python3 -c "import sys,json; [print(json.dumps(w,indent=2)) for w in json.load(sys.stdin).get('data',[])]" > "${BACKUP_DIR}/workflows_export_${TIMESTAMP}.json"
}
# Nếu lệnh n8n export thành công, copy file từ container ra host
if [ -f "${BACKUP_DIR}/workflows_export_${TIMESTAMP}.json" ]; then
docker cp "${N8N_CONTAINER}":/home/node/.n8n/workflows_export_${TIMESTAMP}.json "${BACKUP_DIR}/" 2>/dev/null || true
fi
# 4. Nén tất cả thành file tar.gz
echo ">>> Compressing backup..."
cd "${BACKUP_DIR}"
tar -czf "${BACKUP_FILE}" n8n_db_${TIMESTAMP}.sql .encryptionKey_${TIMESTAMP} .env_${TIMESTAMP} workflows_export_${TIMESTAMP}.json 2>/dev/null
# Xóa file tạm
rm -f n8n_db_${TIMESTAMP}.sql .encryptionKey_${TIMESTAMP} .env_${TIMESTAMP} workflows_export_${TIMESTAMP}.json
echo ">>> Backup completed: ${BACKUP_FILE}"
echo ">>> Size: $(du -h ${BACKUP_FILE} | cut -f1)"
sudo chmod +x /usr/local/bin/n8n-backup.sh
Hãy thay DB_PASS bằng mật khẩu PostgreSQL thật của bạn. Nếu bạn chưa biết mật khẩu, kiểm tra trong file .env hoặc biến môi trường trong docker-compose.
Bước 3 - Thiết lập lịch chạy backup tự động
Chạy backup mỗi ngày vào lúc 2 giờ sáng, dùng cron:
sudo crontab -e
Thêm dòng:
0 2 * * * /usr/local/bin/n8n-backup.sh >> /var/log/n8n-backup.log 2>&1
Hoặc dùng systemd timer nếu bạn ưa systemd timer thay cron (có hướng dẫn chi tiết trong bài đó).
Kiểm tra log sau lần chạy đầu:
tail -f /var/log/n8n-backup.log
Bước 4 - Script restore n8n từ backup
Khi cần khôi phục (ví dụ sau khi cài lại VPS hoặc container), bạn cần restore cả ba thứ theo đúng thứ tự. Tạo file /usr/local/bin/n8n-restore.sh:
#!/bin/bash
set -e
if [ -z "$1" ]; then
echo "Usage: $0 /path/to/n8n_backup_20260115_020001.tar.gz"
exit 1
fi
BACKUP_FILE="$1"
N8N_DIR="/opt/n8n"
RESTORE_DIR="/tmp/n8n_restore_$$"
mkdir -p "${RESTORE_DIR}"
# Giải nén backup
echo ">>> Extracting backup..."
tar -xzf "${BACKUP_FILE}" -C "${RESTORE_DIR}"
# Dừng container n8n để tránh ghi đè
echo ">>> Stopping n8n containers..."
cd "${N8N_DIR}"
docker compose down
# 1. Khôi phục database PostgreSQL
echo ">>> Restoring database..."
DB_FILE=$(ls ${RESTORE_DIR}/n8n_db_*.sql 2>/dev/null | tail -1)
if [ -n "${DB_FILE}" ]; then
# Khởi động riêng container PostgreSQL
docker compose up -d n8n-postgres
sleep 5
docker exec -i n8n-postgres psql -U n8n -d n8n < "${DB_FILE}"
echo "Database restored."
fi
# 2. Khôi phục encryption key
echo ">>> Restoring encryption key..."
ENV_FILE=$(ls ${RESTORE_DIR}/.env_* 2>/dev/null | tail -1)
KEY_FILE=$(ls ${RESTORE_DIR}/.encryptionKey_* 2>/dev/null | tail -1)
if [ -n "${KEY_FILE}" ]; then
cp "${KEY_FILE}" "${N8N_DIR}/.encryptionKey"
echo "Encryption key (.encryptionKey) restored."
elif [ -n "${ENV_FILE}" ]; then
# Nếu trong .env có N8N_ENCRYPTION_KEY, khôi phục file .env
echo "Copying .env file (ensure N8N_ENCRYPTION_KEY is present)..."
cp "${ENV_FILE}" "${N8N_DIR}/.env"
fi
# 3. Khôi phục workflow JSON (import vào n8n)
echo ">>> Importing workflows..."
WF_FILE=$(ls ${RESTORE_DIR}/workflows_export_*.json 2>/dev/null | tail -1)
if [ -n "${WF_FILE}" ]; then
docker compose up -d
sleep 10
docker exec -i n8n n8n import:workflow --input=- < "${WF_FILE}" || {
echo "WARNING: Workflow import failed. You may need to import manually."
}
fi
# Dọn dẹp
rm -rf "${RESTORE_DIR}"
echo ">>> Restore completed. n8n container is running."
sudo chmod +x /usr/local/bin/n8n-restore.sh
Cách dùng:
sudo /usr/local/bin/n8n-restore.sh /var/backups/n8n/n8n_backup_20260115_020001.tar.gz
Bước 5 - Verify backup định kỳ
Backup mà hiếm khi kiểm tra cũng như không có. Thêm một bước verify vào cuối script backup. Bạn có thể tạo file /usr/local/bin/n8n-verify-backup.sh chạy riêng hàng tuần:
#!/bin/bash
# Kiểm tra file backup gần nhất có thể giải nén và có đủ 3 thành phần không
LATEST=$(ls -t /var/backups/n8n/*.tar.gz | head -1)
if [ -z "$LATEST" ]; then
echo "ERROR: No backup found!"
exit 1
fi
TEMP_DIR=$(mktemp -d)
tar -tzf "$LATEST" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "ERROR: Backup file corrupted: $LATEST"
exit 1
fi
# Kiểm tra có ít nhất file SQL và encryption key
tar -tzf "$LATEST" | grep -E "n8n_db_|\.encryptionKey|\.env_" > /dev/null
if [ $? -ne 0 ]; then
echo "WARNING: Backup missing database or encryption key: $LATEST"
fi
echo "OK: Backup verified: $LATEST"
rm -rf "$TEMP_DIR"
Thêm vào cron chạy thứ 7 hàng tuần: 0 3 * * 6 /usr/local/bin/n8n-verify-backup.sh
Xử lý lỗi thường gặp
Lỗi "pg_dump: error: connection to server ... failed": Kiểm tra container PostgreSQL có đang chạy không (docker ps). Nếu tên container đúng nhưng vẫn lỗi, có thể bạn cần đặt mật khẩu qua biến môi trường PGPASSWORD: docker exec -e PGPASSWORD="$DB_PASS" "${DB_CONTAINER}" pg_dump ...
Lỗi "n8n export:workflow command not found": Lệnh n8n không có trong container. Cách an toàn là dùng API với curl như phần fallback trong script trên, hoặc bạn có thể cài n8n-cli trong container (không khuyến khích vì tăng kích thước image).
Lỗi restore: credential không hoạt động sau khi import workflow JSON: Điều này xảy ra nếu bạn restore workflow JSON mà không restore database. Workflow JSON chỉ chứa cấu trúc workflow, không chứa credential. Bạn phải restore toàn bộ database PostgreSQL trước. Như script chúng tôi đã làm ở bước 4.
Câu hỏi thường gặp
Tôi có thể backup n8n mà không cần Docker không?
Có. Nếu bạn cài n8n trực tiếp trên VPS (node + npm), database là SQLite hoặc PostgreSQL local. Lúc đó bạn có thể dump database bằng pg_dump hoặc copy file ~/.n8n/database.sqlite, và copy file ~/.n8n/config (chứa encryption key). Tuy nhiên, dùng Docker vẫn là cách dễ quản lý hơn.
Tôi cần lưu backup ở đâu để an toàn?
Nên copy file .tar.gz ra ngoài VPS: lên Google Drive (dùng rclone), S3 bucket, hoặc FTP đến server khác. Thêm dòng rclone copy ... vào cuối script backup.
Script có tự động dọn backup cũ không?
Chưa có. Bạn có thể thêm dòng xóa file quá 30 ngày: find /var/backups/n8n -name "*.tar.gz" -mtime +30 -delete ở cuối script backup.
Tôi quên mật khẩu PostgreSQL trong script backup thì sao?
Mật khẩu được dump ra file .sql dạng text. Cách an toàn hơn là dùng file .pgpass hoặc biến môi trường trong Docker. Nếu dùng Docker Compose, bạn có thể lấy mật khẩu từ biến POSTGRES_PASSWORD trong file .env.
Việc backup có ảnh hưởng đến workflow đang chạy không?
Thời gian dump database không đáng kể (vài giây), workflow vẫn chạy bình thường. Tuy nhiên, nếu bạn có execution lịch sử quan trọng, hãy chạy backup vào lúc ít tải.
Bài viết liên quan
- Chuyển n8n từ SQLite sang PostgreSQL không mất workflow
- Cài đặt n8n trên VPS Ubuntu 24.04 bằng Docker Compose
- n8n queue mode với Redis, khi nào cần tách worker


