ALB Mengembalikan 502 Bad Gateway: Panduan Diagnosa Lengkap Saat Instance Healthy
Situasi ini muncul lebih sering dari yang seharusnya: ALB melaporkan 502 Bad Gateway, tapi target group menunjukkan semua instance berstatus Healthy. Health check lolos, tapi request nyata gagal. Ini bukan kontradiksi — ini sinyal bahwa masalah bukan di ketersediaan instance, melainkan di level respons HTTP atau protokol koneksi antara ALB dan aplikasi.
TL;DR: Penyebab Umum 502 di ALB
| Penyebab | Lapisan | Sinyal Utama |
|---|---|---|
| Respons HTTP tidak valid dari aplikasi | Aplikasi | Access log ALB: 502, target_status_code kosong atau - |
| Koneksi ditutup prematur oleh target | Transport | target_status_code: -, error_reason: Target.ResponseHeaderTimeout |
| Mismatch protokol (HTTP vs HTTPS di target group) | Protokol | SSL handshake error di log aplikasi |
| Keep-alive timeout tidak selaras | Koneksi | 502 intermiten, tidak konsisten di semua request |
| Response header terlalu besar | HTTP | 502 konsisten untuk endpoint tertentu |
| Target group protocol mismatch | Konfigurasi | 502 sejak deployment atau perubahan konfigurasi |
Cara ALB Memproses Request dan Menghasilkan 502
Sebelum mendiagnosa, penting memahami di mana 502 bisa lahir. ALB bertindak sebagai reverse proxy — ia menerima koneksi dari client, membuka koneksi baru ke target, lalu meneruskan respons. Jika target mengembalikan respons yang tidak bisa diparsing sebagai HTTP valid, atau koneksi ke target gagal setelah request dikirim, ALB menghasilkan 502 sendiri. Health check menggunakan path dan interval terpisah, jadi instance bisa lolos health check tapi tetap gagal melayani request produksi.
- Client → ALB: Koneksi HTTPS diterima, TLS di-terminate di ALB.
- ALB → Target: ALB membuka koneksi baru ke instance menggunakan protokol yang dikonfigurasi di target group (HTTP atau HTTPS).
- Target → ALB: Jika respons tidak valid, timeout, atau koneksi putus — ALB menghasilkan 502 ke client.
- Health Check: Berjalan independen dengan path dan interval sendiri. Tidak mewakili perilaku request produksi.
Langkah 1: Baca Access Log ALB — Ini Sumber Kebenaran Pertama
Sebelum menyentuh instance, aktifkan dan baca access log ALB. Log ini mencatat target_status_code dan error_reason per request — dua field yang langsung membedakan apakah masalah ada di sisi ALB atau target. Tanpa log ini, semua diagnosa berikutnya hanya tebakan.
Aktifkan access log jika belum aktif:
aws elbv2 modify-load-balancer-attributes \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/1234567890abcdef \
--attributes Key=access_logs.s3.enabled,Value=true \
Key=access_logs.s3.bucket,Value=my-alb-logs-bucket \
Key=access_logs.s3.prefix,Value=my-alb
Setelah log tersedia, query dengan Amazon Athena atau unduh dan grep secara lokal. Field kritis yang perlu diperhatikan:
# Format field penting di access log ALB:
# type timestamp elb client:port target:port request_processing_time
# target_processing_time response_processing_time elb_status_code
# target_status_code ... error_reason
# Cari semua baris dengan status 502
grep ' 502 ' access_log.log | awk '{print $14, $15, $NF}'
# Output: elb_status_code target_status_code error_reason
Interpretasi hasil:
target_status_code: -→ ALB tidak menerima respons valid dari target. Masalah ada di koneksi atau aplikasi crash sebelum menulis respons.target_status_code: 200tapielb_status_code: 502→ Jarang, tapi bisa terjadi jika respons corrupt setelah header dikirim.error_reason: Target.ResponseHeaderTimeout→ Target terlalu lama mengirim header respons.error_reason: Target.ConnectionError→ Koneksi ke target gagal atau ditutup paksa.
Langkah 2: Verifikasi Konfigurasi Protokol Target Group
Ini penyebab yang paling sering terlewat karena tidak ada error eksplisit di console. Jika target group dikonfigurasi dengan protokol HTTPS tapi aplikasi hanya mendengarkan HTTP (atau sebaliknya), ALB akan gagal melakukan handshake dan menghasilkan 502. Health check bisa tetap lolos jika health check dikonfigurasi dengan protokol yang berbeda dari traffic produksi.
aws elbv2 describe-target-groups \
--target-group-arns arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/my-tg/1234567890abcdef \
--query 'TargetGroups[*].{Protocol:Protocol,Port:Port,HealthCheckProtocol:HealthCheckProtocol,HealthCheckPort:HealthCheckPort}'
Bandingkan output dengan port yang benar-benar didengarkan aplikasi di instance:
# Jalankan di instance target via SSM Session Manager
ss -tlnp | grep LISTEN
Jika protokol target group adalah HTTPS, ALB akan mencoba TLS handshake ke instance. Pastikan aplikasi memang mendengarkan dengan TLS di port tersebut, bukan plain HTTP.
Langkah 3: Periksa Keep-Alive Timeout — Penyebab 502 Intermiten yang Paling Sering Salah Didiagnosa
502 yang muncul tidak konsisten — kadang berhasil, kadang gagal, tanpa pola jelas — hampir selalu mengarah ke masalah keep-alive timeout. ALB mempertahankan koneksi persistent ke target untuk efisiensi. Jika aplikasi menutup koneksi keep-alive lebih cepat dari yang ALB harapkan, ALB bisa mencoba menggunakan koneksi yang sudah ditutup oleh aplikasi, menghasilkan 502.
Bayangkan ALB seperti kasir yang menyimpan antrian koneksi terbuka ke dapur. Jika dapur menutup jendela lebih cepat dari yang kasir tahu, pesanan berikutnya jatuh ke lantai.
ALB idle timeout default adalah 60 detik. Nilai ini bisa diubah, dan harus lebih kecil dari idle timeout keep-alive di sisi aplikasi. Periksa konfigurasi saat ini:
aws elbv2 describe-load-balancer-attributes \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/1234567890abcdef \
--query 'Attributes[?Key==`idle_timeout.timeout_seconds`]'
Aturan praktisnya: idle timeout keep-alive di aplikasi harus lebih besar dari idle timeout ALB. Jika menggunakan Nginx, periksa keepalive_timeout. Jika menggunakan Node.js HTTP server, periksa server.keepAliveTimeout. Jika menggunakan Gunicorn atau uWSGI, pastikan keep-alive diaktifkan dan timeout dikonfigurasi lebih tinggi dari ALB.
Untuk menyesuaikan idle timeout ALB (misalnya turunkan ke 30 detik jika aplikasi menutup koneksi di 45 detik):
aws elbv2 modify-load-balancer-attributes \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/1234567890abcdef \
--attributes Key=idle_timeout.timeout_seconds,Value=30
Langkah 4: Validasi Respons HTTP dari Aplikasi
ALB membutuhkan respons HTTP yang valid — status line yang benar, header yang parseable, dan tidak ada karakter ilegal. Aplikasi yang mengembalikan respons malformed (misalnya header dengan karakter non-ASCII, status line yang tidak standar, atau body yang dikirim sebelum header selesai) akan menyebabkan ALB menghasilkan 502 meski instance berstatus Healthy.
Uji respons langsung dari instance, bypass ALB sepenuhnya:
# Jalankan dari instance lain di VPC yang sama, atau via SSM
curl -v --max-time 10 http://<instance-private-ip>:<port>/<path> 2>&1 | head -50
Perhatikan output verbose curl. Jika ada anomali di response header — karakter aneh, header duplikat, atau koneksi yang ditutup sebelum body selesai — itu konfirmasi masalah ada di aplikasi, bukan di ALB atau jaringan.
Untuk endpoint yang menghasilkan 502 secara konsisten, bandingkan dengan endpoint yang berhasil. Jika hanya endpoint tertentu yang gagal, periksa apakah endpoint tersebut menghasilkan response header yang lebih besar atau memiliki logika yang berbeda.
Langkah 5: Periksa Security Group dan Konektivitas Jaringan
Meski instance berstatus Healthy di target group, ada skenario di mana koneksi ke port tertentu bisa diblokir. Health check menggunakan port dan path yang dikonfigurasi — jika health check port berbeda dari traffic port, instance bisa Healthy tapi traffic produksi tetap diblokir.
# Verifikasi security group yang attached ke instance target
aws ec2 describe-instances \
--instance-ids i-1234567890abcdef0 \
--query 'Reservations[*].Instances[*].SecurityGroups'
# Verifikasi inbound rules security group tersebut
aws ec2 describe-security-groups \
--group-ids sg-1234567890abcdef0 \
--query 'SecurityGroups[*].IpPermissions'
Security group instance harus mengizinkan inbound traffic dari security group ALB pada port aplikasi. Jika menggunakan referensi security group (bukan CIDR), pastikan referensinya ke security group ALB yang benar, bukan security group lain.
Langkah 6: Periksa Log Aplikasi di Instance Target
Setelah access log ALB mengkonfirmasi bahwa target_status_code adalah - (tidak ada respons), langkah selanjutnya adalah melihat apa yang terjadi di sisi aplikasi. Crash, OOM kill, atau exception yang tidak tertangani bisa menyebabkan koneksi ditutup tanpa mengirim respons HTTP apapun.
# Akses instance via SSM Session Manager (tidak perlu SSH/bastion)
aws ssm start-session \
--target i-1234567890abcdef0 \
--region us-east-1
# Di dalam session, periksa log aplikasi dan system
journalctl -u my-application-service --since '10 minutes ago' --no-pager
# Atau jika menggunakan file log
tail -n 200 /var/log/my-app/error.log
# Periksa OOM kill
dmesg | grep -i 'killed process'
# Periksa resource utilization saat ini
top -bn1 | head -20
Pola yang sering ditemukan: aplikasi crash karena memory exhaustion tepat saat menerima request besar, tapi recovery-nya cepat sehingga health check berikutnya sudah lolos. Instance kembali Healthy, tapi 502 sudah terjadi dan mungkin akan berulang.
Pengalaman Nyata: Salah Diagnosa yang Menghabiskan 3 Jam
Skenario yang pernah terjadi: 502 muncul hanya pada request POST dengan payload lebih dari 1MB, GET selalu berhasil. Instance Healthy. Access log menunjukkan target_status_code: - dan error_reason: Target.ConnectionError. Asumsi awal: network issue atau security group.
Setelah 2 jam memeriksa VPC flow log dan security group tanpa hasil, akhirnya curl langsung ke instance dengan payload besar mengungkap masalah sebenarnya: Nginx di instance dikonfigurasi dengan client_max_body_size 1m — request di atas 1MB langsung ditolak Nginx dengan menutup koneksi, bukan dengan mengembalikan 413. Nginx menutup koneksi TCP tanpa mengirim HTTP response, sehingga ALB menerima connection reset dan menghasilkan 502.
Perbaikannya satu baris di konfigurasi Nginx. Tapi pelajarannya: health check tidak pernah menguji payload besar. Instance Healthy hanya berarti path health check bisa diakses — tidak lebih dari itu.
Ringkasan Alur Diagnosa 502 ALB
IAM Policy untuk Akses Diagnosa
Untuk menjalankan semua perintah diagnosa di atas, engineer membutuhkan permission berikut. Terapkan prinsip least privilege — berikan hanya pada role atau user yang memang melakukan troubleshooting.
🔽 Klik untuk melihat IAM Policy diagnosa 502 ALB
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ALBDiagnostics",
"Effect": "Allow",
"Action": [
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeLoadBalancerAttributes",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:ModifyLoadBalancerAttributes"
],
"Resource": "*"
},
{
"Sid": "EC2Diagnostics",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeSecurityGroups"
],
"Resource": "*"
},
{
"Sid": "SSMAccess",
"Effect": "Allow",
"Action": [
"ssm:StartSession",
"ssm:DescribeSessions",
"ssm:TerminateSession"
],
"Resource": "*"
},
{
"Sid": "S3LogAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-alb-logs-bucket",
"arn:aws:s3:::my-alb-logs-bucket/*"
]
}
]
}
Wrap-Up: ALB 502 Selalu Punya Jejak — Temukan di Log yang Benar
502 dari ALB dengan instance Healthy bukan anomali sistem — ini adalah sinyal bahwa lapisan antara ALB dan aplikasi perlu diperiksa lebih dalam dari sekadar status health check. Mulai dari access log ALB untuk mendapatkan error_reason, lalu ikuti jalur yang ditunjukkan: protokol mismatch, keep-alive timeout, respons malformed, atau crash aplikasi. Setiap penyebab meninggalkan jejak berbeda di log.
Untuk referensi lebih lanjut, lihat dokumentasi resmi AWS:
- ALB Access Logs — AWS Documentation
- Target Group Health Checks — AWS Documentation
- Troubleshoot ALB 502 Errors — AWS Knowledge Center
Glosarium
| Istilah | Definisi |
|---|---|
| 502 Bad Gateway | Error HTTP yang dihasilkan ALB ketika target tidak mengembalikan respons HTTP yang valid atau koneksi ke target gagal. |
| Target Group | Kumpulan target (instance, IP, Lambda) yang menerima traffic dari ALB berdasarkan listener rule. |
| Health Check | Probe periodik yang ALB kirim ke target untuk menentukan apakah target layak menerima traffic. Berjalan independen dari traffic produksi. |
| Keep-Alive Timeout | Durasi koneksi TCP persistent dipertahankan antara ALB dan target sebelum ditutup karena tidak ada aktivitas. |
| error_reason | Field di access log ALB yang menjelaskan alasan spesifik kegagalan request, seperti Target.ResponseHeaderTimeout atau Target.ConnectionError. |
Komentar
Posting Komentar