วิธีติดตั้ง n8n บน VPS ด้วย Docker และตั้งค่า HTTPS
เรียนรู้วิธีติดตั้ง n8n บน VPS ผ่าน Docker Compose พร้อมฐานข้อมูล Postgres และ HTTPS ครบวงจร แก้ปัญหา WEBHOOK_URL ไม่ทำงาน รวมถึงการตั้งค่า encryption-key ที่ถูกต้อง
สิ่งที่คุณกำลังสร้าง
n8n คือเครื่องมือสำหรับทำ workflow automation ซึ่งเป็นตัวแก้ไขแบบ visual ที่ให้คุณกำหนด trigger เช่น webhook, ตารางเวลา หรือการส่งฟอร์ม เพื่อเรียกใช้งานชุดของ node ต่างๆ ในการเรียกใช้ API, ปรับเปลี่ยนรูปแบบข้อมูล และเขียนข้อมูลลงในระบบอื่น เครื่องมือนี้กลายเป็นตัวเชื่อมมาตรฐานสำหรับ workflow ของ AI-agent เนื่องจากสามารถสื่อสารกับผู้ให้บริการโมเดลและฐานข้อมูลทุกแห่งได้โดยที่คุณไม่ต้องเขียน service ขึ้นมาเอง การใช้ docker run เพียงหนึ่งคำสั่งจะช่วยให้คุณได้ตัวแก้ไขที่ใช้งานได้ภายในเวลาสองนาที แต่คู่มือนี้จะกล่าวถึงอีกเก้าสิบเปอร์เซ็นต์ที่เหลือ นั่นคือการทำให้ระบบมีความทนทานด้วยการใช้ Postgres แทนไฟล์ SQLite ที่เป็นค่าเริ่มต้น, การเข้าถึงผ่าน HTTPS และส่วนที่เกือบทุกคนมักทำผิดพลาด คือการทำให้ webhook สามารถส่ง URL ที่โลกภายนอกสามารถเข้าถึงได้จริง
stack ที่เสร็จสมบูรณ์จะประกอบด้วย container สองตัวบน Docker network เดียวกัน ได้แก่ ตัว n8n เอง และฐานข้อมูล Postgres ที่เก็บ workflow และ credential ต่างๆ โดยมี reverse proxy บน host ทำหน้าที่จัดการ TLS termination และส่งต่อคำขอไปยัง n8n บน localhost ดังนั้นจึงไม่มีส่วนใดที่เปิดรับการเชื่อมต่อจากอินเทอร์เน็ตโดยตรงยกเว้นผ่าน proxy ตัวนี้ ซึ่งจะทำงานร่วมกับบริการอื่นๆ ใน รายการ self-hosting ประจำปี 2026
ข้อกำหนดเบื้องต้นและขีดจำกัดตามความเป็นจริง
คุณต้องใช้ VPS ที่มี RAM อย่างน้อย 1 GB และควรวางแผนไว้ที่ 2 GB เมื่อ workflow เริ่มทำงานจริง เนื่องจาก execution รวมกับ Node.js runtime จะใช้หน่วยความจำ และ out-of-memory killer อาจหยุด container ระหว่างการทำงาน วิธีนี้เป็นวิธีที่แย่มากในการค้นพบว่าหน่วยความจำไม่เพียงพอ เริ่มต้นด้วย vCPU เดียวก็เพียงพอ
หากเครื่องนี้จะใช้รันบริการที่ต้องใช้ทรัพยากรมากกว่าด้วย ให้กำหนดขนาดเครื่องโดยยึดบริการนั้นเป็นหลัก photo library มักเป็นสาเหตุที่พบได้บ่อย และ ข้อกำหนด RAM ขั้นต่ำจริงของ PhotoPrism และ Immich สูงกว่าที่ n8n ต้องการมาก เช่นเดียวกันกับ media box: Jellyfin server พร้อม front end สำหรับเรียกดูเนื้อหา เช่น Halcyon ซึ่งสร้าง library ขึ้นใหม่ให้มีลักษณะเหมือนร้านเช่าวิดีโอในยุค 90s จะใช้ RAM และ headroom สำหรับ transcoding ก่อนที่ n8n จะเริ่มสังเกตเห็นปัญหาเสียอีก
คุณจำเป็นต้องมีโดเมนหรือซับโดเมน เช่น n8n.example.com โดยต้องตั้งค่า A record ให้ชี้ไปยัง IP สาธารณะของ VPS และต้อง resolve ได้ก่อนที่คุณจะขอใบรับรอง พอร์ต 80 และ 443 ต้องเปิดให้เข้าถึง proxy ได้ ส่วนพอร์ต 5678 ของ n8n เองนั้น ต้องไม่ เปิดรับการเชื่อมต่อจากอินเทอร์เน็ต คุณต้องติดตั้ง Docker Engine และ Compose plugin หาก docker compose version แสดงข้อผิดพลาด docker: 'compose' is not a docker command แสดงว่าคุณกำลังใช้ binary แบบ standalone รุ่นเก่า ซึ่งตัว plugin คือ sudo apt install docker-compose-plugin
SQLite เหมาะสำหรับการทดสอบ แต่ Postgres เหมาะสำหรับงานที่ต้องพึ่งพา
ฐานข้อมูลเริ่มต้นของ n8n คือไฟล์ SQLite ที่ /home/node/.n8n/database.sqlite สำหรับการทดลองใช้งานเบื้องต้นถือว่าเพียงพอ แต่หากคุณไม่ได้ mount volume ข้อมูลจะสูญหายทันทีเมื่อมีการสร้าง container ใหม่ ซึ่งถือเป็นบทเรียนสำคัญ เหตุผลที่ควรเปลี่ยนไปใช้ Postgres ไม่ใช่เรื่องความเร็วในการประมวลผล แต่เป็นเพราะ SQLite ใช้การล็อกแบบ single writer lock ดังนั้นหากมีการรัน workflow หลายรายการพร้อมกัน หรือเมื่อคุณต้องการใช้งานในโหมด queue ในอนาคต จะเกิดข้อผิดพลาด SQLITE_BUSY: database is locked ขึ้นเมื่อมีการเข้าถึงข้อมูลพร้อมกัน (concurrency) ในขณะที่ Postgres ไม่มีข้อจำกัดดังกล่าว อีกทั้งยังสามารถสำรองข้อมูลได้อย่างสะอาดด้วย pg_dump และเป็นฐานข้อมูลที่เอกสารของ n8n แนะนำให้ใช้สำหรับเซิร์ฟเวอร์ที่ใช้งานจริง การย้ายฐานข้อมูลในภายหลังต้องทำด้วยตนเอง ดังนั้นหากเซิร์ฟเวอร์นี้มีความสำคัญ ควรเริ่มต้นด้วย Postgres ตั้งแต่แรก
DNS และไฟร์วอลล์
ให้ชี้ระเบียน DNS และเปิดพอร์ตก่อน เพื่อป้องกันไม่ให้ขั้นตอนการออกใบรับรองในภายหลังล้มเหลวเนื่องจากชื่อโดเมนไม่สามารถ resolve ได้
dig +short n8n.example.com
curl -s ifconfig.me
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow OpenSSH
sudo ufw enableห้ามเปิดพอร์ต 5678 ไฟล์ compose ได้กำหนดให้ n8n ผูกกับ 127.0.0.1:5678 เพื่อให้เฉพาะ reverse proxy ของโฮสต์เท่านั้นที่เข้าถึงได้ และการใช้ ufw allow 5678 จะทำให้การแยกส่วนนี้สูญเสียไป
ไฟล์ Compose
สร้างไดเรกทอรีทำงานและไฟล์ docker-compose.yml นี่คือสแต็กทั้งหมดที่ประกอบด้วยสองบริการ หนึ่งเครือข่ายส่วนตัว และสอง named volume
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: n8n
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- n8n_net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n8n -d n8n"]
interval: 10s
timeout: 5s
retries: 5
n8n:
image: docker.n8n.io/n8nio/n8n:2.29.10
restart: unless-stopped
ports:
- "127.0.0.1:5678:5678"
environment:
- N8N_HOST=n8n.example.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://n8n.example.com/
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- N8N_PROXY_HOPS=1
- GENERIC_TIMEZONE=Europe/London
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- n8n_data:/home/node/.n8n
networks:
- n8n_net
depends_on:
postgres:
condition: service_healthy
volumes:
postgres_data:
n8n_data:
networks:
n8n_net:มีข้อตัดสินใจบางประการที่ควรระบุให้ชัดเจน DB_POSTGRESDB_HOST=postgres คือ ชื่อบริการ ซึ่ง Docker จะใช้ระบุตำแหน่งบนเครือข่ายที่ใช้ร่วมกัน ไม่ใช่ localhost ซึ่งภายในคอนเทนเนอร์ n8n จะหมายถึงตัว n8n เอง ส่วน depends_on ที่ใช้ร่วมกับ condition: service_healthy จะช่วยป้องกันไม่ให้ n8n เริ่มทำงานก่อน Postgres ในช่วงบูต หากไม่มีส่วนนี้ n8n จะเริ่มทำงาน ตรวจไม่พบฐานข้อมูล และหยุดการทำงานไป สำหรับ named volume n8n_data ที่ตำแหน่ง /home/node/.n8n จะเก็บคีย์การเข้ารหัสและฐานข้อมูล (ในกรณีที่ใช้ SQLite) ซึ่งเป็นไดเรกทอรีเดียวที่คุณห้ามทำหายเด็ดขาด ให้กำหนดเวอร์ชันของอิมเมจให้ตายตัว ห้ามใช้ latest โดยเหตุผลจะระบุไว้ในส่วนการอัปเกรดด้านล่าง
ไฟล์เก็บความลับ
ห้ามใส่รหัสผ่านไว้ในไฟล์ compose โดยเด็ดขาด ให้ใส่ไว้ในไฟล์ .env ที่วางอยู่ข้างกันเพื่อให้ Compose อ่านค่าโดยอัตโนมัติ และควรสร้างรหัสผ่านเหล่านั้นให้เป็นค่าสุ่มจริง
printf 'POSTGRES_PASSWORD=%s\n' "$(openssl rand -hex 24)" > .env
printf 'N8N_ENCRYPTION_KEY=%s\n' "$(openssl rand -hex 32)" >> .env
chmod 600 .envค่า N8N_ENCRYPTION_KEY คือสตริงที่สำคัญที่สุดในที่นี้ เนื่องจากเป็นกุญแจที่ใช้เข้ารหัสข้อมูลประจำตัวทุกรายการที่ถูกจัดเก็บไว้ ให้กำหนดค่านี้อย่างชัดเจนแทนการปล่อยให้ n8n สร้างขึ้นเอง เพราะค่าที่คุณสร้างขึ้นเองคือค่าที่คุณสามารถจดบันทึกและนำกลับมาใช้ใหม่ได้ เมื่อ n8n เข้ารหัสข้อมูลประจำตัวรายการแรกด้วยกุญแจนี้แล้ว การเปลี่ยนกุญแจจะทำให้ข้อมูลประจำตัวทั้งหมดไม่สามารถถอดรหัสได้อีกต่อไป ดังนั้นให้กำหนดค่านี้เพียงครั้งเดียวในตอนนี้ และห้ามแก้ไขบรรทัดดังกล่าวอีกเป็นอันขาด
ตัวแปรสภาพแวดล้อมที่กำหนดว่า webhooks จะทำงานหรือไม่
ตัวแปร 4 ตัวควบคุมวิธีการที่ n8n แสดงตัวตนต่อโลกภายนอก และการตั้งค่าตัวแปรเหล่านี้ผิดพลาดเป็นปัญหาที่ถูกสอบถามเข้ามายังฝ่ายสนับสนุนของ n8n มากที่สุด
N8N_HOSTคือชื่อโฮสต์สาธารณะ หรือn8n.example.comหากปล่อยไว้เป็นค่าเริ่มต้นlocalhostในขณะที่อยู่หลังพร็อกซี ตัวแก้ไข (editor) จะพยายามโหลด API ของตัวเองจากlocalhostภายใน เบราว์เซอร์ของคุณ ซึ่งจะล้มเหลวN8N_PROTOCOL=httpsแจ้งให้ n8n ทราบว่าบริการถูกเรียกผ่าน TLS ดังนั้น n8n จะทำเครื่องหมาย session cookie เป็นSecureและสร้าง URL เป็นhttps://N8N_PORT=5678คือพอร์ตที่ n8n รับฟัง ภายในคอนเทนเนอร์ ไม่ใช่พอร์ตสาธารณะ เพราะพร็อกซีเป็นผู้ดูแลพอร์ต 443WEBHOOK_URL=https://n8n.example.com/คือตัวแปรที่มักสร้างปัญหา n8n จะพิมพ์ที่อยู่ webhook ที่คุณต้องนำไปวางใน Stripe, GitHub หรือผู้เรียกภายนอกอื่นๆ โดยสร้างจากค่าเหล่านี้ หากไม่ได้ตั้งค่าหรือตั้งค่าผิด n8n จะย้อนกลับไปใช้N8N_HOST:N8N_PORTและแสดงผลเป็นhttps://n8n.example.com:5678/webhook/...หรือที่แย่กว่านั้นคือhttp://localhost:5678/webhook/...โดยไม่มีข้อความแจ้งเตือนข้อผิดพลาดใดๆ ทำให้ดูเหมือนถูกต้องแต่ไม่สามารถเข้าถึงได้จากอินเทอร์เน็ต ส่งผลให้คำขอจากผู้เรียกหายไปโดยไม่มีการตอบกลับ ให้ตั้งค่านี้เป็น URL ฐานสาธารณะที่ถูกต้องพร้อมเครื่องหมายทับปิดท้าย (trailing slash) จากนั้นตรวจสอบให้แน่ใจว่าโหนด webhook แสดง URL ที่ไม่มีพอร์ตระบุไว้
N8N_PROXY_HOPS=1 แจ้งให้เซิร์ฟเวอร์ Express ของ n8n เชื่อถือพร็อกซีที่อยู่ด้านหน้า เพื่อให้การจำกัดอัตรา (rate-limiting) และฟีเจอร์ใดก็ตามที่อ่าน IP ของไคลเอนต์มองเห็นที่อยู่จริงแทนที่จะเป็นที่อยู่ของพร็อกซี ตัวแปรหนึ่งที่คุณ ไม่ควร ตั้งค่าที่นี่คือ N8N_RUNNERS_ENABLED: เนื่องจาก task runners ซึ่งเป็นส่วนที่ n8n ใช้รันตรรกะ Code-node ในกระบวนการแยกส่วน (sandboxed process) ได้กลายเป็นค่าเริ่มต้นตั้งแต่เวอร์ชัน 1.69 และเป็นข้อบังคับสำหรับสาย 2.x ที่คู่มือนี้อ้างอิง ดังนั้นการเลือกเปิดใช้งานแบบเดิมจึงถือว่าเลิกใช้แล้ว หากคุณตั้งค่านี้ในตอนนี้ n8n จะเพียงแค่บันทึกประกาศแจ้งเตือนให้คุณลบออกเท่านั้น
การเริ่มทำงานครั้งแรก
docker compose up -d
docker compose ps
docker compose logs -f n8nการเริ่มทำงานครั้งแรกที่สมบูรณ์จะจบลงด้วยบรรทัด Editor is now accessible via: โดยมีบรรทัด n8n ready on ..., port 5678 อยู่ด้านบน docker compose ps ควรแสดงคอนเทนเนอร์ทั้งสองรายการคือ Up โดยที่ postgres จะถูกทำเครื่องหมายเป็น (healthy) หาก n8n ติดอยู่ในลูป Restarting ให้ตรวจสอบ log ซึ่งมักเกิดจากการเชื่อมต่อฐานข้อมูลหรือสิทธิ์การเข้าถึง volume ที่อธิบายไว้ด้านล่างนี้เสมอ
การใช้งาน TLS ร่วมกับ reverse proxy
ตัว n8n เองสื่อสารผ่าน HTTP ปกติที่พอร์ต 5678 ดังนั้นจึงต้องมีตัวกลางคอยทำหน้าที่ terminate HTTPS โดยมีทางเลือกที่ชัดเจน 2 ทาง
หากคุณใช้งานคอนเทนเนอร์หลายตัวอยู่แล้ว ให้วาง n8n ไว้หลัง Traefik reverse proxy ซึ่งออกใบรับรอง TLS ให้โดยอัตโนมัติ ด้วยการกำหนด labels เพียงไม่กี่รายการ Traefik จะทำการร้องขอและต่ออายุใบรับรองให้คุณเอง
หากนี่เป็นแอปพลิเคชันเดียวบนเซิร์ฟเวอร์ การใช้ nginx virtual host ร่วมกับใบรับรองจาก Let's Encrypt จะเป็นวิธีที่ง่ายกว่า ให้ใช้ การตั้งค่า TLS ด้วย Certbot และ nginx บน Ubuntu 24.04 เพื่อขอใบรับรอง จากนั้นจึงใช้ server block ดังนี้:
server {
listen 443 ssl;
server_name n8n.example.com;
ssl_certificate /etc/letsencrypt/live/n8n.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/n8n.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600;
client_max_body_size 16m;
}
}ส่วนหัว Upgrade และ Connection "upgrade" เป็นสิ่งที่จำเป็น n8n จะส่งข้อมูลอัปเดตการทำงานแบบสดไปยังหน้าแก้ไขผ่าน WebSocket หากไม่มีสองบรรทัดนี้ หน้าเข้าสู่ระบบจะโหลดขึ้นมาแต่จะค้างพร้อมกับแถบแจ้งเตือนว่าการเชื่อมต่อขาดหาย ส่วน proxy_read_timeout 3600 ช่วยป้องกันไม่ให้การทำงานที่ใช้เวลานานถูกตัดการเชื่อมต่อที่ค่าเริ่มต้น 60 วินาทีของ nginx สำหรับส่วนหัว X-Forwarded-Proto $scheme นั้นเป็นส่วนประกอบคู่กับ N8N_PROXY_HOPS=1 โดยจะแจ้งให้ n8n ทราบว่าคำขอต้นทางเป็น HTTPS แม้ว่า proxy จะส่งต่อมาผ่าน HTTP ปกติก็ตาม เพื่อป้องกันไม่ให้ n8n ตัดสินว่าการเชื่อมต่อไม่ปลอดภัยและปฏิเสธคุกกี้ของตัวเอง
เวิร์กโฟลว์แรกของคุณ เพื่อให้เห็นภาพการใช้งานจริง
เปิด https://n8n.example.com/ สร้างบัญชีเจ้าของ (ในส่วนถัดไป) และสร้างเวิร์กโฟลว์ขนาดเล็กที่สุดเพื่อพิสูจน์ว่าเส้นทางทำงานได้จริง: เริ่มจาก webhook ขาเข้า, การเรียก HTTP, และการตอบกลับขาออก
- เพิ่มโหนด Webhook ตั้งค่า method เป็น
POSTและกำหนด path เช่นhelloระบบจะแสดง URL สองชุด คือ Test URL และ Production URL ซึ่งเป็นสาเหตุของรายงานปัญหา "webhook ของฉันไม่ทำงาน" ถึงครึ่งหนึ่ง โดย Test URL จะตอบสนองต่อการเรียกเพียงครั้งเดียวและทำได้เฉพาะในขณะที่คุณคลิก Listen for test event เท่านั้น หลังจากนั้นจะหมดอายุ ส่วน Production URL จะตอบสนองทุกครั้งที่เวิร์กโฟลว์อยู่ในสถานะ Active - เพิ่มโหนด HTTP Request ต่อจากโหนดแรก โดยชี้ไปยัง public JSON API ใดก็ได้ การใช้ GET ไปที่
https://api.github.com/zenจะได้ข้อความแบบบรรทัดเดียว ซึ่งเพียงพอสำหรับการทดสอบ - เพิ่มโหนด Respond to Webhook และตั้งค่าตัวเลือก Respond ในโหนด Webhook เป็น "Using Respond to Webhook node" เพื่อให้ผู้เรียกได้รับผลลัพธ์จากโหนด HTTP กลับไป
- สลับสถานะเวิร์กโฟลว์เป็น Active (มุมขวาบน) แล้วเรียกใช้งานด้วยคำสั่ง:
curl -X POST https://n8n.example.com/webhook/helloคุณควรได้รับข้อความ zen กลับมา ซึ่งเป็นการทำงานแบบ POST เข้า, เรียก API, และตอบกลับออกไป อันเป็นรูปแบบพื้นฐานของระบบอัตโนมัติส่วนใหญ่
สำหรับการทำงานตามกำหนดเวลา ให้เปลี่ยนโหนด Webhook เป็น Schedule Trigger แล้วเรียกไปยัง model endpoint แทน ซึ่งการใช้โมเดลที่โฮสต์เองจาก Ollama ที่รันบน VPS เดียวกัน เป็นวิธีที่เรียบง่ายในการสร้างระบบสรุปข้อมูลรายคืน
การจัดการผู้ใช้ ไม่ใช่ basic auth
คู่มือ n8n รุ่นเก่าระบุให้ตั้งค่า N8N_BASIC_AUTH_ACTIVE=true ตัวแปรเหล่านั้นถูกนำออกใน n8n 1.0 และไม่มีผลใด ๆ แล้ว ปัจจุบันการยืนยันตัวตนใช้ บัญชี owner เมื่อโหลด editor เป็นครั้งแรก n8n จะให้คุณสร้าง owner ด้วยอีเมลและรหัสผ่าน และขั้นตอนนี้บังคับใช้ ไม่มี anonymous mode สร้างบัญชีนี้ทันทีหลัง boot ครั้งแรก ก่อนส่ง URL ให้ผู้อื่น ระหว่าง docker compose up กับการส่งแบบฟอร์มครั้งแรก instance จะถูกยึดครองได้โดยผู้ที่เข้าถึงได้ก่อน การเพิ่มชั้น reverse-proxy basic-auth เป็นการล็อกเพิ่มเติมที่เหมาะสม แต่เป็นเพียงปัจจัยเสริม ไม่ใช่การยืนยันตัวตนหลัก บัญชี owner และฟังก์ชันอื่นทั้งหมดในคู่มือนี้ใช้งานได้ใน free community edition หากภายหลังต้องการผู้ใช้เพิ่มเติมที่กำหนด role ได้ละเอียด หรือ SSO ควรอ่าน ฟีเจอร์ใดของ n8n ที่ต้องใช้ licence แบบมีค่าใช้จ่าย ก่อนวางแผนโดยอาศัยฟีเจอร์เหล่านั้น
การสำรองข้อมูล: กุญแจเข้ารหัสต้องมาก่อน ตามด้วยฐานข้อมูล
มีสองสิ่งที่จำเป็นต้องสำรองข้อมูล และทั้งสองสิ่งนี้มีความสามารถในการทดแทนกันได้ไม่เท่ากัน
N8N_ENCRYPTION_KEY ข้อมูลรับรอง (credential) ทุกรายการที่คุณจัดเก็บไว้ใน n8n ไม่ว่าจะเป็น API token, รหัสผ่านฐานข้อมูล หรือ OAuth secret ล้วนถูกเข้ารหัสไว้ที่ปลายทางด้วยกุญแจนี้ เวิร์กโฟลว์ใน Postgres จะไม่สามารถใช้งานได้หากไม่มีกุญแจนี้ หากคุณกู้คืนฐานข้อมูลไปยังเซิร์ฟเวอร์เครื่องใหม่โดยใช้กุญแจที่ต่างออกไป n8n จะไม่สามารถถอดรหัสข้อมูลรับรองใดๆ ได้เลย ซึ่งไม่มีวิธีแก้ไขหรือรีเซ็ตได้ ไฟล์ .env คือที่เก็บกุญแจดังกล่าว ให้คัดลอกไฟล์นี้ออกไปเก็บไว้นอกเซิร์ฟเวอร์ทันทีในวันที่สร้างขึ้น โดยการเก็บไว้ในโปรแกรมจัดการรหัสผ่าน (password manager) เป็นวิธีที่เหมาะสมที่สุด นี่คือการสำรองข้อมูลที่สำคัญที่สุดอย่างแท้จริง
ฐานข้อมูล Postgres สำหรับเวิร์กโฟลว์ ประวัติการทำงาน และตัวข้อมูลรับรองที่ถูกเข้ารหัสเอง:
docker compose exec -T postgres pg_dump -U n8n -d n8n \
| gzip > n8n-db-$(date +%F).sql.gzให้รันคำสั่งดังกล่าวตามกำหนดเวลาและคัดลอกไฟล์ดัมพ์ (dump) ออกจากเซิร์ฟเวอร์ สำหรับการกู้คืนบน VPS เครื่องใหม่: ให้เริ่มการทำงานของ stack หนึ่งครั้งเพื่อให้ฐานข้อมูลถูกสร้างขึ้น จากนั้นหยุดการทำงานของ n8n, โหลดไฟล์ดัมพ์กลับเข้าไปด้วย psql, นำ N8N_ENCRYPTION_KEY ชุดเดิมใส่ลงใน .env แล้วจึงเริ่มการทำงานของ n8n การใช้กุญแจชุดเดิมร่วมกับไฟล์ดัมพ์จะทำให้ได้อินสแตนซ์ที่ใช้งานได้ตามปกติ แต่หากใช้กุญแจชุดใหม่ เวิร์กโฟลว์จะไม่สามารถใช้งานข้อมูลรับรองใดๆ ได้เลย
การอัปเกรด: การล็อกเวอร์ชันด้วย tag
ไฟล์ compose ล็อกเวอร์ชันไว้ที่ n8nio/n8n:2.29.10 แทนที่จะเป็น latest โดยมีจุดประสงค์ n8n มีการออกเวอร์ชัน minor ใหม่แทบทุกสัปดาห์ และบางครั้งมีการเปลี่ยนแปลง schema ของฐานข้อมูลหรือพฤติกรรมของ node ระหว่างเวอร์ชันเหล่านั้น ดังนั้นการใช้ latest หมายความว่าการ pull อัตโนมัติอาจทำให้คุณได้ build ที่ทำการ migrate ฐานข้อมูลทันทีที่เริ่มทำงาน คุณควรล็อกเวอร์ชันไว้อ่าน บันทึกการเปลี่ยนแปลง (release notes) ก่อนที่จะปรับเวอร์ชันขึ้น n8n จะระบุการเปลี่ยนแปลงที่ส่งผลกระทบ (breaking changes) ไว้ในนั้น และคุณควรทำการอัปเกรดอย่างรอบคอบ:
docker compose exec -T postgres pg_dump -U n8n -d n8n | gzip > pre-upgrade.sql.gz
# edit the image tag in docker-compose.yml, then:
docker compose pull n8n
docker compose up -d n8n
docker compose logs -f n8nการข้ามเวอร์ชันหลัก (major-version) เป็นจุดที่เรื่องนี้มีความสำคัญที่สุด ตัวอย่างเช่น ในเวอร์ชัน 2.0 ได้เปลี่ยนค่าเริ่มต้นจาก N8N_BLOCK_ENV_ACCESS_IN_NODE เป็น true ดังนั้น Code node ใดก็ตามที่อ่านค่า process.env จะสูญเสียการเข้าถึงโดยไม่แจ้งเตือนจนกว่าคุณจะตั้งค่ากลับเป็น false นอกจากนี้เวอร์ชันเดียวกันยังเริ่มบังคับใช้สิทธิ์การเข้าถึงไฟล์ตั้งค่าอย่างเข้มงวด โปรดอ่าน หน้าการเปลี่ยนแปลงที่ส่งผลกระทบของเวอร์ชัน 2.0 ก่อนที่จะข้ามไปยังเวอร์ชันหลักใหม่ n8n จะดำเนินการ migrate ฐานข้อมูลที่จำเป็นโดยอัตโนมัติเมื่อเริ่มทำงาน และนั่นคือเหตุผลว่าทำไมการทำ pg_dump ก่อนอัปเกรดจึงเป็นสิ่งที่ขาดไม่ได้ เนื่องจากข้อมูลประจำตัว (credentials) ถูกเข้ารหัสด้วยคีย์ใน .env และข้อมูลหลักอยู่ใน Postgres คอนเทนเนอร์เหล่านี้จึงสามารถลบทิ้งและสร้างใหม่ได้: คุณสามารถอัปเกรดโดยการแทนที่คอนเทนเนอร์ และย้อนกลับ (roll back) โดยการล็อก tag เวอร์ชันก่อนหน้าแล้วกู้คืนข้อมูลจากไฟล์ dump
รูปแบบความล้มเหลวและข้อความที่คุณจะพบ
The requested webhook "POST hello" is not registered. เกิดข้อผิดพลาด 404 เมื่อเรียกใช้ webhook ที่ workflow ไม่ได้อยู่ในสถานะ Active หรือเรียกใช้ path สำหรับทดสอบในขณะที่ไม่มีการรอรับข้อมูลอยู่ Path สำหรับทดสอบ (/webhook-test/...) จะตอบสนองก็ต่อเมื่อคุณกดปุ่ม "Listen for test event" เท่านั้น ส่วน path สำหรับใช้งานจริง (/webhook/...) จะตอบสนองเมื่อเปิดสวิตช์ workflow แล้วเท่านั้น หากพบ This webhook is not registered for GET requests. Did you mean to make a POST request? แสดงว่าใช้ method ผิด โดย node คาดหวัง POST แต่คุณส่ง GET ไป
URL ของ webhook แสดง :5678 หรือ localhost node จะแสดง https://n8n.example.com:5678/webhook/... หรือ http://localhost:5678/... สาเหตุคือ WEBHOOK_URL ไม่ได้ตั้งค่าหรือตั้งค่าไม่ถูกต้อง ทำให้ n8n สร้างที่อยู่จาก N8N_HOST:N8N_PORT แทนที่จะเป็น public base ของคุณ ให้ตั้งค่า WEBHOOK_URL=https://n8n.example.com/ แล้วสร้าง container ใหม่ด้วย docker compose up -d พอร์ตดังกล่าวก็จะหายไป
There was a problem loading init data ในเบราว์เซอร์ ตัว editor โหลดขึ้นมาได้แต่ไม่สามารถติดต่อ backend API ของตัวเองได้ หากอยู่หลัง proxy มักเกิดจาก N8N_HOST หรือ WEBHOOK_URL ไม่ถูกต้อง, proxy ขาด header สำหรับ WebSocket Upgrade หรือ N8N_PROTOCOL ไม่ตรงกับวิธีที่คุณเชื่อมต่อ ให้ตรวจสอบตัวแปรที่เปิดเผยต่อสาธารณะทั้งสี่ตัว และตรวจสอบว่า proxy ส่งต่อ Upgrade และ Connection อย่างถูกต้อง
password authentication failed for user "n8n" ใน log และ container มีการรีสตาร์ทซ้ำๆ รหัสผ่านที่ n8n ส่งไปไม่ตรงกับที่ใช้ตอนเริ่มต้นฐานข้อมูล ข้อควรระวังคือ Postgres จะอ่าน POSTGRES_PASSWORD เฉพาะตอนที่เริ่มสร้างไดเรกทอรีข้อมูลที่ ว่างเปล่า เท่านั้น หากคุณเริ่ม stack ไปแล้วครั้งหนึ่ง แล้วมาเปลี่ยน POSTGRES_PASSWORD ใน .env ตัว volume postgres_data ที่มีอยู่เดิมจะยังคงเก็บรหัสผ่านเก่าไว้ ให้เปลี่ยนกลับเป็นค่าเดิม หรือหากคุณไม่มีข้อมูลที่ต้องเก็บรักษา ให้ docker compose down และ docker volume rm ตัว postgres volume ทิ้ง แล้วเริ่มระบบใหม่ทั้งหมด
EACCES: permission denied, open '/home/node/.n8n/config' ในขณะเริ่มทำงาน n8n ทำงานในฐานะผู้ใช้ node (UID 1000) จึงไม่สามารถเขียนไฟล์ลงในไดเรกทอรี config ได้ ปัญหานี้มักเกิดกับผู้ที่ใช้ bind-mount โฟลเดอร์จาก host (./n8n_data:/home/node/.n8n) ที่มี root เป็นเจ้าของ ให้ใช้ named volume ตามที่แสดงไว้ด้านบน หรือหากจำเป็นต้องใช้ bind mount ให้ sudo chown -R 1000:1000 ./n8n_data ก่อน
Permissions 0644 for n8n settings file /home/node/.n8n/config are too wide. Changing permissions to 0600.. ตั้งแต่เวอร์ชัน 2.x เป็นต้นไป n8n จะบังคับใช้ 0600 กับไฟล์ตั้งค่าดังกล่าวโดยอัตโนมัติและแก้ไขให้เองเมื่อบูตระบบ ข้อความ log นี้หมายความว่าระบบได้แก้ไขสิทธิ์ให้ถูกต้องแล้ว ซึ่งมักเกิดขึ้นหลังจากการทำ bind mount หรือหลังจากการกู้คืนข้อมูลที่ทำให้ไฟล์กลับมามีสิทธิ์แบบหลวมๆ ไม่จำเป็นต้องดำเนินการใดๆ ให้ตั้งค่า N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=false เฉพาะในกรณีที่ระบบไฟล์ของคุณไม่รองรับการจัดการสิทธิ์จริงๆ เท่านั้น
Mismatching encryption keys ข้อความเต็มระบุว่า encryption key ในไฟล์ตั้งค่า /home/node/.n8n/config ไม่ตรงกับ N8N_ENCRYPTION_KEY ใน environment ของคุณ คีย์ใน environment ของคุณแตกต่างจากที่ n8n เคยเขียนลงใน data volume ในการรันครั้งก่อน ซึ่งมักเกิดจากการที่ n8n สุ่มสร้างคีย์ขึ้นมาเองในการบูตครั้งก่อนหน้าตอนที่ยังไม่ได้ตั้งค่าตัวแปรนี้ แล้วคุณมาตั้งค่าใหม่ในภายหลัง ให้ใส่คีย์เดิมกลับเข้าไปใน .env หรือหากคุณไม่มีข้อมูล credentials ที่สำคัญต้องเก็บรักษา ให้ลบไฟล์ config ภายใน volume n8n_data ทิ้ง แล้วปล่อยให้ n8n สร้างขึ้นใหม่ โดยต้องยอมรับว่า credentials เดิมจะอ่านไม่ได้อีกต่อไป
แถบแจ้งเตือนการเข้าสู่ระบบเกี่ยวกับ secure cookies: Your n8n server is configured to use a secure cookie, however you are either visiting this via an insecure URL, or using Safari. คุณตั้งค่า N8N_PROTOCOL=https ไว้แต่เข้าถึง n8n ผ่าน HTTP ธรรมดา ซึ่งมักเกิดจากการเรียกผ่าน IP และพอร์ตโดยตรงแทนที่จะผ่าน HTTPS proxy ให้เข้าถึงผ่าน https://n8n.example.com/ เท่านั้น หากคุณไม่สามารถใช้ HTTPS ได้จริงๆ จึงค่อยตั้งค่า N8N_SECURE_COOKIE=false และห้ามตั้งค่านี้บนเครื่องที่เชื่อมต่อกับอินเทอร์เน็ตโดยตรงเด็ดขาด
หากต้องการนำโมเดลภาษาไปใส่ไว้ใน workflow เหล่านั้น โปรดดู การสร้าง AI workflow ด้วย Claude และ n8n
FAQ
ฉันควรใช้ SQLite หรือ Postgres สำหรับ n8n?
SQLite (ค่าเริ่มต้น) เหมาะสำหรับการทดลองใช้งาน n8n และการใช้งานส่วนตัวที่รัน workflow ทีละรายการ หากคุณต้องพึ่งพาการใช้งานจริงให้ย้ายไปใช้ Postgres เนื่องจาก SQLite มีการล็อกแบบ single writer ซึ่งจะทำให้เกิด database is locked เมื่อมีการทำงานพร้อมกันหลายรายการ และ Postgres สามารถสำรองข้อมูลได้อย่างสะอาดด้วย pg_dump การย้ายฐานข้อมูลในภายหลังต้องทำด้วยตนเอง ดังนั้นหากเซิร์ฟเวอร์นี้มีความสำคัญ ควรเริ่มต้นด้วย Postgres ตั้งแต่แรก
ทำไม webhook ของ n8n ถึงไม่ทำงาน?
สาเหตุเกือบทั้งหมดมาจาก WEBHOOK_URL หากตั้งค่าไม่ถูกต้องหรือไม่ได้ตั้งค่า n8n จะแสดงที่อยู่ webhook ที่สร้างจาก N8N_HOST:N8N_PORT ซึ่งมักจะมี :5678 หรือ localhost ติดมาด้วย แม้จะดูเหมือนถูกต้องแต่จะไม่สามารถเข้าถึงได้จากอินเทอร์เน็ต ทำให้คำขอจากภายนอกมาไม่ถึง ให้ตั้งค่า WEBHOOK_URL=https://n8n.example.com/ และตรวจสอบว่า node แสดง URL ที่ไม่มีพอร์ต สาเหตุที่สองคือการเรียกใช้ webhook ที่ workflow ยังไม่ได้เปิดสถานะ Active ซึ่งจะส่งผลให้ได้รับ The requested webhook ... is not registered.
ฉันต้องสำรองข้อมูลอะไรบ้างใน n8n?
มีสองสิ่งที่ต้องสำรอง: N8N_ENCRYPTION_KEY จากไฟล์ .env ของคุณ เนื่องจากข้อมูลประจำตัว (credential) ทั้งหมดถูกเข้ารหัสไว้ด้วยคีย์นี้ หากทำหายจะทำให้ข้อมูลเหล่านั้นไม่สามารถถอดรหัสได้อีกต่อไป ให้คัดลอกไฟล์นี้ออกจากเซิร์ฟเวอร์ตั้งแต่วันที่สร้าง และสำรองข้อมูล pg_dump ของฐานข้อมูล Postgres สำหรับเก็บ workflow, ประวัติการทำงาน และข้อมูลประจำตัว การกู้คืนข้อมูลต้องใช้ทั้งสองอย่าง คือคีย์เดิมและไฟล์ dump
ฉันจะตั้งค่า n8n ให้ใช้งานผ่าน HTTPS ได้อย่างไร?
n8n ให้บริการผ่าน HTTP ปกติบนพอร์ต 5678 โดยต้องมี reverse proxy อยู่ด้านหน้าเพื่อทำ TLS termination ให้ผูก n8n ไว้กับ 127.0.0.1:5678 เพื่อให้เฉพาะ proxy เท่านั้นที่เข้าถึงได้ จากนั้นใช้ Traefik พร้อมใบรับรองอัตโนมัติ หรือใช้ nginx ร่วมกับใบรับรองจาก Let's Encrypt ให้ตั้งค่า N8N_PROTOCOL=https และ WEBHOOK_URL=https://your-host/ และตรวจสอบให้แน่ใจว่า proxy ได้ส่งต่อ header ของ WebSocket Upgrade แล้ว มิฉะนั้นตัวแก้ไขจะค้าง
ฉันจะอัปเกรด n8n อย่างปลอดภัยได้อย่างไร?
ให้ระบุ image tag ที่เฉพาะเจาะจงแทนการใช้ latest และทำการ pg_dump ก่อนเสมอเนื่องจาก n8n จะรันการย้ายฐานข้อมูล (migration) โดยอัตโนมัติเมื่อเริ่มทำงาน อ่านบันทึกประจำรุ่น (release notes) เพื่อดูการเปลี่ยนแปลงที่อาจส่งผลกระทบ จากนั้นจึงปรับเวอร์ชันของ tag และรัน docker compose pull n8n && docker compose up -d n8n คอนเทนเนอร์สามารถลบทิ้งและสร้างใหม่ได้ ดังนั้นหากเกิดปัญหาให้ย้อนกลับโดยการระบุ tag เดิมและกู้คืนข้อมูลจากไฟล์ dump ก่อนการอัปเกรด