
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 case | vCPU | RAM | Disk | Gói tham khảo |
|---|---|---|---|---|
| Cá nhân, <20 workflow, <100 execution/ngày | 2 | 2GB | 30GB | VPS 30 (299k) |
| Team nhỏ, 20-50 workflow, 1k execution/ngày | 4 | 4GB | 50GB | VPS 50 (639k) |
| Agency/team, 50+ workflow, 10k execution/ngày | 6 | 6GB | 80GB | VPS 80 (999k) |
| Production, workflow nặng (LLM, AI) | 8 | 8GB | 160GB | VPS 160 (1.790.000đ) |
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:
# Từ máy bạn
ssh root@
# Update hệ thống
apt update && apt upgrade -y
# Tạo user non-root (đừng dùng root cho daily work)
adduser n8nadmin
usermod -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ới
exit
ssh n8nadmin@
Step 2: Cài Docker + Docker Compose
# Cài Docker official
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Cho user dùng docker không cần sudo
sudo usermod -aG docker $USER
# Logout/login lại để áp dụng group
exit
ssh n8nadmin@
# Verify
docker --version
docker compose version
Docker Compose hiện đại đã tích hợp vào Docker CLI (lệnh là docker compose, không phải docker-compose kiểu cũ).
Step 3: Setup firewall (UFW)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo 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:
Type: A
Name: n8n (hoặc subdomain bạn muốn)
Value:
TTL: Auto / 300
Proxy status: DNS only (TẮT proxy Cloudflare lúc đầu để Let's Encrypt verify được)
Test DNS đã propagate:
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
mkdir -p ~/n8n-stack/{caddy,n8n,postgres,backups}
cd ~/n8n-stack
# Tạo file .env
cat > .env <<'EOF'
# Domain
DOMAIN=n8n.yourdomain.com
[email protected]
# n8n
N8N_ENCRYPTION_KEY=
N8N_USER_MANAGEMENT_JWT_SECRET=
# PostgreSQL
POSTGRES_USER=n8n
POSTGRES_PASSWORD=
POSTGRES_DB=n8n
EOF
# Set permission file env (CHỈ owner đọc được)
chmod 600 .env
Generate random secret:
# Trên VPS
openssl 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 Postgres
openssl rand -base64 24
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
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: bridge
EOF
Step 7: Viết Caddyfile (auto HTTPS)
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
cd ~/n8n-stack
docker compose up -d
# Theo dõi log
docker 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:
cat > ~/n8n-stack/backup.sh <<'EOF'
#!/bin/bash
set -e
BACKUP_DIR=~/n8n-stack/backups
DATE=$(date +%Y%m%d_%H%M%S)
KEEP_DAYS=14
cd ~/n8n-stack
# Dump database
docker 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ày
find $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:
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:
./backup.sh
ls -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:
# Cài AWS CLI
sudo 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:
# AWS Secret Access Key:
# Default region: auto
# Default output: json
# Sửa backup.sh thêm phần upload
cat >> ~/n8n-stack/backup.sh <<'EOF'
# Upload to Cloudflare R2
aws s3 cp $BACKUP_DIR/n8n_db_${DATE}.sql.gz \
s3://your-bucket/n8n-backups/ \
--endpoint-url https://.r2.cloudflarestorage.com \
--profile r2
aws s3 cp $BACKUP_DIR/n8n_data_${DATE}.tar.gz \
s3://your-bucket/n8n-backups/ \
--endpoint-url https://.r2.cloudflarestorage.com \
--profile r2
EOF
Step 11: Update n8n định kỳ (an toàn)
n8n release version mới đều đặn. Update:
cd ~/n8n-stack
# Backup TRƯỚC khi update
./backup.sh
# Pull image mới
docker compose pull
# Recreate container (giữ volume data)
docker compose up -d
# Verify
docker 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:
# Thay vì
image: n8nio/n8n:latest
# Pin cụ thể version đang chạy stable
image: n8nio/n8n:1.65.2 # ví dụ
Step 12: Bảo mật bổ sung
SSH key only, disable password
sudo nano /etc/ssh/sshd_config
# Sửa: PasswordAuthentication no
# Sửa: PermitRootLogin no
sudo systemctl restart ssh
Fail2ban chống brute force
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
Auto security update
sudo apt install unattended-upgrades -y
sudo 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:
- Tạo workflow mới tên "Error Handler".
- Node 1: Error Trigger (auto trigger khi workflow khác fail).
- Node 2: Telegram Send Message với chi tiết error.
- 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: docker stats 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: curl https://n8n.yourdomain.com/webhook-test/abc.
Caddy không lấy được cert HTTPS
DNS chưa propagate đúng IP, hoặc port 80 bị block. Test curl -I http://n8n.yourdomain.com - 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.
Bài viết liên quan
VPS phù hợp chạy n8n self-host?
TND Cloud VPS 50 (4vCPU/4GB/50GB - 639k/tháng) là sweet spot cho n8n cá nhân/team nhỏ. Lên VPS 80 nếu workflow nhiều. Ceph SSD NVMe + RAM ECC + datacenter VN/US.
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.



