SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor

วิธีติดตั้ง 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 เข้ารหัสข้อมูลประจำตัวรายการแรกด้วยกุญแจนี้แล้ว การเปลี่ยนกุญแจจะทำให้ข้อมูลประจำตัวทั้งหมดไม่สามารถถอดรหัสได้อีกต่อไป ดังนั้นให้กำหนดค่านี้เพียงครั้งเดียวในตอนนี้ และห้ามแก้ไขบรรทัดดังกล่าวอีกเป็นอันขาด

ตัวแปรสภาพแวดล้อมที่กำหนดการทำงานของ webhook

ตัวแปร 4 ตัวควบคุมวิธีการที่ n8n นำเสนอตัวเองต่อโลกภายนอก และการตั้งค่าตัวแปรเหล่านี้ผิดพลาดเป็นสาเหตุอันดับหนึ่งของคำถามที่ส่งเข้ามายังฝ่ายสนับสนุนของ n8n

  • N8N_HOST คือชื่อโฮสต์สาธารณะ หรือ n8n.example.com หากปล่อยไว้เป็นค่าเริ่มต้น localhost ในขณะที่อยู่หลังพร็อกซี ตัวแก้ไข (editor) จะพยายามโหลด API ของตัวเองจาก localhost ใน เบราว์เซอร์ของคุณ ซึ่งจะทำให้เกิดความล้มเหลว
  • N8N_PROTOCOL=https แจ้งให้ n8n ทราบว่าบริการถูกส่งผ่าน TLS ดังนั้น n8n จะทำเครื่องหมายคุกกี้เซสชันเป็น Secure และสร้าง URL เป็น https://
  • N8N_PORT=5678 คือพอร์ตที่ n8n รับฟัง ภายในคอนเทนเนอร์ ไม่ใช่พอร์ตสาธารณะ เนื่องจากพร็อกซีเป็นผู้ดูแลพอร์ต 443
  • WEBHOOK_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 แยกออกจากกระบวนการหลักนั้น เป็นฟีเจอร์ที่ต้องเลือกเปิดใช้งานเองตลอดช่วงเวอร์ชัน 1.x โดยตัวแปรนี้มีค่าเริ่มต้นเป็น false และคุณต้องตั้งค่าเป็น true แต่ใน n8n 2.0 ได้เปิดใช้งานฟีเจอร์นี้เป็นค่าเริ่มต้น ดังนั้นในเวอร์ชัน 2.x ที่คู่มือนี้แนะนำ ตัวแปรดังกล่าวจึงถือว่าเลิกใช้งานแล้ว (deprecated) และเอกสารของ 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, และการตอบกลับขาออก

  1. เพิ่มโหนด Webhook ตั้งค่า method เป็น POST และกำหนด path เช่น hello โหนดนี้จะแสดง URL สองชุด คือ Test URL และ Production URL ซึ่งเป็นสาเหตุของรายงานปัญหา "webhook ของฉันไม่ทำงาน" ถึงครึ่งหนึ่ง โดย Test URL จะตอบสนองต่อการเรียกเพียงครั้งเดียวและเฉพาะในขณะที่คุณคลิก Listen for test event เท่านั้น หลังจากนั้นจะหมดอายุ ส่วน Production URL จะถูกลงทะเบียนเมื่อคุณกด publish เวิร์กโฟลว์ และจะตอบสนองตั้งแต่นั้นเป็นต้นไป
  2. เพิ่มโหนด HTTP Request ต่อจากโหนดแรก โดยชี้ไปยัง public JSON API ใดก็ได้ การใช้ GET ไปที่ https://api.github.com/zen จะได้ข้อความบรรทัดเดียว ซึ่งเพียงพอสำหรับการทดสอบ
  3. เพิ่มโหนด Respond to Webhook และตั้งค่าตัวเลือก Respond ของโหนด Webhook เป็น "Using Respond to Webhook node" เพื่อให้ผู้เรียกได้รับผลลัพธ์จากโหนด HTTP กลับไป
  4. คลิก Publish (มุมขวาบน) แล้วเรียกใช้งานด้วย: curl -X POST https://n8n.example.com/webhook/hello คุณควรได้รับข้อความ zen กลับมา ซึ่งเป็นการทำงานแบบ POST เข้า, เรียก API, และตอบกลับออกไป อันเป็นรูปแบบของระบบอัตโนมัติส่วนใหญ่ คู่มือรุ่นเก่าอาจแนะนำให้สลับปุ่ม Active แต่ n8n 2.0 ได้เปลี่ยนมาใช้การ Publish และ Unpublish แทน

รูปแบบที่ใช้การตั้งเวลาจะเปลี่ยนโหนด 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 ล้วนถูกเข้ารหัสไว้ในสถานะจัดเก็บ (encrypted at rest) ด้วยกุญแจนี้ เวิร์กโฟลว์ใน 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, โหลดไฟล์ dump กลับเข้าไปด้วย psql, นำ N8N_ENCRYPTION_KEY ชุดเดิมใส่ลงใน .env แล้วจึงเริ่มการทำงานของ n8n การใช้กุญแจชุดเดิมร่วมกับไฟล์ dump จะทำให้คุณได้ instance ที่ใช้งานได้ตามปกติ แต่หากใช้กุญแจชุดใหม่ คุณจะได้เวิร์กโฟลว์ที่ไม่สามารถใช้งานข้อมูลรับรองใดๆ ได้เลย

การอัปเกรด: การล็อกเวอร์ชัน (pinning)

ไฟล์ 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 นอกจากนี้เวอร์ชันดังกล่าวยังเริ่มบังคับใช้สิทธิ์การเข้าถึงไฟล์ตั้งค่าอย่างเข้มงวด เปิดใช้งาน task runners เป็นค่าเริ่มต้น และเปลี่ยนปุ่มสลับ Activate workflow เป็น Publish โปรดอ่าน หน้าการเปลี่ยนแปลงที่ส่งผลกระทบในเวอร์ชัน 2.0 ก่อนที่จะข้ามไปยังเวอร์ชันหลักใหม่ n8n จะดำเนินการย้ายข้อมูลฐานข้อมูลที่จำเป็นโดยอัตโนมัติเมื่อเริ่มทำงาน ซึ่งเป็นเหตุผลว่าทำไมการทำ pg_dump ก่อนการอัปเกรดจึงเป็นขั้นตอนที่ขาดไม่ได้ เนื่องจากข้อมูลประจำตัว (credentials) ถูกเข้ารหัสด้วยคีย์ใน .env และข้อมูลถูกเก็บไว้ใน Postgres คอนเทนเนอร์เหล่านี้จึงสามารถลบทิ้งได้: คุณสามารถอัปเกรดโดยการแทนที่คอนเทนเนอร์ และย้อนกลับ (roll back) ได้โดยการล็อกเวอร์ชันแท็กเดิมและกู้คืนข้อมูลจากไฟล์ dump

รูปแบบความล้มเหลวและข้อความที่พบ

The requested webhook "POST hello" is not registered. เกิดข้อผิดพลาด 404 เมื่อเรียกใช้ webhook ที่ workflow ยังไม่ได้เผยแพร่ หรือเรียกใช้ 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 แทนที่จะเป็น base URL สาธารณะของคุณ ให้ตั้งค่า WEBHOOK_URL=https://n8n.example.com/ แล้วสร้าง container ใหม่ด้วย docker compose up -d พอร์ตดังกล่าวก็จะหายไป

There was a problem loading init data ในเบราว์เซอร์ ตัวแก้ไขโหลดขึ้นมาได้แต่ไม่สามารถเชื่อมต่อกับ 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 volume ของ postgres แล้วเริ่มระบบใหม่

EACCES: permission denied, open '/home/node/.n8n/config' เมื่อเริ่มต้นระบบ n8n ทำงานในฐานะผู้ใช้ node (UID 1000) และไม่สามารถเขียนไฟล์ลงในไดเรกทอรีการตั้งค่าได้ ปัญหานี้มักเกิดกับผู้ที่ใช้ 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 สร้างใหม่ โดยต้องยอมรับว่าข้อมูลรับรองเดิมจะอ่านไม่ได้อีกต่อไป

แถบแจ้งเตือนการเข้าสู่ระบบเรื่อง 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 และการใช้งานส่วนตัวที่รันเวิร์กโฟลว์ทีละรายการ หากเป็นงานที่สำคัญควรย้ายไปใช้ Postgres เนื่องจาก SQLite มีการล็อกแบบเขียนได้ทีละรายการ ซึ่งจะทำให้เกิด 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/ และตรวจสอบว่าโหนดแสดง URL ที่ไม่มีพอร์ต สาเหตุที่สองคือการเรียกใช้ URL ในโหมด production ของเวิร์กโฟลว์ที่ยังไม่ได้เผยแพร่ ซึ่งจะส่งผลให้ได้รับ The requested webhook ... is not registered.

ฉันต้องสำรองข้อมูลอะไรบ้างใน n8n?

มีสองสิ่งที่ต้องสำรอง: N8N_ENCRYPTION_KEY จากไฟล์ .env ของคุณ เนื่องจากข้อมูลประจำตัวที่จัดเก็บไว้ทั้งหมดถูกเข้ารหัสด้วยคีย์นี้ หากทำหายจะทำให้ไม่สามารถถอดรหัสข้อมูลได้อีกต่อไป ควรคัดลอกไฟล์นี้ออกจากเซิร์ฟเวอร์ตั้งแต่วันที่สร้าง และอีกอย่างคือ pg_dump ของฐานข้อมูล Postgres สำหรับเวิร์กโฟลว์ ประวัติการทำงาน และข้อมูลประจำตัว การกู้คืนข้อมูลต้องใช้ทั้งสองอย่างนี้ควบคู่กัน คือคีย์เดิมและไฟล์ดัมพ์

ฉันจะนำ 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 จะรันการย้ายฐานข้อมูลโดยอัตโนมัติเมื่อเริ่มทำงาน โปรดอ่านบันทึกประจำรุ่น (release notes) เพื่อดูการเปลี่ยนแปลงที่อาจส่งผลกระทบ จากนั้นจึงปรับเวอร์ชันของ tag และรัน docker compose pull n8n && docker compose up -d n8n คอนเทนเนอร์สามารถลบทิ้งได้ ดังนั้นหากมีปัญหาให้ย้อนกลับโดยการระบุ tag เดิมและกู้คืนไฟล์ดัมพ์ก่อนการอัปเกรด