Pernah deploy aplikasi di VPS, buka browser, terus muncul halaman putih bertuliskan "502 Bad Gateway"? Atau lebih parah lagi, loading muter-muter terus akhirnya muncul "504 Gateway Timeout"? Kalau kamu pernah ngalamin ini, tenang - kamu nggak sendirian. Dua error ini adalah masalah paling umum yang dihadapi developer saat bekerja dengan Nginx sebagai reverse proxy.
Saya pribadi pernah stres gara-gara 502 yang muncul setelah update PHP-FPM config. Website tiba-tiba down, client komplain, dan saya panik karena nggak tahu penyebabnya. Ternyata cuma masalah socket path yang berubah. Pengalaman itu yang bikin saya tulis artikel ini - supaya kamu nggak perlu menghabiskan waktu berjam-jam debugging masalah yang sama.
Sebelum masuk ke cara debug, penting untuk paham bedanya dulu. Kedua error ini memang terlihat mirip, tapi penyebabnya berbeda.
502 Bad Gateway terjadi ketika Nginx sebagai reverse proxy menerima response yang nggak valid dari backend server (biasanya PHP-FPM, Node.js, atau Gunicorn). Artinya, backend "mati" atau nggak bisa merespons dengan benar.
504 Gateway Timeout terjadi ketika Nginx menunggu response dari backend terlalu lama sampai melebihi batas waktu yang ditentukan. Backend masih hidup, tapi terlalu lambat merespons.
Bedanya sederhana: 502 = backend mati atau error, 504 = backend lambat. Kedua-duanya bikin website nggak bisa diakses user.
Ada beberapa penyebab utama kenapa 502 muncul. Saya urutkan dari yang paling sering terjadi:
Hal pertama yang harus dilakukan saat muncul 502 atau 504 adalah cek log. Nggak ada yang lebih informatif dari log untuk tahu persis apa yang terjadi.
# Cek error log Nginx
sudo tail -50 /var/log/nginx/error.log
# Cek access log Nginx (lihat status code)
sudo tail -50 /var/log/nginx/access.log | grep -E "502|504"
# Cek log PHP-FPM (tergantung versi PHP)
sudo tail -50 /var/log/php8.3-fpm.log
# Kalau pakai systemd journal
sudo journalctl -u php8.3-fpm --since "10 minutes ago" --no-pager
Di error log Nginx, kamu akan melihat pesan seperti:
# 502 - upstream connection error
connect() failed (111: Connection refused) while connecting to upstream
upstream prematurely closed connection while reading response header
# 504 - timeout
upstream timed out (110: Connection timed out) while reading response header
Pesan ini langsung kasih tahu kamu apakah masalahnya di koneksi ke backend (502) atau timeout (504).
Ini langkah paling dasar tapi sering terlewat. Banyak developer langsung otak-atik config padahal servicenya aja nggak jalan.
# Cek status PHP-FPM
sudo systemctl status php8.3-fpm
# Kalau mati, start
sudo systemctl start php8.3-fpm
# Kalau mau auto-start setelah reboot
sudo systemctl enable php8.3-fpm
# Cek apakah proses PHP-FPM berjalan
ps aux | grep php-fpm
# Cek socket file ada atau nggak
ls -la /run/php/php8.3-fpm.sock
Untuk backend Node.js, cek dengan cara yang sama:
# Cek proses Node.js
pm2 status
# atau
ps aux | grep node
# Restart kalau perlu
pm2 restart all
Ini dia masalah yang pernah bikin saya stres. Nginx dan PHP-FPM harus "ngomong" di channel yang sama. Kalau nggak cocok, ya dapat 502.
Cek konfigurasi PHP-FPM pool:
# Lihat konfigurasi PHP-FPM pool
sudo cat /etc/php/8.3/fpm/pool.d/www.conf | grep -E "listen =|listen.owner|listen.group"
# Output yang diharapkan:
# listen = /run/php/php8.3-fpm.sock
# listen.owner = www-data
# listen.group = www-data
Lalu cek konfigurasi Nginx:
# Cek Nginx config yang mengarah ke PHP-FPM
sudo grep -r "fastcgi_pass" /etc/nginx/sites-enabled/
# Harusnya seperti ini:
# fastcgi_pass unix:/run/php/php8.3-fpm.sock;
# atau
# fastcgi_pass 127.0.0.1:9000;
Pastikan path socket di Nginx SAMA PERSIS dengan yang ada di PHP-FPM config. Satu karakter beda saja bikin 502.
Kalau masalahnya 504, kemungkinan besar Nginx timeout-nya terlalu pendek. Tambahkan atau modifikasi directive berikut di blok server atau location Nginx:
server {
# ... konfigurasi lain ...
# Naikkan proxy timeout
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 120s; # Bisa dinaikkan untuk operasi berat
# Untuk FastCGI (PHP-FPM)
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 120s;
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_read_timeout 300s; # 5 menit untuk script berat
}
}
Di sisi PHP-FPM, pastikan juga request_terminate_timeout nggak terlalu pendek:
# Di /etc/php/8.3/fpm/pool.d/www.conf
request_terminate_timeout = 300s
Kalau kamu mau tahu lebih dalam tentang optimasi Nginx, cek juga tutorial konfigurasi Nginx reverse proxy untuk Node.js yang sudah saya tulis sebelumnya.
Server yang kehabisan resource adalah penyebab silent yang sering nggak disadari. PHP-FPM bisa crash kalau nggak cukup RAM, dan Nginx timeout kalau CPU 100%.
# Cek RAM usage
free -h
# Cek CPU usage
top -bn1 | head -20
# Cek disk space
df -h
# Cek jumlah PHP-FPM worker yang aktif
ps aux | grep php-fpm | wc -l
# Cek limit PHP-FPM di config
cat /etc/php/8.3/fpm/pool.d/www.conf | grep -E "pm.max_children|pm.start_servers"
PHP-FPM dengan pm = dynamic bisa bikin masalah kalau pm.max_children terlalu tinggi untuk RAM yang tersedia. Setiap worker PHP-FPM makan sekitar 20-40MB RAM. Kalau kamu set pm.max_children = 50 tapi cuma punya 1GB RAM, server pasti crash.
Rumus sederhana: pm.max_children = (Total RAM - RAM untuk sistem dan Nginx) / Rata-rata RAM per PHP worker
# Contoh: Server 2GB RAM, sisakan 500MB untuk sistem
# PHP worker rata-rata 30MB
# pm.max_children = (2048 - 500) / 30 = ~50
# Tapi lebih aman set konservatif:
pm.max_children = 25
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
Untuk monitoring server yang lebih detail, kamu bisa baca tutorial monitoring server dengan Netdata yang membahas setup dashboard real-time.
504 Gateway Timeout sering disebabkan oleh query database yang lambat. Kalau satu query butuh 30 detik, user dapat timeout sebelum page ter-load.
# Cek query yang berjalan lama di MySQL
mysql -u root -p -e "SHOW PROCESSLIST;"
# Aktifkan slow query log
mysql -u root -p -e "SET GLOBAL slow_query_log = 'ON';"
mysql -u root -p -e "SET GLOBAL long_query_time = 2;"
mysql -u root -p -e "SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';"
# Cek slow query log
sudo tail -50 /var/log/mysql/slow.log
Kalau ketemu query yang lambat, tambahkan index yang sesuai. Soal MySQL indexing, saya sudah bahas lengkap di tutorial MySQL Indexing - Optimasi Query dari 4 Detik ke 30ms.
Preventif lebih baik daripada debugging. Setup auto-restart supaya backend otomatis recovery kalau crash.
Untuk PHP-FPM, systemd sudah handle ini secara default. Tapi kalau kamu pakai Node.js atau Python backend:
# Pakai PM2 untuk Node.js
pm2 start app.js --name my-app --max-memory-restart 500M
# Atau buat systemd service untuk aplikasi Node.js
sudo tee /etc/systemd/system/my-app.service << 'EOF'
[Unit]
Description=My Node.js App
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/my-app
ExecStart=/usr/bin/node app.js
Restart=always
RestartSec=5
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable my-app
sudo systemctl start my-app
| Gejala | Error Code | Kemungkinan Penyebab | Langkah Cepat |
|---|---|---|---|
| Halaman langsung error | 502 | Backend mati/crash | systemctl status php-fpm |
| Loading lama lalu error | 504 | Backend lambat/timeout | Cek slow query log |
| Error setelah update config | 502 | Socket/port mismatch | Cocokkan fastcgi_pass |
| Error intermittent | 502 | Worker exhaustion | Naikkan pm.max_children |
| Error saat upload file | 504 | Upload timeout | client_max_body_size + timeout |
502 Bad Gateway dan 504 Gateway Timeout memang bikin panik, tapi kalau tahu langkah debuggingnya, masalah ini bisa diselesaikan dalam hitungan menit. Kuncinya adalah: cek log dulu, pastikan service jalan, cocokkan config, dan monitor resource. Nggak perlu langsung restart server atau otak-atik config tanpa tahu masalahnya.
Satu tips terakhir: setup monitoring seperti Netdata atau Uptime Kuma supaya kamu tahu segera kalau server bermasalah, bukan menunggu user yang komplain. Dan kalau kamu sering mengalami timeout pada operasi tertentu, pertimbangkan untuk pakai Redis sebagai caching layer - bisa kurangi beban database secara signifikan.
Punya pengalaman debugging 502 atau 504 yang unik? Share di kolom komentar, siapa bisa bantu developer lain yang mengalami masalah serupa.