Tới nội dung
Cloudj

Ứng dụng VPS

Tự host n8n trên VPS Frankfurt: Docker, HTTPS và mở rộng quy mô

Hướng dẫn tự host n8n trên VPS Frankfurt: Docker Compose với PostgreSQL, HTTPS qua reverse proxy, sao lưu định kỳ và thời điểm nên chuyển sang queue mode.

Cập nhật · 4 phút đọc

Tự host n8n trên VPS nghĩa là toàn bộ quy trình tự động hóa, thông tin đăng nhập các dịch vụ và lịch sử chạy đều nằm trên máy chủ do bạn kiểm soát. Nếu bạn làm việc với khách hàng hoặc đối tác ở Liên minh châu Âu, đặt n8n trên VPS Frankfurt còn giúp dữ liệu được lưu tại Đức. Bài này đi theo đúng trình tự một hệ thống thật lớn dần: bắt đầu với một container, chuyển sang bố cục production có PostgreSQL và HTTPS, sao lưu định kỳ, và cuối cùng là queue mode khi một tiến trình không còn gánh nổi.

"Dữ liệu ở EU" nghĩa là gì và không có nghĩa gì

Chạy n8n ở Frankfurt nghĩa là định nghĩa workflow, credential đã mã hóa và log thực thi nằm trên ổ đĩa ở Đức. Điều này giúp việc trả lời câu hỏi "dữ liệu lưu ở đâu" với khách hàng châu Âu đơn giản hơn. Nhưng nó không khiến mọi workflow ở lại EU: một node gọi API đặt ở Mỹ vẫn gửi dữ liệu sang đó. Hãy liệt kê các dịch vụ mà workflow chạm tới, và coi vị trí máy chủ là một phần của công tác bảo vệ dữ liệu, không phải toàn bộ.

Máy chủ Cloudj tại Frankfurt có gói tháng kèm 5 TB băng thông. Nếu đang cân nhắc giữa Đức và các nước lân cận, bài VPS tốt nhất tại Đức nói kỹ về vị trí này, còn hướng dẫn VPS châu Âu so sánh cả bảy quốc gia châu Âu.

Chọn cấu hình: bắt đầu nhỏ, theo dõi số lần chạy

Bản thân tiến trình n8n khá nhẹ. RAM tăng theo lượng dữ liệu mà workflow mang theo, chẳng hạn các phản hồi JSON lớn, file đính kèm và dữ liệu nhị phân. Lộ trình thực tế:

Giai đoạnMáy chủBố cục
Dùng thử1 vCPU, 2 GB RAMMột container, SQLite
Đội dùng thật2 vCPU, 4 GB RAMn8n cùng PostgreSQL, reverse proxy
Workflow nặng hoặc chạy song song nhiều4 vCPU, 8 GB RAM trở lênQueue mode với Redis và worker

CPU shared ổn cho phần lớn tác vụ tự động hóa, vì chúng chủ yếu chờ API phản hồi chứ ít tính toán. Hãy chuyển sang CPU general purpose hoặc dedicated nếu workflow xử lý tập dữ liệu lớn. Bạn có thể tăng CPU và RAM sau trong console, nên cứ chọn đúng giai đoạn hiện tại của mình.

Tự host n8n trên VPS bằng Docker Compose

Bắt đầu từ một máy chủ đã có SSH key, firewall và Docker; bài cài Docker trên VPS hướng dẫn phần này. Trỏ một bản ghi DNS như n8n.example.com về IP máy chủ, rồi tạo thư mục dự án:

mkdir -p ~/n8n && cd ~/n8n

Tạo file .env với giá trị của bạn. Encryption key chỉ tạo một lần và cần cất bản sao ở nơi an toàn: mất nó thì không giải mã được các credential đã lưu.

cat > .env <<'EOF'
N8N_HOST=n8n.example.com
POSTGRES_PASSWORD=change-me-long-random
EOF
echo "N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env

Tạo file docker-compose.yml:

services:
  postgres:
    image: postgres:16
    restart: always
    environment:
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=n8n
    volumes:
      - pg_data:/var/lib/postgresql/data

  n8n:
    image: docker.n8n.io/n8nio/n8n   # môi trường thật nên ghim tag phiên bản
    restart: always
    depends_on:
      - postgres
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
      - N8N_HOST=${N8N_HOST}
      - N8N_PROTOCOL=https
      - N8N_PORT=5678
      - WEBHOOK_URL=https://${N8N_HOST}/
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      - GENERIC_TIMEZONE=Europe/Berlin
      - TZ=Europe/Berlin
    ports:
      - "127.0.0.1:5678:5678"
    volumes:
      - n8n_data:/home/node/.n8n

  caddy:
    image: caddy:2
    restart: always
    network_mode: host
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data

volumes:
  pg_data:
  n8n_data:
  caddy_data:

n8n chỉ lắng nghe trên 127.0.0.1, nên trình soạn thảo và webhook chỉ truy cập được qua reverse proxy. Caddy tự xin và gia hạn chứng chỉ Let's Encrypt, đồng thời chuyển tiếp kết nối WebSocket mà giao diện n8n cần. Tạo file Caddyfile:

n8n.example.com {
    reverse_proxy 127.0.0.1:5678
}

Mở cổng web và khởi động toàn bộ:

sudo ufw allow 80,443/tcp
docker compose up -d
docker compose logs -f n8n

Truy cập https://n8n.example.com và tạo tài khoản owner ngay lập tức, trước khi người khác tìm thấy trang này. Nếu máy chủ đã chạy Nginx, bạn có thể dùng Nginx thay cho Caddy; bài Nginx reverse proxy và SSL có cấu hình mẫu, nhớ truyền header Upgrade và Connection cho WebSocket.

WEBHOOK_URL quan trọng hơn vẻ ngoài của nó. Thiếu biến này, n8n có thể hiển thị URL webhook kèm cổng nội bộ, và dịch vụ bên ngoài sẽ gọi vào một địa chỉ không hoạt động.

Sao lưu và cập nhật

Cần sao lưu ba thứ: database PostgreSQL, encryption key trong .env, và bản export workflow để có thêm một bản dễ đọc.

cd ~/n8n
docker compose exec -T postgres pg_dump -U n8n -Fc n8n > n8n-$(date +%F).dump
docker compose exec -T n8n mkdir -p /home/node/.n8n/backups
docker compose exec -T n8n n8n export:workflow --backup --output=/home/node/.n8n/backups/
docker compose cp n8n:/home/node/.n8n/backups ./workflow-backups

Chép file dump, file .env và thư mục workflow-backups ra ngoài máy chủ theo lịch. Khi cập nhật n8n, hãy đọc release notes, sao lưu trước, rồi chạy:

docker compose pull n8n
docker compose up -d

Ghim tag phiên bản thay vì dùng tag mặc định giúp việc cập nhật diễn ra khi bạn quyết định, chứ không phải bất cứ lúc nào container khởi động lại.

Queue mode: khi một tiến trình không còn đủ

Ở chế độ mặc định, một tiến trình n8n vừa phục vụ giao diện, vừa nhận webhook, vừa chạy mọi execution. Khi các execution dài hoặc dày đặc bắt đầu làm giao diện chậm hay webhook bị trễ, hãy chuyển sang queue mode. Redis giữ hàng đợi, tiến trình chính nhận trigger, còn các container worker riêng chạy execution.

Thay đổi chính là thêm dịch vụ Redis và vài biến môi trường dùng chung giữa tiến trình chính và worker:

  redis:
    image: redis:7
    restart: always

  n8n-worker:
    image: docker.n8n.io/n8nio/n8n
    restart: always
    command: worker
    depends_on:
      - redis
      - postgres
    environment:
      - EXECUTIONS_MODE=queue
      - QUEUE_BULL_REDIS_HOST=redis
      # cùng các biến DB_* và N8N_ENCRYPTION_KEY như dịch vụ n8n chính

Thêm EXECUTIONS_MODE=queue và QUEUE_BULL_REDIS_HOST=redis vào cả dịch vụ n8n chính. Worker cần cùng encryption key và cấu hình database, nếu không sẽ không đọc được credential. Tăng số worker bằng docker compose up -d --scale n8n-worker=3, và chọn cấu hình máy theo số worker bạn chạy. Trước khi chuyển, hãy xem tài liệu n8n để biết các tùy chọn hiện hành, vì chi tiết cấu hình thay đổi qua các phiên bản.

Những dịch vụ hay chạy cùng

Một máy chủ Frankfurt chạy n8n thường dần trở thành nền tảng nội bộ nho nhỏ. Một Git server tự host để quản lý script tự động hóa đặt cạnh n8n rất hợp, còn bài Minecraft trên VPS Đức cho thấy cùng vị trí này được dùng cho một loại tải hoàn toàn khác. Khi một dịch vụ trở nên quan trọng, hãy tách nó ra máy riêng.

Câu hỏi thường gặp

Dùng SQLite thay PostgreSQL được không?

Được, nếu chỉ để thử nghiệm hoặc dùng cá nhân nhẹ nhàng. Với cả đội, PostgreSQL xử lý execution đồng thời và lịch sử chạy ổn định hơn, đồng thời dễ sao lưu nhất quán hơn.

Tự host n8n có miễn phí không?

n8n phát hành theo giấy phép fair-code riêng, cho phép tự host để dùng nội bộ. Nếu bạn định cung cấp n8n cho khách hàng dưới dạng dịch vụ, hãy đọc kỹ điều khoản giấy phép.

Có cần queue mode ngay từ đầu không?

Không. Bắt đầu với bố cục một tiến trình và chuyển khi execution bắt đầu làm chậm giao diện hoặc webhook. Database vẫn giữ nguyên.

Mất encryption key thì sao?

Workflow vẫn còn, nhưng credential đã lưu không giải mã được và phải nhập lại từ đầu. Hãy cất key cùng với bản sao lưu.

Chạy n8n tại Frankfurt

Bắt đầu với bố cục Compose ở trên trên một máy chủ Frankfurt nhỏ, thiết lập sao lưu ngay từ ngày đầu, và chuyển sang queue mode khi khối lượng công việc đòi hỏi. Xem giá hiện hành trên trang bảng giá và triển khai từ console Cloudj, với số dư nạp bằng chuyển khoản ngân hàng bằng VND nếu bạn ở Việt Nam.

Triển khai máy chủ hoặc mua proxy

Chọn vị trí trong console, xem giá trực tiếp và thanh toán từ số dư tài khoản.