วิธีแก้ปัญหา n8n ออฟไลน์บน VPS ด้วยตัวเอง
สาเหตุที่ n8n ดูเหมือนออฟไลน์มี 4 รูปแบบหลัก เรียนรู้วิธีแยกแยะปัญหา WebSocket การรีสตาร์ทวนซ้ำ การถูกสั่ง Kill จาก Out of Memory และ Workflow ที่หยุดทำงาน เพื่อแก้ไขให้ตรงจุด
เหตุใด n8n ถึงออฟไลน์บ่อยครั้ง: สี่ความล้มเหลว หนึ่งอาการ
"n8n ออฟไลน์บ่อยครั้ง" เป็นประโยคที่ครอบคลุมความล้มเหลวที่แตกต่างกันสี่ประการ ซึ่งแต่ละประการต้องใช้วิธีแก้ไขที่ต่างกัน บางครั้งตัวแก้ไขแสดงแถบแจ้งเตือนว่าการเชื่อมต่อขาดหายในขณะที่ container ยังทำงานปกติ บางครั้ง container รีสตาร์ทตัวเอง บางครั้ง kernel สั่งยุติกระบวนการ Node.js เนื่องจากใช้หน่วยความจำมากเกินไป หรือบางครั้งไม่มีสิ่งใดผิดปกติกับกระบวนการเลย แต่ workflow ที่ตั้งไว้กลับไม่ทำงาน หากคุณเปลี่ยนการตั้งค่าผิดจุด คุณอาจต้องเสียเวลาทั้งสุดสัปดาห์ไปกับการแก้ไขปัญหาที่ไม่ได้เกิดขึ้นจริง
ดังนั้น ให้ตรวจสอบก่อนว่าคุณกำลังเผชิญกับความล้มเหลวแบบใดก่อนที่จะปรับแต่งการตั้งค่าใดๆ n8n ทำงานเป็นกระบวนการ Node.js เดียว โดยปกติจะอยู่ภายใน Docker container หนึ่งตัว ซึ่งอยู่หลัง reverse proxy ที่ทำหน้าที่จัดการ TLS (transport layer security) แต่ละเลเยอร์เหล่านี้สามารถเกิดปัญหาได้ในรูปแบบของตนเอง แต่เบราว์เซอร์จะรายงานปัญหาทั้งหมดด้วยข้อความเดียวกัน
ลำดับการตรวจสอบปัญหา
ให้รันคำสั่งเหล่านี้บน VPS (virtual private server) และอ่านค่าที่เครื่องของคุณแสดงผล อย่าเปรียบเทียบกับตัวเลขจากกระทู้ในฟอรัม ค่าที่สำคัญคือค่าที่อธิบายสถานะของเครื่องคุณ ไม่ใช่ของผู้อื่น
docker ps -a --filter name=n8n
docker logs --tail 200 --timestamps n8n
docker inspect n8n | grep -iE 'Status|Running|RestartCount|OOMKilled|ExitCode'
docker stats --no-streamคอลัมน์ STATUS จาก docker ps -a ระบุระยะเวลาที่คอนเทนเนอร์อยู่ในสถานะปัจจุบัน ให้เปรียบเทียบค่านี้กับช่วงเวลาที่ปัญหาของคุณเริ่มเกิดขึ้น หากคอนเทนเนอร์ทำงานมานานก่อนที่ข้อความแจ้งเตือนจะปรากฏ แสดงว่า n8n ไม่ได้ออฟไลน์ สิ่งที่ขัดข้องคือการเชื่อมต่อระหว่างเบราว์เซอร์ของคุณกับแบ็กเอนด์ ซึ่งเป็นเส้นทาง websocket ที่ครอบคลุมในส่วนถัดไป
RestartCount คือจำนวนครั้งที่ Docker ได้รีสตาร์ทคอนเทนเนอร์นี้ ให้จดตัวเลขไว้ รอหนึ่งนาที แล้วอ่านค่าอีกครั้ง หากตัวเลขเพิ่มขึ้นในขณะที่คุณกำลังเฝ้าดู แสดงว่าเกิดลูปการรีสตาร์ท และบรรทัด log ก่อนการรีสตาร์ทแต่ละครั้งจะระบุสาเหตุไว้
OOMKilled คือสถานะ true หรือ false หากเป็น true หมายความว่า Linux kernel ได้สั่งยุติกระบวนการทำงานเนื่องจากใช้หน่วยความจำเกินขีดจำกัด ไม่ว่าจะเป็นขีดจำกัดของคอนเทนเนอร์เองหรือของทั้งเครื่อง ฟิลด์นี้เพียงฟิลด์เดียวสามารถแยกแยะการถูกสั่งยุติเนื่องจากหน่วยความจำเต็ม (memory kill) ออกจากการปิดตัวลงในรูปแบบอื่น ซึ่งเป็นเหตุผลว่าทำไมคุณต้องอ่านค่านี้ก่อนที่จะคาดเดาสาเหตุ
ExitCode คือรหัสที่คอนเทนเนอร์ใช้ในการปิดตัวลงครั้งล่าสุด คุณไม่จำเป็นต้องจำความหมายของรหัสแต่ละตัว ให้อ่านรหัสของคุณ แล้วอ่านส่วนท้ายของ docker logs ที่มี timestamp เดียวกัน ข้อมูลส่วนท้ายของ log และสถานะหน่วยความจำเต็มจะบอกคุณว่าเกิดอะไรขึ้น การดูเพียงอย่างใดอย่างหนึ่งอาจทำให้คุณเข้าใจผิดได้
docker stats แสดงการใช้หน่วยความจำแบบเรียลไทม์เทียบกับขีดจำกัดที่บังคับใช้ ให้เปิดคำสั่งนี้ทิ้งไว้ในเทอร์มินัลที่สอง จากนั้นสั่งรันเวิร์กโฟลว์ที่ทำให้เกิดปัญหา แล้วสังเกตว่าตัวเลขเปลี่ยนแปลงอย่างไรในขณะที่เกิดความล้มเหลว
ข้อความแจ้งเตือนการเชื่อมต่อขาดหายมักเกิดจาก reverse proxy ของคุณ
ตัวแก้ไข n8n จะเปิดการเชื่อมต่อแบบ push ค้างไว้กับ backend เพื่อสตรีมความคืบหน้าของการทำงานไปยัง canvas โดยค่าเริ่มต้นการเชื่อมต่อนี้จะเป็น WebSocket ซึ่งเป็นสิ่งที่ N8N_PUSH_BACKEND เลือกไว้ และมีค่าเริ่มต้นคือ websocket การเชื่อมต่อ WebSocket จะเริ่มต้นด้วยคำขอ HTTP ปกติที่มี header เป็น Connection: Upgrade และ Upgrade: websocket จากนั้นเซิร์ฟเวอร์จะตอบกลับด้วย 101 Switching Protocols และหลังจากนั้นทั้งสองฝั่งจะใช้ TCP socket เดียวกันในการรับส่งข้อมูล
มีสองสาเหตุที่ทำให้การเชื่อมต่อนี้ล้มเหลว ซึ่งทั้งสองสาเหตุเกิดขึ้นที่ตัว proxy ไม่ใช่ที่ n8n สาเหตุแรกคือ proxy สื่อสารกับ upstream ด้วย HTTP/1.0 หรือลบ header ที่ใช้สำหรับการอัปเกรดออก ทำให้การอัปเกรดไม่สำเร็จและตัวแก้ไขพยายามเชื่อมต่อใหม่ตลอดเวลา สาเหตุที่สองคือการอัปเกรดสำเร็จแต่ proxy ปิด socket ในภายหลังเนื่องจากไม่มีการรับส่งข้อมูล เพราะ WebSocket ที่ไม่มีข้อความใดๆ จะดูเหมือนการเชื่อมต่อที่ไม่ได้ใช้งาน (idle connection) ในทั้งสองกรณี container ยังคงทำงานปกติ ข้อความแจ้งเตือนที่ปรากฏคือเบราว์เซอร์กำลังแจ้งให้คุณทราบว่าช่องทางการสื่อสารขาดหายไป
ให้ตรวจสอบเรื่องนี้ในเบราว์เซอร์ก่อนทำการแก้ไขใดๆ โดยเปิดเครื่องมือสำหรับนักพัฒนา (developer tools) ไปที่แท็บ Network กรองข้อมูลเฉพาะ WS แล้วโหลดหน้าตัวแก้ไขใหม่ คำขอ push ควรจะไปถึง 101 Switching Protocols และคงสถานะเปิดไว้ หากคำขอ push ส่งกลับมาเป็นสถานะปกติ หรือปรากฏขึ้นใหม่ทุกๆ สองสามวินาที แสดงว่าปัญหาอยู่ที่ตัว proxy
การตั้งค่า nginx เพื่อรักษาการเชื่อมต่อของตัวแก้ไข
nginx จะไม่ส่งต่อการอัปเกรดการเชื่อมต่อเว้นแต่คุณจะระบุให้ทำ โดยปกติแล้ว proxy_pass จะสื่อสารกับ backend ด้วย HTTP/1.0 และ Connection กับ Upgrade เป็น hop-by-hop headers ที่ nginx จะลบออกระหว่างทาง คุณจึงต้องเพิ่มทั้งสองส่วนนี้กลับเข้าไป บล็อก map ต้องวางไว้ในบริบท http ไม่ใช่ภายใน server หากส่วนที่เหลือของ server block ด้านล่างนี้ไม่คุ้นเคย คำอธิบายทีละบรรทัดของ nginx server block จะครอบคลุมหน้าที่ของแต่ละ directive ไว้
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}server {
listen 443 ssl;
http2 on;
server_name n8n.example.com;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
}proxy_read_timeout คือบรรทัดที่ผู้คนมักลืมใส่ ค่าเริ่มต้นคือ 60 วินาทีและมีผลกับ WebSocket ที่อัปเกรดแล้วด้วย ดังนั้นแท็บตัวแก้ไขที่เปิดทิ้งไว้บนอินสแตนซ์ที่ไม่มีการใช้งานจะตัดการเชื่อมต่อหลังจากผ่านไปประมาณหนึ่งนาทีนับจากข้อความล่าสุด การเพิ่มค่านี้จะช่วยแก้ไขปัญหาแถบแจ้งเตือนที่ปรากฏขึ้นเมื่อคุณกลับมายังแท็บที่เปิดทิ้งไว้
sudo nginx -t && sudo systemctl reload nginx
sudo nginx -T | grep -iE 'proxy_http_version|upgrade|proxy_read_timeout'nginx -T จะแสดงการตั้งค่าที่ทำงานอยู่ทั้งหมดแทนที่จะแสดงเพียงไฟล์เดียว จึงเป็นการพิสูจน์ว่าการแก้ไขของคุณถูกโหลดใช้งานจริง การตั้งค่าที่อยู่ในไฟล์แต่ไม่มีบรรทัด include ใดเรียกใช้งาน คือสาเหตุที่ทำให้การแก้ไขที่ถูกต้องดูเหมือนไม่มีผลใดๆ
จากนั้นให้แจ้ง n8n ว่ามันอยู่หลัง proxy เนื่องจาก n8n จะสร้าง URL จากค่าเหล่านี้
environment:
- N8N_HOST=n8n.example.com
- N8N_PROTOCOL=https
- N8N_PORT=5678
- N8N_PROXY_HOPS=1
- N8N_WEBHOOK_URL=https://n8n.example.com/N8N_PROXY_HOPS มีค่าเริ่มต้นเป็น 0 ซึ่งหมายความว่า n8n จะถือว่าที่อยู่การเชื่อมต่อคือที่อยู่ของไคลเอนต์และเพิกเฉยต่อ X-Forwarded-For ให้ตั้งค่านี้เป็นจำนวนของ proxy ที่อยู่หน้าคอนเทนเนอร์ ณ เดือนสิงหาคม 2026 N8N_WEBHOOK_URL คือชื่อปัจจุบัน และ WEBHOOK_URL แบบเก่าก็ยังคงใช้งานได้แต่จะแสดงคำเตือนเรื่องการเลิกใช้งาน (deprecation warning) ขณะเริ่มระบบ
Traefik ส่งต่อ WebSocket แต่เกิด timeout
Traefik ส่งต่อการอัปเกรด WebSocket โดยไม่มีการใช้ middleware หรือ label เพิ่มเติม ดังนั้นผู้ใช้ Traefik ที่พบข้อความนี้มักจะประสบปัญหา timeout มากกว่าการขาด header โดยการตั้งค่าจะอยู่ที่ entryPoint สำหรับ Traefik v3 ณ เดือนสิงหาคม 2026 ค่า idleTimeout จะมีค่าเริ่มต้นที่ 180 วินาที และ readTimeout มีค่าเริ่มต้นที่ 60 วินาที
entryPoints:
websecure:
address: ":443"
transport:
respondingTimeouts:
readTimeout: 0
idleTimeout: 3600sCaddy จัดการการอัปเกรดโดยอัตโนมัติใน reverse_proxy และไม่จำเป็นต้องใช้ directive ใดๆ เพิ่มเติม หากคุณไม่สามารถเปลี่ยน proxy ได้เนื่องจากเป็นสิทธิ์ของผู้อื่น ให้เปลี่ยนช่องทางการส่งข้อมูล (push channel) ไปใช้ N8N_PUSH_BACKEND=sse แทน ทั้งนี้ SSE (server-sent events) เป็นการตอบสนองแบบ HTTP ปกติที่เปิดค้างไว้ จึงสามารถใช้งานผ่าน proxy ที่ปฏิเสธการอัปเกรดได้ แต่ยังคงถูกตัดการเชื่อมต่อหากมีการตั้งค่า idle timeout ที่เข้มงวดเกินไป การเลือกใช้ proxy เป็นการตัดสินใจแยกต่างหาก และ การเปรียบเทียบ nginx, Caddy และ Traefik ได้ครอบคลุมถึงต้นทุนในการดูแลรักษาของแต่ละตัวไว้แล้ว
เมื่อคอนเทนเนอร์รีสตาร์ทซ้ำๆ
หาก RestartCount เพิ่มขึ้นเรื่อยๆ แสดงว่าคอนเทนเนอร์กำลังล้มเหลวและ Docker กำลังพยายามเริ่มใหม่ ให้เทียบเวลาใน log กับช่วงเวลาที่รีสตาร์ทและอ่านข้อความที่ปรากฏขึ้นทันทีก่อนหน้านั้น สาเหตุหลัก 4 ประการที่พบได้บ่อยคือ: ข้อผิดพลาดในการตั้งค่าที่ทำให้เริ่มทำงานไม่ได้, ฐานข้อมูลที่ n8n เข้าถึงไม่ได้, การ crash หลังจากเริ่มทำงานไปแล้ว และการถูกสั่ง kill เนื่องจากหน่วยความจำไม่พอ
ให้เริ่มตรวจสอบจาก volume เพราะปัญหาเรื่องสิทธิ์การเข้าถึงมักเป็นสาเหตุที่ตรวจพบได้ยาก อิมเมจทางการจะรันด้วยผู้ใช้ที่ไม่มีสิทธิ์พิเศษคือ node และเก็บข้อมูลไว้ใน /home/node/.n8n หาก bind mount ถูกสร้างขึ้นโดย root ผู้ใช้ดังกล่าวจะไม่สามารถเขียนไฟล์ได้ ส่งผลให้กระบวนการทำงานหยุดลงทันทีที่เริ่ม และนโยบายการรีสตาร์ทจะทำให้เกิดลูปซ้ำไปมา
docker compose config
docker run --rm -it --entrypoint sh docker.n8n.io/n8nio/n8n -c 'id'
docker exec n8n ls -ld /home/node/.n8nการใช้ named volume จะช่วยหลีกเลี่ยงปัญหานี้ได้โดยสิ้นเชิง เนื่องจาก Docker จะสร้าง volume ด้วยความเป็นเจ้าของที่ถูกต้อง หากคุณจำเป็นต้องใช้ bind mount ให้ใช้ chown กับไดเรกทอรีบนโฮสต์โดยระบุเป็น numeric user id ตามที่คำสั่งแรกแสดงไว้ การทำความเข้าใจเรื่องการแมปความเป็นเจ้าของระหว่างโฮสต์และคอนเทนเนอร์เป็นสิ่งสำคัญ และ คำอธิบายเกี่ยวกับ PUID และ PGID จะครอบคลุมถึงวิธีการที่อิมเมจเหล่านี้ตัดสินใจว่าใครเป็นผู้เขียนไฟล์
การถูกสั่งหยุดทำงานเนื่องจากหน่วยความจำไม่พอที่ดูเหมือนการแครช
มีเพดานหน่วยความจำสองระดับที่อยู่เหนือกระบวนการทำงานของ n8n ซึ่งมีลักษณะการล้มเหลวที่ต่างกัน เพดานของ container control group จะถูกบังคับใช้โดย kernel หากใช้งานเกินขีดจำกัด กระบวนการจะถูกสั่งหยุดทำงานทันทีโดยไม่มีโอกาสเขียนข้อมูลใดๆ ลงใน log และ OOMKilled จะมีค่าเป็นจริง ส่วนเพดาน V8 heap จะถูกบังคับใช้ภายใน Node.js หากใช้งานเกินขีดจำกัด Node จะแสดงข้อผิดพลาดเกี่ยวกับ heap พร้อม stack trace และปิดตัวเองลง ทำให้ OOMKilled มีค่าเป็นเท็จ เมื่อดูจากเบราว์เซอร์เหตุการณ์ทั้งสองนี้จะดูเหมือนกัน แต่เมื่อดูจาก docker inspect จะพบว่าข้อมูลทั้งสองอยู่ในฟิลด์ที่ต่างกัน
ให้ตั้งค่าเพดาน heap ของ Node ให้ต่ำกว่าขีดจำกัดของ container หากเพดาน heap สูงกว่า V8 จะยังคงจัดสรรหน่วยความจำต่อไปจนเกินจุดที่ kernel จะเข้ามาแทรกแซง ส่งผลให้ตัวจัดการขยะ (garbage collector) ไม่เคยทำงานถึงขีดจำกัดของตนเอง และคุณจะพบกับความล้มเหลวที่รุนแรงกว่าโดยไม่มี log ให้ตรวจสอบ
services:
n8n:
image: docker.n8n.io/n8nio/n8n
restart: unless-stopped
environment:
- NODE_OPTIONS=--max-old-space-size=<MiB, below the container limit>
deploy:
resources:
limits:
memory: <your container limit>ให้เลือกตัวเลขทั้งสองค่าโดยอิงจากทรัพยากรจริงของ VPS ที่คุณมี และเผื่อพื้นที่ไว้สำหรับฐานข้อมูล, proxy และระบบปฏิบัติการด้วย docker stats --no-stream จะแสดงการใช้งานปัจจุบันควบคู่ไปกับขีดจำกัดที่บังคับใช้ เพื่อให้คุณตรวจสอบได้ว่าขีดจำกัดที่คุณกำหนดคือขีดจำกัดที่ Docker นำไปใช้จริง วิธีการบังคับใช้ขีดจำกัดหน่วยความจำใน Compose จะอธิบายรายละเอียดว่าคีย์ใดจะมีผลเหนือกว่าเมื่อมีการตั้งค่าหลายรายการพร้อมกัน
ข้อมูลการทำงานคือสิ่งที่สะสมอยู่เบื้องหลังคุณ
การทำงานหนึ่งครั้งจะเก็บผลลัพธ์ของทุกโหนดไว้ในระหว่างที่รันอยู่ และ n8n จะจัดเก็บข้อมูลเหล่านั้นไว้ ซึ่งส่งผลตามมาสองประการ ประการแรก หน่วยความจำสูงสุดที่ใช้ในการรันหนึ่งครั้งจะถูกกำหนดโดยชุดข้อมูลที่ใหญ่ที่สุดที่คุณส่งผ่านเข้าไป ดังนั้น workflow ที่จัดการข้อมูลหนึ่งหมื่นแถวในคราวเดียวจึงถือเป็นโปรแกรมที่ต่างออกไปจาก workflow เดียวกันที่จัดการข้อมูลครั้งละสองร้อยแถว ประการที่สอง สำเนาที่ถูกจัดเก็บไว้จะเพิ่มขนาดขึ้นเรื่อยๆ จนกว่าจะมีสิ่งใดมาลบออก
การทำ Pruning จะช่วยจัดการปัญหาที่สองนี้ นับตั้งแต่เดือนสิงหาคม 2026 ค่าเริ่มต้นคือการเปิดใช้งาน Pruning โดยมี EXECUTIONS_DATA_MAX_AGE อยู่ที่ 336 ชั่วโมง (14 วัน) และ EXECUTIONS_DATA_PRUNE_MAX_COUNT อยู่ที่ 10000 ค่าเหล่านี้ถือว่าเพียงพอสำหรับ VPS ขนาดเล็กที่รัน SQLite ซึ่งไฟล์เดียวต้องเก็บข้อมูลทุกอย่างและกระบวนการเดียวกันที่ให้บริการตัว editor ก็ต้องอ่านและเขียนไฟล์นั้นด้วย
environment:
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=72
- EXECUTIONS_DATA_PRUNE_MAX_COUNT=1000
- EXECUTIONS_DATA_SAVE_ON_SUCCESS=none
- EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=falseEXECUTIONS_DATA_SAVE_ON_SUCCESS=none คือการตั้งค่าแบบรุนแรง โดยจะเก็บเฉพาะการทำงานที่ล้มเหลวไว้เพื่อการดีบั๊กและลบการทำงานที่สำเร็จทิ้งไป คุณควรตัดสินใจเลือกใช้การตั้งค่านี้อย่างรอบคอบ เพราะหาก workflow สร้างผลลัพธ์ที่ผิดพลาดโดยไม่แจ้ง error คุณจะไม่เหลือข้อมูลใดๆ ให้ตรวจสอบ นอกจากนี้ การทำ Pruning จะทำเครื่องหมายแถวข้อมูลว่าถูกลบก่อนแล้วจึงค่อยลบออกในรอบถัดไป และ SQLite จะนำหน้ากระดาษที่ว่างลงกลับมาใช้ใหม่แทนที่จะคืนพื้นที่ให้ระบบ ดังนั้นขนาดไฟล์บนดิสก์จึงไม่ลดลงทันทีที่คุณเปลี่ยนการตั้งค่า
หากต้องการลดการใช้ทรัพยากรสูงสุดแทนที่จะลดปริมาณข้อมูลที่จัดเก็บรวม ให้ส่งผ่านข้อมูลต่อการรันหนึ่งครั้งให้น้อยลง โดยแบ่งงานขนาดใหญ่เป็น sub-workflow ที่ส่งผลลัพธ์ขนาดเล็กกลับไปยัง parent workflow, ใช้การแบ่งกลุ่มข้อมูลด้วยโหนด Loop Over Items และหลีกเลี่ยงการเก็บชุดข้อมูลทั้งหมดไว้ในโหนด Code
ไฟล์ไบนารีไม่ควรถูกประมวลผลผ่านหน่วยความจำ
N8N_DEFAULT_BINARY_DATA_MODE มีค่าเริ่มต้นเป็น default ซึ่งจะเก็บข้อมูลไบนารีไว้ในหน่วยความจำของกระบวนการที่กำลังทำงานอยู่ ไฟล์ทุกไฟล์ที่โหนดดาวน์โหลดและทุกสำเนาที่ส่งต่อไปยังโหนดถัดไปจะค้างอยู่ในนั้นจนกว่าการทำงานจะสิ้นสุดลง เวิร์กโฟลว์เดียวที่ดึงไฟล์แนบขนาดใหญ่เพียงไม่กี่ไฟล์อาจผลักดันให้กระบวนการใช้หน่วยความจำเกินขีดจำกัด ซึ่งเป็นระดับที่งาน JSON ทั่วไปไม่มีทางเข้าใกล้ นี่คือสาเหตุที่ทำให้เกิดการ crash หลังจากรันเวิร์กโฟลว์เฉพาะเจาะจง ไม่ใช่เกิดตามเวลาที่กำหนด
environment:
- N8N_DEFAULT_BINARY_DATA_MODE=filesystemเมื่อใช้ filesystem ข้อมูลไบนารีจะถูกเขียนลงภายใต้ N8N_BINARY_DATA_STORAGE_PATH ซึ่งโดยค่าเริ่มต้นจะอยู่ในโฟลเดอร์ผู้ใช้ n8n และจะถูกจัดเก็บไว้ในโวลุ่มเดียวกับข้อมูลส่วนอื่นทั้งหมด โปรดตรวจสอบว่าโวลุ่มมีพื้นที่เพียงพอก่อนทำการเปลี่ยนการตั้งค่า N8N_PAYLOAD_SIZE_MAX ใช้กำหนดขนาด payload ของ webhook ขาเข้าที่ใหญ่ที่สุดในหน่วย MiB (mebibytes) โดยมีค่าเริ่มต้นอยู่ที่ 16 การเพิ่มค่านี้จะช่วยให้รับคำขอที่มีขนาดใหญ่ขึ้นได้ แต่คุณต้องยอมรับภาระด้านหน่วยความจำที่เพิ่มขึ้นตามไปด้วย
บริการอื่นใดที่ทำงานอยู่บนเครื่องเดียวกันจะแย่งชิง RAM ในส่วนนี้ หากปัญหา OOM killer เริ่มเกิดขึ้นหลังจากที่คุณเพิ่มคอนเทนเนอร์ฐานข้อมูล การรันฐานข้อมูลใน Docker หรือบนโฮสต์โดยตรง คือสิ่งที่คุณต้องเลือกว่าจะแลกเปลี่ยนกันอย่างไร
นโยบายการเริ่มการทำงานใหม่และการกลับมาทำงานหลังรีบูต
คอนเทนเนอร์ที่ไม่มีนโยบายการเริ่มการทำงานใหม่จะหยุดทำงานถาวรหลังจากที่โปรเซสจบลง และหลังจากที่โฮสต์รีบูต restart: unless-stopped จะช่วยให้คอนเทนเนอร์กลับมาทำงานได้ในทั้งสองกรณี โดยยังคงเคารพสถานะของคอนเทนเนอร์ที่คุณหยุดการทำงานด้วยตนเอง ส่วน restart: always จะเริ่มการทำงานของคอนเทนเนอร์ที่คุณหยุดการทำงานโดยเจตนาใหม่ทันทีที่ Docker เริ่มทำงานในครั้งถัดไป
n8n มี health endpoint ซึ่งกำหนดชื่อโดย N8N_ENDPOINT_HEALTH โดยมีค่าเริ่มต้นคือ healthz ให้ตรวจสอบ endpoint นี้จากโฮสต์ก่อนเพื่อให้แน่ใจว่า path นั้นถูกต้องบนอินสแตนซ์ของคุณ
curl -fsS http://127.0.0.1:5678/healthz
docker exec n8n which wget curl
sudo systemctl is-enabled dockerการทำ healthcheck เพียงอย่างเดียวจะไม่เริ่มการทำงานของบริการใหม่โดยอัตโนมัติ Docker Compose จะทำเครื่องหมายคอนเทนเนอร์ว่า unhealthy และหยุดอยู่เพียงแค่นั้น ดังนั้น healthcheck จึงจำเป็นต้องมีนโยบายการเริ่มการทำงานใหม่หรือตัวตรวจสอบภายนอกควบคู่ไปด้วยจึงจะส่งผล การเขียน healthcheck ที่ทำงานได้จริง และ การทำให้ stack เริ่มทำงานใหม่หลังรีบูต ครอบคลุมทั้งสองส่วนนี้
เวิร์กโฟลว์ไม่ทำงานทั้งที่ n8n ทำงานปกติ
กรณีนี้ไม่มีการแสดงข้อความแจ้งเตือนและไม่มีการรีสตาร์ท คอนเทนเนอร์ยังคงทำงานอยู่ ตัวแก้ไขทำงานได้ปกติ แต่การรันที่คุณคาดหวังกลับไม่ปรากฏในรายการ executions สาเหตุส่วนใหญ่เกิดจาก 4 ปัจจัยดังนี้:
- เวิร์กโฟลว์ไม่ได้ถูกเปิดใช้งาน (Active) ตัวกระตุ้นประเภท Schedule Trigger จะทำงานเฉพาะในเส้นทาง production เท่านั้น ดังนั้นการทดสอบในหน้า canvas จะไม่ทำให้เกิดการตั้งเวลาใดๆ
- เขตเวลา (Timezone) ไม่ตรงกับของคุณ ค่าเริ่มต้นของ
GENERIC_TIMEZONEคือAmerica/New_Yorkดังนั้นการตั้งเวลาไว้ที่ 09:00 จะทำงานที่เวลา 09:00 ในเขตเวลานั้น จนกว่าคุณจะตั้งค่าGENERIC_TIMEZONEและTZให้เป็นเขตเวลาของคุณเอง - ช่วงเวลาที่ระบบหยุดทำงานจะไม่ถูกรันย้อนหลัง ตัวกระตุ้นจะถูกลงทะเบียนเมื่อ n8n เริ่มทำงาน ดังนั้นตารางเวลาที่ควรจะทำงานในช่วงที่คอนเทนเนอร์กำลังรีสตาร์ทจะไม่ถูกรันย้อนหลัง การรันครั้งถัดไปจะเป็นเวลาตามตารางหลังจากที่ระบบเริ่มทำงานแล้วเท่านั้น
- เวิร์กโฟลว์ถูกปิดการใช้งานโดยอัตโนมัติ
N8N_WORKFLOW_AUTODEACTIVATION_ENABLEDถูกปิดไว้เป็นค่าเริ่มต้น และเมื่อเปิดใช้งาน เวิร์กโฟลว์ที่เกิดข้อผิดพลาดซ้ำๆ จะถูกยกเลิกการเผยแพร่ (Unpublished) ซึ่งจะทำให้ดูเหมือนเวิร์กโฟลว์ที่ไม่มีใครเคยเปิดใช้งานมาก่อน
ให้เปิดรายการ executions และกรองข้อมูลตามเวิร์กโฟลว์นั้น หากมีรายการที่ล้มเหลวแสดงว่าปัญหาอยู่ที่ตัวเวิร์กโฟลว์เอง หากล้มเหลวด้วยข้อผิดพลาด 429 จากบริการอื่นที่คุณโฮสต์ไว้บนเครื่องเดียวกัน ขีดจำกัดนั้นเป็นของบริการดังกล่าวไม่ใช่ n8n และ คู่มือการแก้ไขปัญหา 429 ของ SearXNG จะแสดงวิธีแยกแยะระหว่างตัวจำกัดอัตรา (Rate Limiter) ของบริการนั้น กับการที่เอนจินบล็อก IP เซิร์ฟเวอร์ของคุณ หากไม่มีรายการใดปรากฏเลย แสดงว่าเป็นปัญหาที่ตัวกระตุ้น (Trigger) ซึ่งควรตรวจสอบจาก 4 สาเหตุข้างต้น
สิ่งที่ควรเปลี่ยนเป็นอันดับแรก
- อ่าน
STATUS,RestartCountและOOMKilledบนคอนเทนเนอร์ของคุณเองก่อนเริ่มแก้ไขไฟล์ใดๆ - หากคอนเทนเนอร์ไม่เคยหยุดทำงาน ให้แก้ไข proxy upgrade headers และ idle timeout
- หาก
OOMKilledเป็น true ให้กำหนดขีดจำกัดของคอนเทนเนอร์ที่คุณเลือกไว้อย่างตั้งใจ ตั้งค่าเพดาน Node heap ให้ต่ำกว่าขีดจำกัดนั้น และเปลี่ยนข้อมูลไบนารีเป็นfilesystem - หากไม่มีการแจ้งเตือนใดๆ เกิดขึ้น ให้ตรวจสอบว่า workflow เปิดใช้งานอยู่และ timezone ของ instance ตรงกับของคุณ
การตั้งค่าส่วนใหญ่เหล่านี้เป็นการตั้งค่าเพียงครั้งเดียวแล้วไม่ต้องแก้ไขอีก โดยอยู่บนพื้นฐานของการติดตั้งที่ทำงานได้ปกติ หากคุณยังอยู่ในขั้นตอนการติดตั้ง คู่มือการใช้งาน n8n บน Docker พร้อม HTTPS คือพื้นฐานที่การตั้งค่าเหล่านี้ควรถูกนำไปใช้
FAQ
ทำไมตัวแก้ไข n8n ถึงแสดงแถบแจ้งเตือนว่าการเชื่อมต่อขาดหายทั้งที่คอนเทนเนอร์ยังทำงานอยู่?
ตัวแก้ไขจะเปิด WebSocket ค้างไว้เพื่อสตรีมความคืบหน้าของการทำงาน หาก reverse proxy ของคุณไม่ได้ส่งต่อ header Connection: Upgrade และ Upgrade: websocket หรือไม่ได้ใช้ HTTP/1.1 ในการเชื่อมต่อ upstream การอัปเกรดการเชื่อมต่อจะไม่สำเร็จ ทำให้เบราว์เซอร์พยายามเชื่อมต่อใหม่ซ้ำๆ ในขณะที่ n8n ยังทำงานปกติ สำหรับ nginx คุณต้องตั้งค่า proxy_http_version 1.1 ร่วมกับบรรทัด proxy_set_header ทั้งสองบรรทัด และกำหนด proxy_read_timeout ให้ยาวกว่าค่าเริ่มต้นที่ 60 วินาที เพื่อป้องกันไม่ให้แท็บที่ไม่มีการใช้งานถูกตัดการเชื่อมต่อ ตรวจสอบการตั้งค่าที่กำลังทำงานอยู่ด้วย sudo nginx -T ไม่ใช่ไฟล์ที่คุณแก้ไข
ฉันจะแยกแยะการถูกสั่งยุติการทำงานเนื่องจากหน่วยความจำเต็ม (OOM kill) ออกจากการหยุดทำงานปกติได้อย่างไร?
ให้รันคำสั่ง docker inspect n8n | grep -iE 'OOMKilled|ExitCode|RestartCount' และอ่านค่าที่ flag OOMKilled หากเป็น True หมายความว่า kernel สั่งยุติกระบวนการทำงานเนื่องจากใช้หน่วยความจำเกินขีดจำกัด ซึ่งจะไม่มีข้อมูลที่เป็นประโยชน์ใน log ของคอนเทนเนอร์เพราะกระบวนการไม่มีโอกาสเขียนข้อมูลลงไป แต่หากเป็น False พร้อมกับมีข้อผิดพลาดเกี่ยวกับ heap และ stack trace ปรากฏที่ท้ายไฟล์ docker logs แสดงว่า Node.js ทำงานถึงขีดจำกัดของ V8 heap และหยุดทำงานด้วยตัวเอง ให้ตั้งค่า NODE_OPTIONS=--max-old-space-size ให้ต่ำกว่าขีดจำกัดของคอนเทนเนอร์ เพื่อให้เกิดความผิดพลาดแบบที่สอง ซึ่งจะทิ้งหลักฐานไว้ให้ตรวจสอบ
การล้างข้อมูลการทำงาน (pruning) จะคืนพื้นที่ดิสก์ให้ทันทีหรือไม่?
ไม่ การทำงานของ EXECUTIONS_DATA_PRUNE จะทำเครื่องหมายข้อมูลเก่าไว้เพื่อรอการลบ และจะมีกระบวนการในภายหลังมาลบออกตามตารางเวลาที่กำหนดไว้ใน EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL สำหรับ SQLite ไฟล์ฐานข้อมูลจะนำหน้าว่างที่ถูกลบไปกลับมาใช้ใหม่แทนการคืนพื้นที่ให้ระบบไฟล์ ดังนั้นขนาดไฟล์บนดิสก์จะยังคงเท่าเดิมสักระยะหลังจากลบแถวข้อมูลไปแล้ว ให้ตั้งค่า EXECUTIONS_DATA_MAX_AGE และ EXECUTIONS_DATA_PRUNE_MAX_COUNT ให้เหมาะสมกับทรัพยากรของคุณ แล้วค่อยตรวจสอบอีกครั้งในวันถัดไปแทนที่จะตรวจสอบทันที
ทำไม workflow ที่ตั้งเวลาไว้ถึงไม่ทำงานในขณะที่ n8n กำลังรีสตาร์ท?
n8n จะลงทะเบียน trigger เมื่อกระบวนการเริ่มทำงาน และจะไม่ย้อนกลับไปรันตารางเวลาที่ถึงกำหนดในช่วงที่ระบบหยุดทำงาน ดังนั้นการรีสตาร์ทแบบวนซ้ำจะไม่ทำให้เกิดการรันย้อนหลัง และการทำงานครั้งถัดไปจะเป็นไปตามกำหนดเวลาหลังจากที่ระบบเริ่มทำงานแล้ว หากคุณต้องการให้แน่ใจว่างานจะไม่พลาด ให้สั่งรัน workflow จากภายนอกผ่าน webhook เพื่อให้ตรรกะการลองใหม่ (retry logic) อยู่ภายนอก n8n
healthcheck จะรีสตาร์ท n8n เมื่อระบบไม่ตอบสนองหรือไม่?
ไม่โดยตัวมันเอง healthcheck ของ Compose ทำหน้าที่เพียงระบุสถานะว่าคอนเทนเนอร์ปกติหรือผิดปกติเท่านั้น การรีสตาร์ทเป็นหน้าที่ของนโยบายการรีสตาร์ท ดังนั้น restart: unless-stopped คือสิ่งที่ทำให้คอนเทนเนอร์กลับมาทำงานหลังจากหยุดไป และยังช่วยให้คอนเทนเนอร์กลับมาทำงานหลังจากการรีบูตโฮสต์ตราบเท่าที่ Docker service ถูกเปิดใช้งานอยู่ ให้ยืนยันสถานะนี้ด้วย sudo systemctl is-enabled docker หากต้องการให้ระบบจัดการเมื่อสถานะเป็น unhealthy โดยเฉพาะ คุณต้องมีตัวเฝ้าระวังภายนอก Docker ที่คอยอ่านสถานะและรีสตาร์ท service ให้