วิธีแก้ปัญหา n8n ออฟไลน์บน VPS ด้วยตัวเอง
สาเหตุที่ n8n ดูเหมือนออฟไลน์มี 4 รูปแบบหลัก เรียนรู้วิธีแยกแยะปัญหา WebSocket, อาการรีสตาร์ทลูป, การถูกสั่ง OOM Kill และ Workflow ค้าง เพื่อให้คุณแก้ไขปัญหาได้อย่างตรงจุดและแม่นยำ
เหตุผลที่ n8n ออฟไลน์บ่อย: สี่ความล้มเหลวกับหนึ่งอาการ
"n8n ออฟไลน์บ่อย" เป็นประโยคเดียวที่ครอบคลุมความล้มเหลวถึง 4 รูปแบบ ซึ่งแต่ละแบบต้องใช้วิธีแก้ไขที่แตกต่างกัน บางครั้งตัวแก้ไขแสดงแถบแจ้งเตือนว่าการเชื่อมต่อขาดหายในขณะที่ 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 ได้รีสตาร์ทคอนเทนเนอร์นี้ ให้จดตัวเลขไว้ รอหนึ่งนาที แล้วอ่านค่าอีกครั้ง หากตัวเลขเพิ่มขึ้นเรื่อยๆ ขณะที่คุณเฝ้าดู แสดงว่าเกิดภาวะ restart loop และบรรทัด log ก่อนการรีสตาร์ทแต่ละครั้งจะมีสาเหตุของปัญหาอยู่
OOMKilled คือสถานะ true หรือ false หากเป็น true หมายความว่า Linux kernel ได้สั่งยุติกระบวนการทำงานเนื่องจากใช้หน่วยความจำเกินขีดจำกัด ไม่ว่าจะเป็นขีดจำกัดของคอนเทนเนอร์เองหรือของทั้งเครื่อง ฟิลด์นี้เพียงฟิลด์เดียวสามารถแยกแยะการถูกสั่งยุติเนื่องจากหน่วยความจำเต็ม (memory kill) ออกจากการปิดตัวลงในรูปแบบอื่นได้ นี่คือเหตุผลที่คุณต้องตรวจสอบค่านี้ก่อนที่จะคาดเดาสาเหตุ
ExitCode คือรหัสสถานะล่าสุดที่คอนเทนเนอร์ปิดตัวลง คุณไม่จำเป็นต้องจำความหมายของรหัสแต่ละตัว ให้ดูรหัสของคุณ แล้วอ่านส่วนท้ายของ docker logs ที่มี timestamp เดียวกัน ข้อมูลจากส่วนท้ายของ log และสถานะหน่วยความจำเต็มจะบอกคุณว่าเกิดอะไรขึ้น การดูเพียงอย่างใดอย่างหนึ่งอาจทำให้คุณเข้าใจผิดได้
docker stats แสดงการใช้หน่วยความจำแบบเรียลไทม์เทียบกับขีดจำกัดที่บังคับใช้ ให้เปิดคำสั่งนี้ทิ้งไว้ในเทอร์มินัลที่สอง จากนั้นสั่งรัน workflow ที่ทำให้เกิดปัญหา และเฝ้าดูการเปลี่ยนแปลงของตัวเลขขณะที่ความล้มเหลวเกิดขึ้น
แบนเนอร์แจ้งเตือนการเชื่อมต่อขาดหายมักเกิดจาก Reverse Proxy ของคุณ
ตัวแก้ไข n8n จะเปิดการเชื่อมต่อแบบ push ค้างไว้กับแบ็กเอนด์เพื่อให้สามารถสตรีมความคืบหน้าของการทำงานไปยังหน้าจอได้ โดยค่าเริ่มต้นการเชื่อมต่อนี้จะเป็น WebSocket ซึ่งเลือกโดย N8N_PUSH_BACKEND และมีค่าเริ่มต้นคือ websocket การเชื่อมต่อ WebSocket เริ่มต้นด้วยคำขอ HTTP ปกติที่มีเฮดเดอร์ Connection: Upgrade และ Upgrade: websocket เซิร์ฟเวอร์จะตอบกลับด้วย 101 Switching Protocols หลังจากนั้นทั้งสองฝั่งจะใช้ TCP socket เดียวกันในการสื่อสารทั้งสองทิศทาง
มีสองสาเหตุที่ทำให้การเชื่อมต่อนี้ล้มเหลว ซึ่งทั้งสองสาเหตุเกิดขึ้นที่ตัว Proxy ไม่ใช่ที่ n8n สาเหตุแรกคือ Proxy สื่อสารกับ upstream ด้วย HTTP/1.0 หรือตัดเฮดเดอร์ upgrade ออก ทำให้การอัปเกรดไม่สำเร็จและตัวแก้ไขพยายามเชื่อมต่อใหม่ตลอดเวลา สาเหตุที่สองคือการอัปเกรดสำเร็จแต่ Proxy ปิด socket ในภายหลังเนื่องจากไม่มีการรับส่งข้อมูล เพราะ WebSocket ที่ไม่มีข้อความรับส่งจะดูเหมือนการเชื่อมต่อที่ไม่ได้ใช้งาน ทั้งสองกรณีนี้ตัวคอนเทนเนอร์ยังทำงานปกติ แบนเนอร์ที่ปรากฏคือเบราว์เซอร์แจ้งให้คุณทราบว่าช่องทางการสื่อสารขาดหายไป
ให้ยืนยันปัญหานี้ในเบราว์เซอร์ก่อนทำการแก้ไขใดๆ โดยเปิดเครื่องมือสำหรับนักพัฒนา (Developer Tools) ไปที่แท็บ Network กรองข้อมูลเฉพาะ WS แล้วโหลดหน้าตัวแก้ไขใหม่ คำขอ push ควรไปถึง 101 Switching Protocols และคงสถานะเปิดค้างไว้ หากคำขอ push ส่งสถานะโค้ดปกติกลับมา หรือปรากฏขึ้นใหม่ทุกๆ สองสามวินาที แสดงว่าปัญหาอยู่ที่ตัว Proxy
การตั้งค่า nginx เพื่อรักษาการเชื่อมต่อของตัวแก้ไข
nginx จะไม่ส่งต่อการอัปเกรดการเชื่อมต่อหากคุณไม่ได้กำหนดค่าไว้ proxy_pass จะสื่อสารด้วย HTTP/1.0 ไปยังแบ็กเอนด์โดยค่าเริ่มต้น และ Connection กับ Upgrade เป็น hop-by-hop headers ที่ nginx จะลบออกระหว่างทาง คุณจึงต้องเพิ่มส่วนนี้กลับเข้าไป บล็อก map ต้องวางไว้ในบริบท http ไม่ใช่ภายใน server
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 ว่ามันทำงานอยู่หลังพร็อกซี เนื่องจาก 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 ให้ตั้งค่านี้เป็นจำนวนของพร็อกซีที่อยู่หน้าคอนเทนเนอร์ ณ เดือนสิงหาคม 2026 N8N_WEBHOOK_URL คือชื่อปัจจุบัน และ WEBHOOK_URL แบบเก่าก็ยังคงใช้งานได้แต่จะแสดงคำเตือนเรื่องการเลิกใช้งาน (deprecation warning) ขณะเริ่มระบบ
Traefik ส่งต่อ WebSocket แต่เกิด timeout
Traefik ส่งต่อการอัปเกรด WebSocket โดยไม่ต้องใช้ middleware หรือ label เพิ่มเติม ดังนั้นผู้ใช้ Traefik ที่พบข้อความนี้มักจะประสบปัญหา timeout มากกว่าการขาด header การตั้งค่าสามารถปรับได้ที่ entryPoint ณ เดือนสิงหาคม 2026 ใน Traefik v3 ค่าเริ่มต้นของ idleTimeout คือ 180 วินาที และ readTimeout คือ 60 วินาที
entryPoints:
websecure:
address: ":443"
transport:
respondingTimeouts:
readTimeout: 0
idleTimeout: 3600sCaddy จัดการการอัปเกรดโดยอัตโนมัติใน reverse_proxy และไม่จำเป็นต้องใช้คำสั่งเพิ่มเติม หากคุณไม่สามารถเปลี่ยน proxy ได้เนื่องจากเป็นระบบของผู้อื่น ให้เปลี่ยนช่องทางการ push ไปใช้ N8N_PUSH_BACKEND=sse แทน ทั้งนี้ SSE (server-sent events) เป็นการตอบกลับ HTTP ปกติที่เปิดค้างไว้ จึงสามารถใช้งานผ่าน proxy ที่ปฏิเสธการอัปเกรดได้ แต่ยังคงถูกตัดการเชื่อมต่อหากมีการตั้งค่า idle timeout ที่เข้มงวด การเลือกใช้ proxy เป็นการตัดสินใจแยกต่างหาก และ การเปรียบเทียบ nginx, Caddy และ Traefik ได้ครอบคลุมถึงภาระในการดูแลรักษาของแต่ละตัวไว้แล้ว
เมื่อคอนเทนเนอร์รีสตาร์ทซ้ำๆ
หาก RestartCount เพิ่มขึ้นเรื่อยๆ แสดงว่าคอนเทนเนอร์กำลังล้มเหลวและ Docker กำลังพยายามเริ่มทำงานใหม่ ให้ตรวจสอบ timestamp ใน log เทียบกับการรีสตาร์ทแต่ละครั้ง และอ่านข้อความที่ปรากฏขึ้นทันทีก่อนเกิดการรีสตาร์ท สาเหตุส่วนใหญ่มาจาก 4 ประการ ได้แก่ ข้อผิดพลาดในการตั้งค่าที่ทำให้ไม่สามารถเริ่มทำงานได้, ฐานข้อมูลที่ n8n เข้าถึงไม่ได้, การแครชหลังจากเริ่มทำงานไปแล้ว และการถูกสั่งยุติการทำงานเนื่องจากหน่วยความจำไม่เพียงพอ
ให้เริ่มตรวจสอบจาก 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 จะพบว่าค่าทั้งสองอยู่ในฟิลด์ที่ต่างกัน
ให้ตั้งค่าเพดาน Node heap ให้ต่ำกว่าขีดจำกัดของ container หากเพดาน heap สูงกว่าขีดจำกัดของ container ตัว 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 ไปใช้งาน จะอธิบายรายละเอียดว่าคีย์ใดจะมีผลเหนือกว่าเมื่อมีการตั้งค่าหลายรายการพร้อมกัน
ข้อมูลการทำงานคือสิ่งที่สะสมอยู่เบื้องหลังคุณ
การทำงานหนึ่งครั้งจะเก็บผลลัพธ์ของทุกโหนดไว้ในขณะที่ workflow กำลังประมวลผล และ n8n จะจัดเก็บข้อมูลเหล่านั้นไว้ ซึ่งส่งผลตามมาสองประการ ประการแรก หน่วยความจำสูงสุดที่ใช้ในการทำงานหนึ่งครั้งจะถูกกำหนดโดยชุดข้อมูลที่ใหญ่ที่สุดที่คุณส่งผ่าน workflow ดังนั้น 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 เป็นการตั้งค่าแบบรุก (aggressive) โดยจะเก็บเฉพาะการทำงานที่ล้มเหลวไว้สำหรับการดีบั๊กและทิ้งการทำงานที่สำเร็จไป คุณควรตัดสินใจเลือกใช้การตั้งค่านี้อย่างตั้งใจ เพราะหาก workflow สร้างผลลัพธ์ที่ผิดพลาดโดยไม่เกิด error คุณจะไม่เหลือข้อมูลใดๆ ให้ตรวจสอบ นอกจากนี้ การทำ Pruning จะทำเครื่องหมายแถวว่าถูกลบก่อนแล้วจึงนำออกในรอบถัดไป และ SQLite จะนำหน้า (page) ที่ว่างลงกลับมาใช้ใหม่แทนที่จะคืนพื้นที่ให้ระบบ ดังนั้นขนาดไฟล์บนดิสก์จะไม่ลดลงทันทีที่คุณเปลี่ยนการตั้งค่า
หากต้องการลดการใช้หน่วยความจำสูงสุดแทนที่จะลดปริมาณข้อมูลที่จัดเก็บ ให้ส่งข้อมูลต่อการทำงานหนึ่งครั้งให้น้อยลง โดยแบ่งงานขนาดใหญ่เป็น sub-workflow ที่ส่งผลลัพธ์ขนาดเล็กกลับไปยัง parent workflow, ใช้การแบ่ง batch ด้วยโหนด 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 เพียงอย่างเดียวจะไม่สั่งรีสตาร์ทสิ่งใด 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จะถูกปิดไว้เป็นค่าเริ่มต้น และเมื่อเปิดใช้งาน เวิร์กโฟลว์ที่เกิดข้อผิดพลาดซ้ำๆ จะถูกยกเลิกการเผยแพร่ ซึ่งจะทำให้ดูเหมือนเวิร์กโฟลว์ที่ไม่มีใครเคยเปิดใช้งานมาก่อน
ให้เปิดรายการ executions แล้วกรองข้อมูลตามเวิร์กโฟลว์นั้น หากมีรายการที่ล้มเหลวแสดงว่าปัญหาอยู่ที่ตัวเวิร์กโฟลว์ แต่หากไม่มีรายการใดปรากฏเลย แสดงว่าเป็นปัญหาที่ตัวทริกเกอร์ ซึ่งคุณควรตรวจสอบจาก 4 สาเหตุข้างต้น
สิ่งที่ควรเปลี่ยนเป็นอันดับแรก
- อ่าน
STATUS,RestartCountและOOMKilledบนคอนเทนเนอร์ของคุณเองก่อนเริ่มแก้ไขไฟล์ใดๆ - หากคอนเทนเนอร์ไม่เคยหยุดทำงาน ให้แก้ไข proxy upgrade headers และ idle timeout
- หาก
OOMKilledเป็น true ให้กำหนดขีดจำกัดของคอนเทนเนอร์ที่คุณเลือกไว้อย่างตั้งใจ ตั้งค่า Node heap ceiling ให้ต่ำกว่าขีดจำกัดนั้น และเปลี่ยนข้อมูลไบนารีเป็น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) ออกจากการที่โปรแกรมหยุดทำงานปกติได้อย่างไร?
รันคำสั่ง 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 ถูกเปิดใช้งานอยู่ ตรวจสอบเรื่องนี้ด้วย sudo systemctl is-enabled docker หากต้องการให้จัดการเฉพาะกรณีที่สถานะผิดปกติ คุณต้องมีตัวเฝ้าระวังภายนอก Docker ที่คอยอ่านสถานะและสั่งรีสตาร์ทบริการนั้นๆ