AI Automation

Dùng webhook n8n nhận dữ liệu từ website ghi vào database

SSH vào VPS Linux chạy n8n, bạn muốn tạo một workflow tự động nhận dữ liệu gửi từ website qua webhook, parse nó, rồi ghi thẳng vào PostgreSQL, tất cả không cần viết dòng code backend nào. Bài này hướng dẫn từng bước, trên n8n self-host (bản 2.x), dùng database PostgreSQL (bạn thoải mái thay bằng MySQL nếu quen). Workflow kết quả: gửi dữ liệu tới URL webhook n8n là dữ liệu đã nằm gọn trong bảng.

Yêu cầu trước khi bắt đầu

  • Một VPS Linux đã cài n8n (bản Docker Compose hoặc npm). Nếu chưa có, bạn có thể thuê VPS n8n với Ubuntu 24.04 có sẵn Docker, hoặc tự cài theo hướng dẫn.
  • Database PostgreSQL hoặc MySQL, có thể chạy trong Docker composer cùng n8n hoặc một server riêng.
  • User sudo (non-root) và quyền truy cập vào n8n dashboard (web UI).
  • Kiến thức cơ bản về JSON và SQL (biết SELECT, INSERT là đủ).

Vì sao nên dùng webhook n8n thay vì tự code backend?

Webhook trong n8n là một HTTP endpoint công khai (hoặc có auth) mà bạn tạo ra trong 2 click. Khi website gửi request POST tới URL đó, n8n nhận dữ liệu, parse và chạy tiếp các node xử lý, như ghi database, gửi email, notify Telegram. So với tự viết một REST API bằng Express.js hay FastAPI, n8n giúp bạn khỏi viết code router, validation thủ công, kết nối database, và queue retry. Bạn chỉ cần kéo thả node webhook, node database, map field là xong. Điều này đặc biệt hữu ích khi bạn có nhiều form/submission từ các website khác nhau: mỗi form chỉ cần một webhook riêng, và workflow xử lý hoàn toàn giống nhau.

Bước 1 - Tạo workflow webhook cơ bản

Đăng nhập vào n8n dashboard. Click WorkflowsAdd Workflow. Đặt tên, ví dụ Webhook ghi lead.

Ở canvas trống, nhấn dấu + để thêm node. Chọn node Webhook. Cấu hình:

  • Webhook URL: N8N tự tạo, ví dụ https://n8n.domain.com/webhook/abc123. Ghi lại URL này.
  • HTTP Method: POST.
  • Respond: Respond to Webhook, nếu muốn gửi phản hồi (200 OK) về cho website ngay. Để trống nếu không cần.
  • Không bật Authentication ở bước đầu để dễ test. Sau đó nhớ bật Basic/Header Auth.

Save node (Ctrl+S). Click Execute Workflow để kích hoạt webhook lắng nghe.

Sau khi execute, n8n sẽ hiển thị dòng chữ "Waiting for Webhook call". Lúc này workflow đang chờ request.

Bước 2 - Tạo bảng trong database (PostgreSQL)

Trên VPS, kết nối tới PostgreSQL server (ví dụ database tên n8n_data). Tạo bảng lưu dữ liệu. Giả sử bạn nhận dữ liệu từ form liên hệ: tên, email, nội dung.

sudo -u postgres psql

CREATE DATABASE n8n_data;
\c n8n_data;

CREATE TABLE contacts (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Lệnh trên tạo bảng contacts với 4 cột. Bạn điều chỉnh số cột theo dữ liệu gửi lên.

Thoát psql: \q

Ghi nhớ thông tin kết nối: host (thường localhost), port (5432), database name (n8n_data), user/password. Nếu PostgreSQL chạy trong Docker, dùng localhost hoặc tên container.

Bước 3 - Thêm node PostgreSQL vào workflow

Quay lại canvas n8n. Từ node Webhook, kéo ra và thêm node Postgres (tìm trong danh sách).

Cấu hình kết nối database:

  • Click vào PostgresCreate New Credential.
  • Host: localhost hoặc địa chỉ IP container.
  • Port: 5432.
  • Database: n8n_data.
  • User: postgres.
  • Password: mật khẩu bạn đã đặt khi cài PostgreSQL.
  • Nhấn Save để test kết nối. Thông báo xanh là OK.

Thiết lập query INSERT: chọn mode Execute Query hoặc Insert. Dùng Insert cho đơn giản:

  • Schema: public
  • Table: contacts
  • Columns: name, email, message
  • Values: click vào icon + Add Value, chọn Add Expression.

Trong ô Expression, gõ lần lượt:

{{ $json.body.name }}
{{ $json.body.email }}
{{ $json.body.message }}

Giải thích: $json.body là object chứa dữ liệu từ request POST, n8n parse JSON body vào đây. Nếu website gửi form-encoded (Content-Type: application/x-www-form-urlencoded) thì dùng $json.body['field']. Nếu dùng query parameters, dùng $json.params.

Lưu node. Nếu bạn dùng MySQL, thay node Postgres bằng node MySQL, cấu hình tương tự.

Bước 4 - Test webhook và verify dữ liệu

Workflow của bạn đã có 2 node: Webhook → Postgres. Bấm Execute Workflow để kích hoạt lại (nếu đã tắt). Lúc này webhook sẵn sàng.

Mở terminal trên VPS hoặc máy local, dùng curl để gửi request test:

curl -X POST https://n8n.domain.com/webhook/abc123 \
  -H "Content-Type: application/json" \
  -d '{"name": "Nguyen Van A", "email": "[email protected]", "message": "Cần tư vấn VPS"}'

Nếu cấu hình đúng, curl sẽ trả về 200 OK (hoặc body tuỳ node Respond). Vào PostgreSQL kiểm tra:

psql -d n8n_data -c "SELECT * FROM contacts;"

Output sẽ hiển thị một dòng dữ liệu mới với ID = 1, các field đã ghi. Nếu không có, kiểm tra log n8n ở tab Execution, lỗi thường gặp là sai tên column hoặc giá trị null.

Bước 5 - Bảo mật webhook (không thể bỏ qua)

Webhook không auth là lỗ hổng bảo mật lớn. Ai cũng có thể gửi request tới URL của bạn và chèn dữ liệu. Làm ngay các bước sau:

  1. Bật Header Auth trong node Webhook: nhập key (vd X-Api-Key) và value (mật khẩu dạng chuỗi dài).
  2. Website gửi kèm header đó trong mỗi request. Với form HTML bạn không thể thêm header, nhưng nếu website gửi AJAX/fetch thì hoàn toàn làm được.
  3. Giới hạn IP nguồn bằng firewall (ufw hoặc nftables), chỉ cho phép IP của website gửi request.
  4. Chặn truy cập webhook qua internet nếu chỉ dùng nội bộ: dùng nginx reverse proxy chặn /webhook/ trừ mạng nội bộ.

Đọc thêm bảo mật n8n self-host: khoá webhook lạ và siết firewall để có checklist đầy đủ.

Xử lý lỗi thường gặp

Webhook nhận request nhưng database không ghi

Kiểm tra execution log trong n8n: vào tab Executions → chọn execution gần nhất → xem node nào báo lỗi. Lỗi phổ biến: cột name bị null do expression sai. Hãy in thử node Set (chuyển đổi dữ liệu) trước node database: {{ JSON.stringify($json) }} để xem cấu trúc dữ liệu thực tế.

Lỗi kết nối database: "connection refused"

Nguyên nhân: PostgreSQL chỉ listen localhost, nhưng n8n trong container connect qua IP Docker. Giải pháp: dùng host.docker.internal thay localhost, hoặc cho n8n container chạy network chung với database (docker network).

Webhook trả về 404

Workflow chưa được execute (ở trạng thái "Inactive"). Bấm Execute Workflow một lần để kích hoạt webhook. Nếu vẫn lỗi, kiểm tra nginx reverse proxy có pass đúng path /webhook/ không.

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

Webhook n8n có hỗ trợ nhận dữ liệu dạng JSON lồng nhau không?

Có. Dùng expression {{ $json.body.something.nested }} để truy cập trường lồng. Nếu không rõ cấu trúc, dùng node Code để parse object hoặc log ra key.

Tôi có thể dùng webhook n8n để nhận dữ liệu từ Webhook.site hoặc Zapier không?

Được. Bất kỳ service nào có thể gửi HTTP POST tới URL webhook n8n đều hợp lệ, Webhook.site, Make (Integromat), form builder (Typeform, Google Forms), hay script bash trên server khác.

Nếu website gửi dữ liệu dạng application/x-www-form-urlencoded thì sao?

n8n node Webhook tự động parse body dạng form (x-www-form-urlencoded) vào $json.body giống JSON. Bạn vẫn dùng expression $json.body.fieldname. Nếu không được, bật nút Raw Body trong node Webhook và tự parse bằng node Code.

Có cần cài thêm node package gì cho n8n không?

Không. Node Postgres và MySQL là node mặc định của n8n. Nếu dùng Docker Compose, cài sẵn. Nếu dùng npm, bạn đã có sẵn. Chỉ cần credential đúng.

Làm sao để xử lý dữ liệu khi webhook nhận nhiều request cùng lúc?

n8n xử lý song song mỗi request trong một execution riêng. Nếu workload cao (hàng trăm request/giây), bạn cần dùng Queue Mode với Redis, xem bài n8n queue mode với Redis: khi nào cần tách worker. Với dữ liệu form thông thường (vài chục request/giờ), chế độ mặc định đủ dùng.

Bài viết liên quan

Lưu ý: Bài viết mang tính tham khảo, tổng hợp kiến thức chung. Mỗi hệ thống, hạ tầng và nhu cầu có đặc thù riêng, nên kiểm thử trong môi trường an toàn và tham vấn kỹ sư trước khi triển khai thực tế.