VPS

VPS chạy n8n 24/7: setup Docker Compose từ A-Z (có HTTPS, backup)

Self-host n8n trên VPS Ubuntu bằng Docker Compose: HTTPS Caddy, backup database, env vars an toàn, integrate webhook. Tutorial real từ dev VN.

Thanh Nguyễn Cập nhật Đăng 10 phút đọc 19 khối lệnh

VPS chạy n8n 24/7: setup Docker Compose từ A-Z (có HTTPS, backup)
Mục lục bài viết
  1. Tại sao self-host n8n trên VPS?
  2. Cấu hình VPS phù hợp chạy n8n
  3. Step 1: Đặt VPS Ubuntu 24.04 + cấu hình ban đầu
  4. Step 2: Cài Docker + Docker Compose
  5. Step 3: Setup firewall (UFW)
  6. Step 4: Trỏ domain về VPS
  7. Step 5: Tạo cấu trúc thư mục và file .env
  8. Step 6: Viết docker-compose.yml
  9. Step 7: Viết Caddyfile (auto HTTPS)
  10. Step 8: Khởi động stack
  11. Step 9: Daily backup database tự động
  12. Step 10: Upload backup ra cloud storage (S3/R2)
  13. Step 11: Update n8n định kỳ (an toàn)
  14. Step 12: Bảo mật bổ sung
  15. Monitoring n8n: biết khi nào workflow fail
  16. Troubleshooting thường gặp
  17. Use case n8n self-host phổ biến cho dev Việt

AI-ready skill doc: bạn đang vibe code với Claude Code/Cursor/Codex/Gemini? Copy nguyên bài này paste vào AI của bạn - nó sẽ đọc như một skill document và áp dụng đúng pattern này vào project mà không cần bạn giải thích lại. Tiện, gọn, dùng được luôn.

n8n cloud bản trả phí khoảng 20 USD/tháng nhưng giới hạn execution. Self-host n8n trên VPS Việt Nam chỉ ~600-1000k/tháng, không giới hạn workflow, dữ liệu tự lưu, integrate được internal tool nội bộ. Bài này hướng dẫn full setup n8n trên Ubuntu 24.04 với Docker Compose, PostgreSQL backend, Caddy auto HTTPS, daily backup, và secure env vars - chuẩn production cho dev solo và team nhỏ.

Tại sao self-host n8n trên VPS?

Năm 2026 n8n đã trở thành tool automation hàng đầu cho dev Việt - thay thế Zapier/Make với chi phí thấp hơn và full control. Lý do self-host:

  • Unlimited workflow execution: bản cloud giới hạn execution/tháng theo plan, self-host không giới hạn.
  • Data ở VPS của bạn: credential API key, webhook payload, customer data đều tự lưu - không qua server bên thứ ba.
  • Custom node + community node: install bất cứ community node nào, viết custom code node tự do.
  • Integrate hệ thống nội bộ: n8n trên VPS có thể gọi internal API (database công ty, intranet) qua private network mà n8n cloud không làm được.
  • Chi phí ổn định: 600-1000k/tháng cho VPS vs 240 USD/năm n8n cloud, lại không lo bị tăng giá.

Cấu hình VPS phù hợp chạy n8n

Use casevCPURAMDiskGói tham khảo
Cá nhân, <20 workflow, <100 execution/ngày22GB30GBVPS 30 (299k)
Team nhỏ, 20-50 workflow, 1k execution/ngày44GB50GBVPS 50 (639k)
Agency/team, 50+ workflow, 10k execution/ngày66GB80GBVPS 80 (999k)
Production, workflow nặng (LLM, AI)88GB160GBVPS 160 (1.790.000đ)

Mẹo: n8n + PostgreSQL + Caddy cần ít nhất 2GB RAM idle. VPS 1GB không chạy nổi setup này. Nếu thấy n8n bị OOM kill, đó là dấu hiệu cần upgrade RAM.

Step 1: Đặt VPS Ubuntu 24.04 + cấu hình ban đầu

Đặt VPS với OS Ubuntu 24.04 LTS. Sau khi nhận IP và root password qua email, SSH vào:

TerminalStep 1: Đặt VPS Ubuntu 24.04 + cấu hình ban đầubash
# Từ máy bạnssh root@<IP_VPS> # Update hệ thốngapt update && apt upgrade -y # Tạo user non-root (đừng dùng root cho daily work)adduser n8nadminusermod -aG sudo n8nadmin # Copy SSH key sang user mới (để login không cần password)rsync --archive --chown=n8nadmin:n8nadmin ~/.ssh /home/n8nadmin # Logout, login lại với user mớiexitssh n8nadmin@<IP_VPS>

Step 2: Cài Docker + Docker Compose

TerminalStep 2: Cài Docker + Docker Composebash
# Cài Docker officialcurl -fsSL https://get.docker.com -o get-docker.shsudo sh get-docker.sh # Cho user dùng docker không cần sudosudo usermod -aG docker $USER # Logout/login lại để áp dụng groupexitssh n8nadmin@<IP_VPS> # Verifydocker --versiondocker compose version

Docker Compose hiện đại đã tích hợp vào Docker CLI (lệnh là , không phải kiểu cũ).

Step 3: Setup firewall (UFW)

TerminalStep 3: Setup firewall (UFW)bash
sudo ufw default deny incomingsudo ufw default allow outgoingsudo ufw allow sshsudo ufw allow 80/tcpsudo ufw allow 443/tcpsudo ufw enablesudo ufw status

Chỉ mở port 22 (SSH), 80 (HTTP, cho Let's Encrypt verify), 443 (HTTPS). PostgreSQL và n8n internal không mở public.

Step 4: Trỏ domain về VPS

Vào DNS provider (Cloudflare, namesilo, godaddy), tạo A record:

File cấu hìnhStep 4: Trỏ domain về VPSyaml
Type: AName: n8n  (hoặc subdomain bạn muốn)Value: <IP_VPS>TTL: Auto / 300Proxy status: DNS only (TẮT proxy Cloudflare lúc đầu để Let's Encrypt verify được)

Test DNS đã propagate:

TerminalStep 4: Trỏ domain về VPSbash
dig n8n.yourdomain.com +short# Phải trả ra IP VPS

Step 5: Tạo cấu trúc thư mục và file .env

TerminalStep 5: Tạo cấu trúc thư mục và file .envbash
mkdir -p ~/n8n-stack/{caddy,n8n,postgres,backups}cd ~/n8n-stack # Tạo file .envcat > .env <<'EOF'# DomainDOMAIN=n8n.yourdomain.com[email protected] # n8nN8N_ENCRYPTION_KEY=<random_32_char_string>N8N_USER_MANAGEMENT_JWT_SECRET=<random_32_char_string> # PostgreSQLPOSTGRES_USER=n8nPOSTGRES_PASSWORD=<strong_random_password>POSTGRES_DB=n8nEOF # Set permission file env (CHỈ owner đọc được)chmod 600 .env

Generate random secret:

TerminalStep 5: Tạo cấu trúc thư mục và file .envbash
# Trên VPSopenssl rand -hex 32# Copy output, paste vào .env cho N8N_ENCRYPTION_KEY và JWT_SECRET (mỗi cái 1 string riêng) # Generate password Postgresopenssl rand -base64 24

Lưu ý: N8N_ENCRYPTION_KEY dùng để mã hóa credential trong n8n. Nếu MẤT key này, mọi credential trong workflow bị mất (phải nhập lại). LƯU key này vào password manager (1Password, Bitwarden) ngay khi tạo.

Step 6: Viết docker-compose.yml

TerminalStep 6: Viết docker-compose.ymlbash
cat > docker-compose.yml <<'EOF'services:  caddy:    image: caddy:2-alpine    container_name: caddy    restart: unless-stopped    ports:      - "80:80"      - "443:443"    volumes:      - ./caddy/Caddyfile:/etc/caddy/Caddyfile      - caddy_data:/data      - caddy_config:/config    networks:      - n8n-net    environment:      - DOMAIN=${DOMAIN}      - ACME_EMAIL=${ACME_EMAIL}   postgres:    image: postgres:16    container_name: n8n-postgres    restart: unless-stopped    environment:      - POSTGRES_USER=${POSTGRES_USER}      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}      - POSTGRES_DB=${POSTGRES_DB}    volumes:      - postgres_data:/var/lib/postgresql/data    networks:      - n8n-net    healthcheck:      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]      interval: 10s      timeout: 5s      retries: 5   n8n:    image: n8nio/n8n:latest    container_name: n8n    restart: unless-stopped    depends_on:      postgres:        condition: service_healthy    environment:      - DB_TYPE=postgresdb      - DB_POSTGRESDB_HOST=postgres      - DB_POSTGRESDB_PORT=5432      - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}      - DB_POSTGRESDB_USER=${POSTGRES_USER}      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}      - N8N_HOST=${DOMAIN}      - N8N_PORT=5678      - N8N_PROTOCOL=https      - WEBHOOK_URL=https://${DOMAIN}/      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}      - N8N_USER_MANAGEMENT_JWT_SECRET=${N8N_USER_MANAGEMENT_JWT_SECRET}      - GENERIC_TIMEZONE=Asia/Ho_Chi_Minh      - TZ=Asia/Ho_Chi_Minh    volumes:      - n8n_data:/home/node/.n8n    networks:      - n8n-net volumes:  caddy_data:  caddy_config:  postgres_data:  n8n_data: networks:  n8n-net:    driver: bridgeEOF

Step 7: Viết Caddyfile (auto HTTPS)

PowerShellStep 7: Viết Caddyfile (auto HTTPS)powershell
cat > caddy/Caddyfile <<'EOF'{$DOMAIN} {    tls {$ACME_EMAIL}     reverse_proxy n8n:5678 {        flush_interval -1        header_up Host {host}        header_up X-Real-IP {remote_host}        header_up X-Forwarded-For {remote_host}        header_up X-Forwarded-Proto {scheme}    }     encode gzip     header {        Strict-Transport-Security "max-age=31536000;"        X-Content-Type-Options "nosniff"        X-Frame-Options "SAMEORIGIN"        Referrer-Policy "strict-origin-when-cross-origin"    }}EOF

Lưu ý quan trọng: flush_interval -1 cần cho n8n vì workflow lâu chạy (long-running), không có flush này thì connection bị buffer và đứt giữa chừng.

Step 8: Khởi động stack

TerminalStep 8: Khởi động stackbash
cd ~/n8n-stackdocker compose up -d # Theo dõi logdocker compose logs -f # Stop log: Ctrl+C

Lần đầu Caddy sẽ request certificate từ Let's Encrypt - mất 10-30 giây. Khi log Caddy hiện "certificate obtained successfully", truy cập https://n8n.yourdomain.com.

Trang setup n8n hiện ra - tạo owner account đầu tiên (email + password). Đây là admin của instance.

Step 9: Daily backup database tự động

Backup quan trọng vì mất DB = mất tất cả workflow. Tạo script backup:

TerminalStep 9: Daily backup database tự độngbash
cat > ~/n8n-stack/backup.sh <<'EOF'#!/bin/bashset -e BACKUP_DIR=~/n8n-stack/backupsDATE=$(date +%Y%m%d_%H%M%S)KEEP_DAYS=14 cd ~/n8n-stack # Dump databasedocker compose exec -T postgres pg_dump -U n8n n8n | gzip > $BACKUP_DIR/n8n_db_${DATE}.sql.gz # Backup volume n8n_data (chứa credential encryption seed)docker run --rm     -v n8n-stack_n8n_data:/data     -v $BACKUP_DIR:/backup     alpine tar czf /backup/n8n_data_${DATE}.tar.gz -C /data . # Xóa backup cũ hơn KEEP_DAYS ngàyfind $BACKUP_DIR -name "*.gz" -mtime +$KEEP_DAYS -delete echo "Backup completed: $DATE"EOF chmod +x ~/n8n-stack/backup.sh

Schedule cron chạy 3h sáng mỗi ngày:

TerminalStep 9: Daily backup database tự độngbash
crontab -e # Thêm dòng:0 3 * * * /home/n8nadmin/n8n-stack/backup.sh >> /home/n8nadmin/n8n-stack/backup.log 2>&1

Test chạy thử backup:

TerminalStep 9: Daily backup database tự độngbash
./backup.shls -lh backups/

Step 10: Upload backup ra cloud storage (S3/R2)

Backup local không đủ - VPS chết là mất hết. Upload lên cloud storage:

TerminalStep 10: Upload backup ra cloud storage (S3/R2)bash
# Cài AWS CLIsudo apt install awscli -y # Cấu hình credential cho Cloudflare R2 (rẻ + miễn phí egress)aws configure --profile r2# AWS Access Key ID: <R2_access_key># AWS Secret Access Key: <R2_secret_key># Default region: auto# Default output: json # Sửa backup.sh thêm phần uploadcat >> ~/n8n-stack/backup.sh <<'EOF' # Upload to Cloudflare R2aws s3 cp $BACKUP_DIR/n8n_db_${DATE}.sql.gz     s3://your-bucket/n8n-backups/     --endpoint-url https://<account_id>.r2.cloudflarestorage.com     --profile r2 aws s3 cp $BACKUP_DIR/n8n_data_${DATE}.tar.gz     s3://your-bucket/n8n-backups/     --endpoint-url https://<account_id>.r2.cloudflarestorage.com     --profile r2EOF

Step 11: Update n8n định kỳ (an toàn)

n8n release version mới đều đặn. Update:

TerminalStep 11: Update n8n định kỳ (an toàn)bash
cd ~/n8n-stack # Backup TRƯỚC khi update./backup.sh # Pull image mớidocker compose pull # Recreate container (giữ volume data)docker compose up -d # Verifydocker compose logs n8n --tail 50

Nếu update gây lỗi (rare), rollback bằng cách pin version cụ thể trong docker-compose.yml:

TerminalStep 11: Update n8n định kỳ (an toàn)bash
# Thay vìimage: n8nio/n8n:latest# Pin cụ thể version đang chạy stableimage: n8nio/n8n:1.65.2  # ví dụ

Step 12: Bảo mật bổ sung

SSH key only, disable password

TerminalStep 12: Bảo mật bổ sungbash
sudo nano /etc/ssh/sshd_config# Sửa: PasswordAuthentication no# Sửa: PermitRootLogin nosudo systemctl restart ssh

Fail2ban chống brute force

TerminalStep 12: Bảo mật bổ sungbash
sudo apt install fail2ban -ysudo systemctl enable fail2ban

Auto security update

TerminalStep 12: Bảo mật bổ sungbash
sudo apt install unattended-upgrades -ysudo dpkg-reconfigure -plow unattended-upgrades

Webhook secret cho từng workflow

Trong n8n, khi tạo Webhook node, set "Authentication" = "Header Auth" hoặc check token trong workflow logic. Không để webhook public không xác thực - bot scan internet liên tục để abuse webhook.

Monitoring n8n: biết khi nào workflow fail

Built-in n8n có "Execution List" - xem history tất cả execution. Nhưng cần alert chủ động khi workflow fail.

Cách 1: Tạo Error Workflow trong n8n - trigger khi bất kỳ workflow nào fail, gửi notification về Telegram/Slack/Email. Workflow:

  1. Tạo workflow mới tên "Error Handler".
  2. Node 1: Error Trigger (auto trigger khi workflow khác fail).
  3. Node 2: Telegram Send Message với chi tiết error.
  4. Vào Settings từng workflow quan trọng, set "Error Workflow" = "Error Handler".

Cách 2: External monitoring qua UptimeRobot - ping HTTPS healthcheck endpoint, alert qua email/Telegram khi n8n down.

Troubleshooting thường gặp

n8n container restart liên tục, log "OOM killed"

RAM không đủ. Upgrade VPS hoặc giảm worker. Check: xem container nào ngốn RAM.

Webhook không nhận được request từ ngoài

Check firewall UFW có open 443. Check Cloudflare proxy (orange cloud) - n8n cần WebSocket hỗ trợ, một số rule Cloudflare có thể block. Test: .

Caddy không lấy được cert HTTPS

DNS chưa propagate đúng IP, hoặc port 80 bị block. Test - phải trả 308 redirect tới HTTPS.

Workflow chạy chậm hoặc timeout

Tăng timeout trong workflow setting. Cân nhắc tách workflow nặng sang queue mode (n8n có doc về queue mode với BullMQ Redis).

Use case n8n self-host phổ biến cho dev Việt

  • Sync data giữa Google Sheet và database SaaS: mỗi khi sales nhập lead vào sheet, n8n tự push sang CRM.
  • Auto-reply Zalo OA/Facebook: webhook nhận message, gọi OpenAI/Claude, gửi response.
  • Báo cáo daily Slack/Telegram: mỗi 8h sáng, n8n query database, gửi report doanh số đêm qua.
  • Backup tự động cross-platform: dump database mỗi đêm, upload R2, gửi notification.
  • RPA cho ads: mỗi giờ check Google Ads/Meta Ads spend, alert khi vượt budget.
  • Workflow AI: input từ form → OpenAI process → save Notion/Airtable.

Tổng kết: self-host n8n trên VPS giúp dev/team kiểm soát hoàn toàn workflow automation với chi phí thấp hơn nhiều bản cloud. Stack đề xuất: VPS Việt Nam giá tốt + Ubuntu 24.04 + Docker Compose + PostgreSQL + Caddy auto HTTPS + cron backup hàng ngày + upload R2 + monitoring qua Error Workflow. Setup ban đầu khoảng 1-2 giờ, sau đó chạy ổn định nhiều tháng không cần can thiệp. Bắt đầu với VPS 50 cho cá nhân, scale lên VPS 80/160 khi workflow tăng.

Chia sẻ:Facebook

Thanh Nguyễn

TND

Tư vấn bản quyền, VPS và máy chủ kèm hóa đơn VAT, hợp đồng đầy đủ cho doanh nghiệp.