n8n Offline di VPS? Bedakan 4 Penyebabnya
n8n tampak offline karena 4 kegagalan berbeda: banner websocket, restart loop, proses Node.js dihentikan karena kehabisan memori, atau jadwal workflow 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 tetap berjalan normal. Container melakukan restart sendiri. Kernel menghentikan proses Node.js karena menggunakan terlalu banyak memori. Atau tidak ada masalah pada proses sama sekali, dan workflow aktif hanya tidak pernah berjalan. Jika Anda mengubah pengaturan yang salah, Anda akan menghabiskan akhir pekan untuk menyelesaikan masalah yang sebenarnya tidak pernah terjadi.
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 dapat mengalami kegagalan dengan caranya sendiri, tetapi browser melaporkan semuanya menggunakan pesan yang sama.
Diagnosis dalam urutan ini
Jalankan perintah berikut pada VPS (virtual private server), lalu baca nilai yang ditampilkan oleh mesin Anda sendiri. Jangan membandingkannya dengan angka dari thread forum. Nilai yang penting 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 nilainya dengan waktu ketika masalah mulai terjadi. Jika container sudah aktif jauh sebelum banner muncul, berarti n8n tidak pernah offline. Yang bermasalah adalah koneksi antara browser dan backend. Jalur websocket ini dibahas pada bagian berikutnya.
RestartCount menunjukkan berapa kali Docker me-restart container ini. Catat angkanya, tunggu satu menit, lalu baca kembali. Jika angkanya terus bertambah saat Anda mengamatinya, berarti terjadi restart loop. Baris log tepat sebelum setiap restart menunjukkan penyebabnya.
OOMKilled adalah flag true atau false. Nilai true berarti kernel Linux menghentikan proses karena penggunaan memorinya melewati batas. Batas tersebut dapat berupa batas container atau batas seluruh mesin. Field ini membedakan penghentian karena kehabisan memori dari jenis exit lainnya. Karena itu, baca field ini sebelum membuat dugaan.
ExitCode menunjukkan kode exit terakhir container Anda. Anda tidak perlu menghafal arti setiap kode. Baca kode milik Anda, lalu baca bagian akhir docker logs dari timestamp yang sama. Tail log dan flag kehabisan memori secara bersamaan dapat menunjukkan apa yang terjadi. Jika dibaca sendiri-sendiri, salah satunya dapat menyesatkan.
docker stats menampilkan penggunaan memori saat ini di samping batas yang berlaku. Biarkan perintah ini berjalan di terminal kedua, jalankan workflow yang menyebabkan masalah, lalu amati perubahan angkanya saat kegagalan terjadi.
Banner koneksi terputus biasanya disebabkan oleh reverse proxy Anda
Editor n8n mempertahankan satu koneksi push jangka panjang ke backend agar dapat mengalirkan progres eksekusi ke canvas. Secara default, koneksi tersebut adalah WebSocket. Koneksi ini dipilih oleh N8N_PUSH_BACKEND, dan nilai defaultnya adalah websocket. WebSocket dimulai sebagai request 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 menyebabkan koneksi ini gagal. Keduanya terjadi pada proxy, bukan pada n8n. Proxy menggunakan HTTP/1.0 ke upstream atau menghapus header upgrade. Akibatnya, proses upgrade tidak pernah terjadi dan editor terus-menerus mencoba menyambung kembali. Atau, proses upgrade berhasil, tetapi proxy kemudian menutup socket karena tidak ada aktivitas. WebSocket tanpa pesan terlihat sama seperti koneksi yang sedang idle. Dalam kedua kasus tersebut, container tetap sehat. Banner tersebut menunjukkan bahwa browser kehilangan kanal koneksinya.
Konfirmasikan hal ini di browser sebelum mengubah apa pun. Buka developer tools, buka tab Network, filter ke WS, lalu muat ulang editor. Request push harus mencapai 101 Switching Protocols dan tetap terbuka. Request push yang mengembalikan kode status biasa, atau yang muncul kembali setiap beberapa detik, menunjukkan masalah pada proxy.
Pengaturan nginx yang menjaga editor tetap terhubung
nginx tidak meneruskan permintaan upgrade kecuali Anda memintanya. Secara default, proxy_pass menggunakan HTTP/1.0 untuk berkomunikasi dengan backend, sedangkan Connection dan Upgrade adalah header hop-by-hop yang dihapus nginx saat meneruskan permintaan. Anda harus menambahkan kembali keduanya. Blok map ditempatkan dalam konteks http, bukan di dalam 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 adalah baris yang sering tidak dicantumkan. Nilai defaultnya adalah 60 detik, dan nilai ini juga berlaku untuk WebSocket yang sudah di-upgrade. Karena itu, tab editor yang dibiarkan terbuka pada instance yang tidak aktif akan kehilangan koneksi sekitar satu menit setelah pesan terakhir melewatinya. Menaikkan nilai ini 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 mencetak seluruh konfigurasi yang sedang berjalan, bukan hanya satu file. Dengan demikian, perintah ini membuktikan bahwa perubahan Anda benar-benar dimuat. Konfigurasi yang berada dalam file yang tidak dibaca oleh baris include adalah alasan perbaikan yang benar tampak tidak berpengaruh.
Selanjutnya, beri tahu n8n bahwa aplikasi tersebut berada di belakang proxy karena n8n membentuk 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/Secara default, N8N_PROXY_HOPS bernilai 0. Artinya, n8n menganggap alamat yang terhubung sebagai alamat klien dan mengabaikan X-Forwarded-For. Tetapkan nilainya sesuai jumlah proxy di depan container. Per Agustus 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, lalu memutusnya 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. Per Agustus 2026 pada Traefik v3, idleTimeout secara default bernilai 180 detik dan readTimeout secara default bernilai 60 detik.
entryPoints:
websecure:
address: ":443"
transport:
respondingTimeouts:
readTimeout: 0
idleTimeout: 3600sCaddy menangani upgrade secara otomatis di reverse_proxy dan tidak memerlukan direktif untuk itu. Jika Anda sama sekali tidak dapat mengubah proxy karena proxy tersebut dikelola pihak lain, alihkan kanal push menggunakan N8N_PUSH_BACKEND=sse. SSE (server-sent events) adalah respons HTTP normal yang dibiarkan tetap terbuka. Karena itu, SSE tetap berjalan pada proxy yang menolak upgrade, meskipun timeout idle yang terlalu agresif tetap dapat memutuskannya. Memilih proxy merupakan keputusan terpisah, dan perbandingan nginx, Caddy, dan Traefik menjelaskan biaya operasional masing-masing.
Saat container benar-benar terus restart
Jika RestartCount terus meningkat, berarti container gagal 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: kesalahan konfigurasi yang menghentikan startup, database yang tidak dapat dijangkau oleh n8n, crash setelah aplikasi berjalan, atau proses yang dihentikan karena kehabisan memori.
Mulai dengan volume karena masalah izin sering tidak terlihat. Official image berjalan sebagai user nonprivileged node dan menyimpan datanya di /home/node/.n8n. Bind mount yang dibuat oleh root tidak dapat ditulisi oleh user tersebut. Akibatnya, proses selalu berhenti saat startup dan restart policy menyamarkan masalah itu dalam sebuah 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 benar. Jika Anda memerlukan bind mount, chown direktori host ke numeric user id yang ditampilkan oleh perintah pertama. Pemetaan ownership antara host dan container perlu dipahami sekali. Penjelasan PUID dan PGID menjelaskan cara image tersebut menentukan user yang dapat menulis file.
Kill karena kehabisan memori yang tampak seperti crash
Ada dua batas memori terpisah yang berlaku pada proses n8n, dan kegagalannya berbeda. Batas control group container diberlakukan oleh kernel. Jika batas ini terlampaui, proses langsung dihentikan tanpa kesempatan menulis apa pun, dan OOMKilled menghasilkan nilai true. Batas heap V8 diberlakukan di dalam Node.js. Jika batas ini terlampaui, Node menampilkan error heap beserta stack trace, lalu berhenti sendiri, sehingga OOMKilled menghasilkan nilai false. Dari browser, kedua kondisi ini 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. Sisakan ruang untuk database, proxy, dan 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 Compose menerapkan batas memori menjelaskan key yang berlaku jika beberapa key ditetapkan.
Data eksekusi adalah hal yang terus bertambah selama proses berjalan
Satu eksekusi menyimpan output dari setiap node selama proses berjalan, lalu n8n menyimpan data tersebut. Ada dua konsekuensinya. Penggunaan memori puncak dari satu proses ditentukan oleh batch data terbesar yang Anda alirkan, sehingga workflow yang memproses sepuluh ribu baris sekaligus merupakan program yang berbeda dari workflow yang sama saat memproses dua ratus baris dalam satu waktu. Salinan yang tersimpan juga terus bertambah sampai sesuatu menghapusnya.
Pruning menangani masalah kedua. Per Agustus 2026, default-nya adalah pruning aktif, EXECUTIONS_DATA_MAX_AGE sebesar 336 jam (14 hari), dan EXECUTIONS_DATA_PRUNE_MAX_COUNT sebesar 10000. Nilai tersebut cukup besar untuk VPS kecil yang menjalankan SQLite. Dalam konfigurasi itu, satu file menyimpan semua data, dan proses yang sama yang menyajikan editor juga harus membaca serta menulis data 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 mempertahankan eksekusi yang gagal untuk keperluan debugging dan membuang eksekusi yang berhasil. Tentukan pilihan ini dengan sengaja. Jika sebuah workflow menghasilkan output yang salah tanpa memunculkan 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, sehingga ukuran file pada disk tidak langsung menyusut setelah Anda mengubah pengaturan.
Untuk mengurangi penggunaan memori puncak, bukan total data yang tersimpan, pindahkan lebih sedikit data dalam setiap proses. Pisahkan pekerjaan besar menjadi sub-workflow yang mengembalikan hasil kecil ke workflow induk, gunakan node Loop Over Items untuk melakukan batching, dan jangan masukkan seluruh dataset ke node Code.
Berkas biner tidak boleh disimpan di memori
N8N_DEFAULT_BINARY_DATA_MODE secara default bernilai default, sehingga data biner tetap berada di memori eksekusi yang sedang berjalan. Setiap file yang diunduh node dan setiap salinan yang diteruskan ke node berikutnya akan tetap berada di sana sampai proses selesai. Satu workflow yang mengambil beberapa lampiran berukuran besar dapat membuat proses melampaui batas yang biasanya tidak tercapai oleh pekerjaan JSON biasa. Karena itu, crash terjadi pada satu workflow tertentu, bukan berdasarkan lamanya proses berjalan.
environment:
- N8N_DEFAULT_BINARY_DATA_MODE=filesystemDengan filesystem, data biner ditulis ke N8N_BINARY_DATA_STORAGE_PATH. Secara default, lokasi ini berada di dalam folder pengguna n8n sehingga menggunakan volume yang sama dengan data lainnya. Pastikan volume tersebut masih memiliki ruang sebelum mengaktifkan pengaturan ini. 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, tetapi juga menambah penggunaan memori yang harus Anda tanggung.
Semua layanan lain yang menggunakan server tersebut akan bersaing memperebutkan 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 sekarang 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 menjalankannya kembali pada kedua kondisi tersebut, tetapi tetap menghormati container yang Anda hentikan secara manual. restart: always juga menjalankan kembali container yang sengaja Anda hentikan setelah Docker dijalankan kembali.
n8n menyediakan endpoint health yang ditentukan oleh N8N_ENDPOINT_HEALTH dan secara default bernilai healthz. Periksa endpoint tersebut dari host terlebih dahulu untuk memastikan path pada instance Anda sudah benar.
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. Karena itu, healthcheck memerlukan kebijakan restart atau watcher eksternal agar memiliki efek. Menulis healthcheck yang benar-benar bertindak dan membuat stack berjalan kembali setelah reboot membahas kedua bagian tersebut.
Workflow yang tidak pernah berjalan saat n8n baik-baik saja
Workflow ini tidak menampilkan banner dan tidak melakukan restart. Container aktif, editor berfungsi, tetapi eksekusi yang Anda harapkan tidak muncul dalam daftar eksekusi. Empat penyebab berikut mencakup sebagian besar kasus.
- Workflow tidak aktif. Schedule Trigger hanya berjalan pada jalur produksi, sehingga pengujian di canvas tidak membuat jadwal apa pun.
- Zona waktunya bukan zona waktu Anda.
GENERIC_TIMEZONEsecara default menggunakanAmerica/New_York, sehingga jadwal yang diatur untuk 09:00 berjalan pada 09:00 di zona tersebut sampai Anda mengaturGENERIC_TIMEZONEdanTZke zona waktu Anda sendiri. - Waktu henti tidak dijalankan setelah layanan kembali aktif. Trigger didaftarkan saat n8n dimulai, sehingga jadwal yang jatuh tempo ketika container sedang restart tidak dijalankan terlambat. Eksekusi berikutnya terjadi pada waktu jadwal berikutnya setelah startup.
- Workflow dinonaktifkan secara otomatis.
N8N_WORKFLOW_AUTODEACTIVATION_ENABLEDsecara default dalam keadaan nonaktif. Jika opsi ini aktif, workflow yang terus mengalami crash akan di-unpublish. Setelah itu, workflow tersebut terlihat sama seperti workflow yang belum pernah diaktifkan.
Buka daftar eksekusi, lalu filter berdasarkan workflow tersebut. Entri yang gagal menunjukkan masalah pada workflow. Jika tidak ada entri sama sekali, masalahnya ada pada trigger. Periksa empat penyebab di atas.
Hal yang harus diubah terlebih dahulu
- Baca
STATUS,RestartCount, danOOMKilledpada container Anda sendiri sebelum mengedit file apa pun. - Jika container tidak pernah berhenti, perbaiki header upgrade proxy dan batas waktu idle.
- Jika
OOMKilledbernilai benar, 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 dikonfigurasi sekali dan kemudian dibiarkan, asalkan instalasi sudah berfungsi. Jika instalasi tersebut masih Anda susun, panduan n8n pada Docker dengan HTTPS adalah dasar untuk pengaturan ini.
FAQ
Mengapa editor n8n menampilkan banner koneksi terputus saat container berjalan?
Editor mempertahankan koneksi WebSocket 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 terhubung kembali sementara n8n tetap berjalan normal. Pada nginx, Anda memerlukan proxy_http_version 1.1 serta kedua baris proxy_set_header, dan proxy_read_timeout yang lebih lama dari 60 detik sebagai nilai default 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 akan 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 berhenti. Tetapkan 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, kemudian proses berikutnya menghapusnya 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. Tetapkan EXECUTIONS_DATA_MAX_AGE dan EXECUTIONS_DATA_PRUNE_MAX_COUNT sesuai kapasitas server Anda, lalu periksa kembali keesokan harinya, bukan langsung.
Mengapa workflow terjadwal saya tidak berjalan saat n8n sedang restart?
n8n mendaftarkan trigger saat proses dimulai. n8n tidak menjalankan kembali jadwal yang seharusnya berjalan saat proses sedang berhenti. Karena itu, loop restart menghasilkan tidak ada eksekusi, bukan serangkaian eksekusi susulan. Eksekusi berikutnya dijadwalkan pada waktu berikutnya setelah startup. Jika eksekusi tidak boleh terlewat, jalankan workflow dari pemanggil eksternal melalui webhook. Dengan demikian, logika retry berada di luar n8n.
Apakah healthcheck akan merestart n8n saat n8n berhenti merespons?
Tidak secara otomatis. 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 berhenti, dan juga menghidupkannya kembali setelah host reboot selama service Docker diaktifkan. Konfirmasikan hal tersebut dengan sudo systemctl is-enabled docker. Untuk mengambil tindakan khusus saat container berstatus tidak sehat, Anda memerlukan watcher di luar Docker yang membaca status lalu merestart service.