n8n Terus Offline di VPS: 4 Penyebab dan Cara Cek
Kenali empat penyebab n8n tampak offline: banner websocket, restart loop, proses Node.js dihentikan karena kehabisan memori, atau jadwal workflow yang mati.
Mengapa n8n terus offline: empat kegagalan, satu gejala
“n8n terus offline” adalah satu kalimat yang mencakup empat kegagalan berbeda, dan masing-masing memerlukan perbaikan yang berbeda. Editor menampilkan banner koneksi terputus, sementara container berjalan normal. Container melakukan restart sendiri. Kernel menghentikan proses Node.js karena menggunakan terlalu banyak memori. Atau tidak ada masalah pada proses sama sekali, tetapi workflow yang aktif tidak pernah berjalan. Jika Anda mengubah pengaturan yang salah, Anda dapat menghabiskan satu akhir pekan untuk menangani masalah yang sebenarnya tidak ada.
Jadi, tentukan jenis kegagalan yang terjadi sebelum mengubah konfigurasi apa pun. n8n berjalan sebagai satu proses Node.js, biasanya di dalam satu container Docker, di belakang reverse proxy yang melakukan terminasi TLS (transport layer security). Setiap lapisan tersebut dapat mengalami kegagalan dengan caranya sendiri, tetapi browser melaporkan semuanya dengan pesan yang sama.
Diagnosis dengan urutan ini
Jalankan perintah berikut pada VPS (virtual private server), lalu baca nilai yang ditampilkan oleh mesin Anda sendiri. Jangan membandingkannya dengan angka dari utas forum. Nilai yang relevan di sini menggambarkan server Anda, bukan server orang lain.
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-streamKolom STATUS dari docker ps -a menunjukkan sudah berapa lama container berada dalam statusnya saat ini. Bandingkan waktunya dengan saat masalah mulai terjadi. Jika container sudah aktif sejak jauh sebelum banner muncul, berarti n8n tidak pernah offline. Yang rusak adalah koneksi antara browser dan backend, yaitu jalur websocket yang dibahas di bagian berikutnya.
RestartCount menunjukkan berapa kali Docker me-restart container ini. Catat angkanya, tunggu satu menit, lalu baca kembali. Jika angkanya terus naik saat Anda mengamatinya, berarti terjadi restart loop. Baris log tepat sebelum setiap restart menunjukkan penyebabnya.
OOMKilled adalah flag true atau false. True berarti kernel Linux mematikan proses karena proses tersebut melewati batas memori, baik batas milik container maupun batas seluruh mesin. Field ini membedakan penghentian karena kehabisan memori dari jenis penghentian lainnya. Karena itu, baca field ini sebelum membuat dugaan.
ExitCode menunjukkan kode terakhir yang digunakan container saat keluar. Anda tidak perlu menghafalkan arti setiap kode. Baca kode pada sistem Anda, lalu baca bagian akhir docker logs dari timestamp yang sama. Tail log dan flag out of memory secara bersama-sama menunjukkan apa yang terjadi. Jika digunakan sendiri, salah satunya dapat menyesatkan.
docker stats menampilkan penggunaan memori secara langsung di samping limit yang berlaku. Biarkan perintah ini tetap berjalan di terminal kedua, jalankan workflow yang menyebabkan masalah, lalu amati perubahan nilainya saat kegagalan terjadi.
Banner “connection lost” biasanya disebabkan oleh reverse proxy Anda
Editor n8n mempertahankan satu koneksi push yang terbuka dalam waktu lama ke backend agar dapat mengirimkan progres eksekusi ke canvas. Secara default, koneksi tersebut adalah WebSocket. Inilah yang dipilih oleh N8N_PUSH_BACKEND, dan nilai defaultnya adalah websocket. WebSocket dimulai sebagai permintaan HTTP biasa yang membawa header Connection: Upgrade dan Upgrade: websocket. Server merespons dengan 101 Switching Protocols. Setelah itu, kedua sisi menggunakan socket TCP yang sama untuk komunikasi dua arah.
Ada dua hal yang dapat mengganggu proses tersebut. Keduanya terjadi pada proxy, bukan pada n8n. Proxy menggunakan HTTP/1.0 ke upstream atau menghapus header upgrade. Akibatnya, upgrade tidak pernah terjadi dan editor terus mencoba menyambung kembali. Atau, upgrade berhasil, tetapi proxy kemudian menutup socket karena tidak ada aktivitas. WebSocket yang tidak membawa pesan terlihat sama seperti koneksi yang tidak aktif. Dalam kedua kasus tersebut, container tetap sehat. Banner itu menunjukkan bahwa browser kehilangan kanal komunikasinya.
Konfirmasikan hal ini melalui browser sebelum mengubah apa pun. Buka developer tools, pilih tab Network, filter ke WS, lalu muat ulang editor. Permintaan push harus mencapai 101 Switching Protocols dan tetap terbuka. Jika permintaan push mengembalikan kode status biasa atau muncul kembali setiap beberapa detik, masalahnya kemungkinan berada pada proxy.
Pengaturan nginx yang menjaga koneksi editor
nginx tidak meneruskan upgrade kecuali Anda memintanya. Connection dan Upgrade adalah header hop-by-hop yang dihapus nginx saat meneruskan permintaan, sehingga Anda harus menambahkan kembali keduanya. Protokol upstream bergantung pada rilis nginx yang Anda gunakan: sejak 1.29.7 (Maret 2026), proxy_pass menggunakan HTTP/1.1 ke backend secara default, sedangkan sebelumnya nginx menggunakan HTTP/1.0, yang sama sekali tidak dapat membawa upgrade. Jalankan nginx -v untuk melihat versi yang Anda gunakan. Konfigurasi di bawah ini mempertahankan proxy_http_version 1.1 secara eksplisit agar berfungsi pada kedua versi. Pada versi 1.29.7 atau yang lebih baru, baris tersebut hanya menegaskan kembali nilai default. Blok map harus ditempatkan dalam konteks http, bukan di dalam server. Jika bagian lain dari server block di bawah ini belum familiar, panduan baris demi baris tentang server block nginx menjelaskan fungsi setiap direktif.
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 adalah baris yang sering terlewat. Nilai defaultnya adalah 60 detik dan berlaku juga untuk WebSocket yang telah di-upgrade. Akibatnya, tab editor yang dibiarkan terbuka pada instance yang tidak aktif akan kehilangan koneksi sekitar satu menit setelah pesan terakhir melewatinya. Menaikkan nilai ini akan memperbaiki banner yang muncul saat Anda kembali ke tab yang dibiarkan terbuka.
sudo nginx -t && sudo systemctl reload nginx
sudo nginx -T | grep -iE 'proxy_http_version|upgrade|proxy_read_timeout'nginx -T menampilkan seluruh konfigurasi yang sedang berjalan, bukan hanya satu file. Dengan demikian, perintah ini membuktikan bahwa perubahan Anda benar-benar dimuat. Konfigurasi yang tersimpan dalam file yang tidak dibaca oleh baris include menyebabkan perbaikan yang benar tampak tidak berpengaruh.
Selanjutnya, beri tahu n8n bahwa layanan tersebut berada di belakang proxy karena n8n membangun URL berdasarkan nilai-nilai ini.
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 memiliki nilai default 0. Artinya, n8n menganggap alamat yang terhubung sebagai alamat client dan mengabaikan X-Forwarded-For. Atur nilainya ke jumlah proxy di depan container. Per Oktober 2026, N8N_WEBHOOK_URL adalah nama yang digunakan saat ini, sedangkan WEBHOOK_URL yang lebih lama masih berfungsi, tetapi menampilkan peringatan deprecation saat startup.
Traefik meneruskan WebSocket, tetapi kemudian mengakhirinya karena timeout
Traefik meneruskan upgrade WebSocket tanpa middleware dan tanpa label tambahan. Karena itu, pengguna Traefik yang melihat banner ini biasanya mengalami timeout, bukan header yang hilang. Pengaturannya berada pada entryPoint. Pada Oktober 2026 di Traefik v3, idleTimeout secara default bernilai 180 seconds dan readTimeout secara default bernilai 60 seconds.
entryPoints:
websecure:
address: ":443"
transport:
respondingTimeouts:
readTimeout: 0
idleTimeout: 3600sCaddy menangani upgrade secara otomatis dalam reverse_proxy dan tidak memerlukan directive untuk itu. Jika Anda sama sekali tidak dapat mengubah proxy karena proxy tersebut dikelola pihak lain, alihkan push channel menggunakan N8N_PUSH_BACKEND=sse. SSE (server-sent events) adalah respons HTTP biasa yang dibiarkan terbuka. Karena itu, SSE tetap berfungsi pada proxy yang menolak upgrade, meskipun idle timeout yang terlalu agresif tetap dapat memutuskannya. Memilih proxy merupakan keputusan terpisah. perbandingan nginx, Caddy, dan Traefik menjelaskan biaya operasional masing-masing.
Saat container terus-menerus restart
Jika RestartCount meningkat, container mengalami kegagalan dan Docker menjalankannya kembali. Cocokkan timestamp log dengan setiap restart, lalu baca pesan yang muncul tepat sebelumnya. Hampir semua kasus disebabkan oleh salah satu dari empat hal: error konfigurasi yang menghentikan startup, database yang tidak dapat dijangkau n8n, crash setelah aplikasi berjalan, atau proses yang dihentikan karena kekurangan memori.
Mulailah dari volume, karena masalah izin sering tidak terlihat. Official image berjalan sebagai pengguna tanpa hak istimewa node dan menyimpan datanya di /home/node/.n8n. Bind mount yang dibuat oleh root tidak dapat ditulisi oleh pengguna tersebut. Akibatnya, proses selalu berhenti saat startup, sementara restart policy menyembunyikan masalah itu dalam loop.
docker compose config
docker run --rm -it --entrypoint sh docker.n8n.io/n8nio/n8n -c 'id'
docker exec n8n ls -ld /home/node/.n8nNamed volume menghindari masalah ini sepenuhnya karena Docker membuatnya dengan ownership yang sesuai. Jika Anda memerlukan bind mount, chown direktori pada host ke numeric user id yang ditampilkan oleh perintah pertama. Pemetaan ownership antara host dan container perlu dipahami sekali, dan penjelasan PUID dan PGID membahas cara image tersebut menentukan pengguna yang menulis file.
Kematian akibat kehabisan memori yang tampak seperti crash
Ada dua batas memori terpisah di atas proses n8n, dan keduanya gagal dengan cara berbeda. Batas control group container diberlakukan oleh kernel: jika terlampaui, proses langsung dihentikan tanpa kesempatan untuk menulis apa pun, dan OOMKilled menghasilkan nilai true. Batas heap V8 diberlakukan di dalam Node.js: jika terlampaui, Node menampilkan error heap beserta stack trace lalu keluar sendiri, sehingga OOMKilled menghasilkan nilai false. Dari browser, keduanya tampak sama. Dari docker inspect, keduanya hanya berbeda satu field.
Tetapkan batas heap Node di bawah batas container. Jika batas heap lebih tinggi daripada batas container, V8 terus mengalokasikan memori melewati titik ketika kernel bertindak. Akibatnya, garbage collector tidak pernah mencapai batasnya sendiri, dan Anda selalu mendapatkan kegagalan yang lebih parah tanpa log yang dapat dibaca.
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>Tentukan kedua angka berdasarkan kapasitas VPS Anda, dan sisakan ruang untuk database, proxy, serta sistem operasi. docker stats --no-stream menampilkan penggunaan saat ini di samping batas yang berlaku, sehingga Anda dapat memastikan bahwa batas yang ditulis adalah batas yang diterapkan Docker. Cara penerapan batas memori Compose menjelaskan key yang berlaku jika beberapa key ditetapkan.
Data eksekusi adalah sumber pertumbuhan penggunaan ruang
Satu eksekusi menyimpan output dari setiap node selama proses berjalan, lalu n8n menyimpan data tersebut. Ada dua konsekuensi. Penggunaan memori puncak dalam satu eksekusi ditentukan oleh batch data terbesar yang diproses. Jadi, workflow yang menangani sepuluh ribu baris sekaligus berbeda dari workflow yang sama ketika menangani dua ratus baris setiap kali. Salinan yang disimpan juga terus bertambah sampai dihapus.
Pruning menangani masalah kedua. Per Oktober 2026, konfigurasi default mengaktifkan pruning, dengan EXECUTIONS_DATA_MAX_AGE pada 336 jam (14 hari) dan EXECUTIONS_DATA_PRUNE_MAX_COUNT pada 10000. Nilai tersebut cukup besar untuk VPS kecil yang menjalankan SQLite. Dalam konfigurasi ini, satu file menyimpan semua data, dan proses yang melayani editor juga harus membaca serta menulis file tersebut.
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 adalah pengaturan agresif. Pengaturan ini menyimpan eksekusi yang gagal untuk debugging dan membuang eksekusi yang berhasil. Tentukan pilihan ini dengan sengaja. Jika workflow menghasilkan output yang salah tanpa menimbulkan error, Anda tidak akan memiliki data untuk diperiksa. Pruning juga terlebih dahulu menandai baris sebagai terhapus, lalu menghapusnya pada proses berikutnya. SQLite menggunakan kembali halaman yang telah dibebaskan, bukan mengembalikannya ke sistem operasi. Karena itu, ukuran file di disk tidak langsung mengecil setelah pengaturan diubah.
Untuk mengurangi penggunaan memori puncak, bukan total data yang disimpan, kurangi jumlah data dalam setiap eksekusi. Pecah pekerjaan besar menjadi sub-workflow yang mengembalikan hasil kecil ke workflow induk, gunakan batching dengan node Loop Over Items, dan jangan memasukkan seluruh dataset ke dalam node Code.
File biner sebaiknya tidak melewati memori
N8N_DEFAULT_BINARY_DATA_MODE secara default bernilai default, yang menyimpan data biner dalam memori eksekusi yang sedang berjalan. Setiap file yang diunduh sebuah node, serta setiap salinan yang diteruskan ke node berikutnya, tetap berada di sana sampai proses selesai. Satu workflow yang mengambil beberapa lampiran besar dapat membuat proses melewati batas yang tidak pernah tercapai oleh operasi JSON biasa. Karena itu, crash terjadi pada workflow tertentu, bukan berdasarkan lamanya waktu.
environment:
- N8N_DEFAULT_BINARY_DATA_MODE=filesystemDengan filesystem, data biner ditulis ke N8N_BINARY_DATA_STORAGE_PATH, yang secara default berada di dalam folder pengguna n8n sehingga menggunakan volume yang sama dengan komponen lainnya. Pastikan volume tersebut memiliki ruang yang cukup sebelum mengaktifkannya. N8N_PAYLOAD_SIZE_MAX menetapkan ukuran maksimum payload webhook masuk dalam MiB (mebibyte) dan secara default bernilai 16. Menaikkan nilai ini memungkinkan request yang lebih besar diterima, tetapi menambah penggunaan memori yang harus Anda tanggung.
Komponen lain yang menggunakan server tersebut juga bersaing untuk mendapatkan RAM yang sama. Jika proses OOM kill mulai terjadi setelah Anda menambahkan container database, menjalankan database di Docker atau pada host adalah trade-off yang harus Anda pilih.
Kebijakan restart dan pemulihan setelah reboot
Container tanpa kebijakan restart tetap berhenti setelah keluar, termasuk setelah host melakukan reboot. restart: unless-stopped akan menjalankannya kembali dalam kedua kondisi tersebut, tetapi tetap menghormati container yang Anda hentikan secara manual. restart: always juga akan menjalankan kembali container yang sengaja Anda hentikan setelah Docker dijalankan kembali.
n8n menyediakan endpoint health bernama N8N_ENDPOINT_HEALTH, yang secara default adalah healthz. Periksa endpoint tersebut dari host terlebih dahulu untuk memastikan path-nya benar pada instance Anda.
curl -fsS http://127.0.0.1:5678/healthz
docker exec n8n which wget curl
sudo systemctl is-enabled dockerHealthcheck saja tidak akan me-restart apa pun. Compose menandai container sebagai tidak sehat lalu berhenti pada tahap itu. Agar healthcheck memberikan efek, container memerlukan kebijakan restart atau watcher eksternal yang berjalan bersamanya. Menulis healthcheck yang benar-benar bertindak dan membuat stack berjalan kembali setelah reboot membahas kedua bagian tersebut.
Alur kerja yang tidak pernah berjalan meskipun n8n normal
Alur kerja ini tidak menampilkan banner dan tidak melakukan restart. Container aktif, editor dapat digunakan, tetapi eksekusi yang Anda harapkan tidak muncul dalam daftar eksekusi. Empat penyebab berikut mencakup sebagian besar kasus.
- Alur kerja tidak aktif. Schedule Trigger hanya berjalan pada jalur produksi, sehingga pengujian di canvas tidak membuat jadwal apa pun.
- Zona waktu bukan zona waktu Anda.
GENERIC_TIMEZONEsecara default menggunakanAmerica/New_York, sehingga jadwal yang ditetapkan untuk 09:00 berjalan pada pukul 09:00 di zona tersebut sampai Anda menetapkanGENERIC_TIMEZONEdanTZke zona waktu Anda sendiri. - Waktu henti tidak digantikan setelah layanan kembali aktif. Trigger didaftarkan saat n8n dimulai, sehingga jadwal yang seharusnya berjalan ketika container sedang restart tidak akan dijalankan terlambat. Eksekusi berikutnya berlangsung pada waktu jadwal berikutnya setelah startup.
- Alur kerja dinonaktifkan secara otomatis.
N8N_WORKFLOW_AUTODEACTIVATION_ENABLEDsecara default nonaktif. Jika opsi tersebut diaktifkan, alur kerja yang terus mengalami crash akan dibatalkan publikasinya. Setelah itu, kondisinya terlihat sama seperti alur kerja yang tidak pernah diaktifkan.
Buka daftar eksekusi, lalu filter berdasarkan alur kerja tersebut. Entri yang gagal menunjukkan masalah pada alur kerja. Jika kegagalan tersebut berisi kode 429 dari service lain yang Anda host pada server yang sama, batas tersebut berasal dari service itu, bukan dari n8n. Panduan 429 SearXNG menjelaskan cara membedakan rate limiter milik service tersebut dari engine yang memblokir alamat IP server Anda. Jika tidak ada entri sama sekali, masalahnya ada pada trigger. Periksa empat penyebab di atas.
Perubahan yang harus dilakukan terlebih dahulu
- Baca
STATUS,RestartCount, danOOMKilledpada container Anda sendiri sebelum mengedit file apa pun. - Jika container tidak pernah berhenti, perbaiki header upgrade proxy dan timeout idle.
- Jika
OOMKilledbernilai true, tetapkan batas container secara sengaja, atur batas atas heap Node di bawah batas tersebut, lalu alihkan data biner kefilesystem. - Jika tidak ada yang terpicu, periksa apakah workflow aktif dan apakah zona waktu instance sesuai dengan zona waktu Anda.
Sebagian besar pengaturan ini cukup ditetapkan sekali dan kemudian dibiarkan, selama instalasi dasar sudah berfungsi. Jika Anda masih menyiapkan instalasi tersebut, panduan n8n di Docker dengan HTTPS adalah dasar untuk menerapkan pengaturan ini.
FAQ
Mengapa editor n8n menampilkan banner koneksi terputus saat container sedang berjalan?
Editor mempertahankan koneksi WebSocket terbuka untuk mengalirkan progres eksekusi. Jika reverse proxy Anda tidak meneruskan header Connection: Upgrade dan Upgrade: websocket, atau tidak menggunakan HTTP/1.1 ke upstream, proses upgrade tidak pernah selesai. Akibatnya, browser terus mencoba menghubungkan kembali, sementara n8n tetap berjalan normal. Pada nginx, Anda memerlukan kedua baris proxy_set_header, proxy_http_version 1.1 pada rilis sebelum 1.29.7 (rilis yang lebih baru menggunakan HTTP/1.1 secara default), serta proxy_read_timeout yang lebih panjang dari default 60 detik agar tab yang tidak aktif tidak terputus. Periksa konfigurasi yang sedang berjalan dengan sudo nginx -T, bukan file yang Anda edit.
Bagaimana membedakan penghentian karena kehabisan memori dari crash biasa?
Jalankan docker inspect n8n | grep -iE 'OOMKilled|ExitCode|RestartCount' dan baca flag OOMKilled. Nilai True berarti kernel menghentikan proses karena melewati batas memori. Tidak ada informasi yang berguna di log container karena proses tidak sempat menulisnya. Nilai False, disertai error heap dan stack trace di akhir docker logs, berarti Node.js mencapai batas heap V8 sendiri lalu keluar. Atur NODE_OPTIONS=--max-old-space-size di bawah batas container agar Anda mendapatkan kegagalan kedua. Kegagalan ini meninggalkan bukti.
Apakah pruning data eksekusi langsung membebaskan ruang disk?
Tidak. EXECUTIONS_DATA_PRUNE menandai eksekusi lama untuk dihapus. Penghapusan dilakukan pada proses berikutnya, sesuai jadwal yang ditetapkan oleh EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL. Pada SQLite, file juga menggunakan kembali halaman yang sudah dibebaskan, bukan mengembalikannya ke filesystem. Karena itu, ukuran file di disk tetap sama untuk sementara setelah baris dihapus. Atur EXECUTIONS_DATA_MAX_AGE dan EXECUTIONS_DATA_PRUNE_MAX_COUNT sesuai kondisi server Anda. Periksa kembali keesokan harinya, bukan langsung.
Mengapa workflow terjadwal saya tidak berjalan saat n8n sedang melakukan restart?
n8n mendaftarkan trigger saat proses dimulai. n8n tidak menjalankan kembali jadwal yang jatuh tempo saat proses berhenti. Karena itu, loop restart menghasilkan keheningan, bukan serangkaian eksekusi susulan. Eksekusi berikutnya berlangsung pada waktu jatuh tempo berikutnya setelah startup. Jika eksekusi tidak boleh terlewat, jalankan workflow dari caller eksternal yang mengakses webhook. Dengan demikian, logika retry berada di luar n8n.
Apakah healthcheck akan me-restart n8n saat n8n berhenti merespons?
Tidak dengan sendirinya. Healthcheck Compose hanya menandai container sebagai sehat atau tidak sehat. Restart ditangani oleh restart policy. Karena itu, restart: unless-stopped menghidupkan kembali container setelah proses keluar. Kebijakan ini juga menghidupkan kembali container setelah host reboot, selama service Docker diaktifkan. Konfirmasikan hal tersebut dengan sudo systemctl is-enabled docker. Untuk mengambil tindakan khusus saat status container tidak sehat, Anda memerlukan watcher di luar Docker yang membaca status lalu me-restart service.