Saat pertama kali saya men-deploy setup multi-server untuk klien di Commsult Indonesia, konfigurasi load balancer sangat naif: round-robin ke tiga upstream server tanpa health check, tanpa batas koneksi, dan tanpa penyetelan timeout. Pertama kali satu server backend kehabisan memori dan mulai mengembalikan 504, Nginx dengan setia terus mengirim 33% traffic ke sana selama beberapa menit sebelum monitoring memberi tahu kami. Load balancer produksi memerlukan logika health check aktif, failover yang anggun, dan konfigurasi upstream yang tepat. Panduan ini mencakup apa yang telah saya pelajari dalam memelihara Nginx sebagai load balancer untuk web API yang melayani klien berbasis Jakarta.
Blok upstream di Nginx mendefinisikan kumpulan server backend dan cara traffic didistribusikan di antara mereka. Algoritma default adalah round-robin — setiap permintaan dikirim ke server berikutnya dalam daftar secara bergiliran. Untuk API stateless (REST, GraphQL), round-robin bekerja dengan baik. Untuk koneksi WebSocket atau sesi yang berumur panjang, least_conn lebih baik — ini merutekan setiap koneksi baru ke server dengan koneksi aktif paling sedikit, mencegah akumulasi koneksi pada satu server. Direktif ip_hash tersedia untuk sesi sticky tetapi harus dihindari dalam arsitektur modern di mana state sesi ada di Redis, bukan di memori pada server tertentu.
Server upstream Nginx mendukung parameter weight untuk mengalihkan lebih banyak atau lebih sedikit traffic ke server tertentu. Jika satu backend memiliki CPU dan RAM dua kali lipat, atur weight=2 untuk mengirimnya dua kali lipat traffic. Parameter backup menandai server sebagai failover — hanya menerima traffic ketika semua server utama tidak tersedia. Ini berguna untuk degradasi yang anggun: server backup yang menjalankan versi aplikasi yang disederhanakan menangani traffic ketika armada utama down, mengembalikan sesuatu yang berguna daripada error 502. Dalam setup kami, kami memiliki satu Droplet yang dikonfigurasi sebagai backup yang menyajikan halaman maintenance ketika dua server utama keduanya tidak tersedia.
Timeout default Nginx terlalu lama untuk sebagian besar API produksi. proxy_connect_timeout mengontrol berapa lama Nginx menunggu koneksi ke backend — 60 detik adalah default, yang tidak masuk akal untuk koneksi jaringan lokal. Atur ini ke 5-10 detik. proxy_read_timeout mengontrol berapa lama Nginx menunggu backend mengirim respons setelah koneksi terjalin — default 60 detik, yang berarti Nginx menahan koneksi terbuka selama satu menit pada backend yang macet. Setel ini agar sesuai dengan waktu pemrosesan permintaan aktual Anda ditambah margin keamanan. proxy_send_timeout mengontrol berapa lama Nginx menunggu saat mengirim permintaan ke backend.
Dari pengalaman saya: atur proxy_next_upstream error timeout http_500 http_502 http_503 dan proxy_next_upstream_tries 2 di blok lokasi upstream Anda. Ini memberi tahu Nginx untuk secara otomatis mencoba ulang permintaan yang gagal pada upstream server berikutnya untuk error server dan timeout. Dikombinasikan dengan health check yang tepat, ini memberikan failover otomatis untuk error backend transien tanpa memengaruhi pengguna akhir. Saya pernah mengalami kasus di mana proses Node.js crash di tengah permintaan dan pengguna tidak menyadarinya karena Nginx mencoba ulang pada backend yang sehat dalam milidetik.
Nginx open-source mendukung passive health check — ia menandai backend sebagai tidak tersedia berdasarkan kegagalan yang diamati. Parameter max_fails mengatur berapa banyak kegagalan berturut-turut yang menyebabkan server ditandai sebagai tidak tersedia. Parameter fail_timeout mengatur berapa lama server tetap tidak tersedia sebelum Nginx mencoba kembali. Titik awal produksi: max_fails=3 fail_timeout=30s. Ini berarti tiga kegagalan berturut-turut (timeout atau kesalahan koneksi) menandai server tidak tersedia selama 30 detik, setelah itu Nginx mencoba satu permintaan untuk menguji apakah telah pulih. Jika permintaan tersebut berhasil, server dikembalikan ke pool; jika gagal, timeout 30 detik diatur ulang.
# /etc/nginx/conf.d/upstream.conf
upstream api_backend {
least_conn;
server 10.0.1.10:3000 weight=2 max_fails=3 fail_timeout=30s;
server 10.0.1.11:3000 weight=2 max_fails=3 fail_timeout=30s;
server 10.0.1.12:3000 backup; # failover server
}
# Rate limiting zone
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://api_backend;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
proxy_send_timeout 10s;
proxy_next_upstream error timeout http_500 http_502 http_503;
proxy_next_upstream_tries 2;
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;
}
}Akhiri SSL di load balancer Nginx dan teruskan HTTP ke server backend di jaringan internal. Ini memusatkan manajemen sertifikat, mengurangi beban CPU pada server backend (TLS handshake intensif CPU), dan menyederhanakan konfigurasi backend. Gunakan Certbot dengan plugin Nginx untuk mendapatkan dan memperbarui otomatis sertifikat Let's Encrypt pada load balancer. Lewatkan header X-Forwarded-For, X-Forwarded-Proto, dan X-Real-IP dari load balancer ke backend sehingga kode aplikasi dapat membaca IP dan protokol klien yang sebenarnya. Selalu verifikasi bahwa aplikasi Anda menggunakan header ini dengan benar — mencatat IP yang salah atau mempercayai HTTP ketika HTTPS diperlukan dapat menyebabkan masalah nyata.
┌─────────────────────────────────────────────────────┐
│ Nginx Load Balancer Production Setup │
├─────────────────────────────────────────────────────┤
│ │
│ Internet → Cloudflare CDN │
│ ↓ │
│ Nginx Load Balancer (443 SSL) │
│ [rate limiting, SSL termination] │
│ ↓ ↓ │
│ Backend 1:3000 Backend 2:3000 │
│ (weight=2) (weight=2) │
│ ↑ │
│ Backup :3000 (if both fail) │
│ │
│ Health: max_fails=3 fail_timeout=30s │
└─────────────────────────────────────────────────────┘Saya pernah memodifikasi konfigurasi upstream Nginx pada load balancer produksi untuk mengubah algoritma load balancing dari round-robin ke least_conn. Saya mengedit nginx.conf dan menjalankan nginx -s reload — yang saya harapkan akan diterapkan dengan anggun. Yang saya lewatkan: saya secara tidak sengaja menghapus salah satu entri upstream server, sehingga reload langsung mengurangi sepertiga kapasitas backend. Perintah nginx -s reload menerapkan perubahan pada koneksi baru tetapi tidak memvalidasi bahwa upstream server dapat dijangkau. Selalu jalankan nginx -t terlebih dahulu (tes konfigurasi), selalu uji perubahan pada staging, dan pertimbangkan pendekatan canary di mana Anda menerapkan perubahan ke satu PoP atau satu load balancer dalam cluster sebelum semua.
Load balancer tanpa rate limiting rentan terhadap lonjakan traffic yang membanjiri backend. Direktif limit_req_zone dan limit_req Nginx mengimplementasikan token-bucket rate limiting per IP. Konfigurasi umum: 10 permintaan per detik per IP untuk API dengan allowance burst 20. Klien dalam batas burst dilayani segera; klien yang melebihi rate limit menerima 429 Too Many Requests. Untuk API terautentikasi di mana rate limiting per pengguna lebih tepat daripada per IP, gunakan zone key berbasis header: $http_x_user_id. Kombinasikan dengan fail2ban pada backend untuk memblokir IP yang berulang kali memicu rate limit.
Nginx mendukung zero-downtime reload konfigurasi melalui nginx -s reload. Proses master membaca konfigurasi baru, memunculkan worker process baru dengan konfigurasi yang diperbarui, dan menguras koneksi yang ada pada worker lama dengan anggun. Koneksi aktif selesai secara normal; koneksi baru pergi ke worker baru. Ini berarti Anda dapat memperbarui daftar upstream server, mengubah nilai timeout, atau memodifikasi sertifikat SSL tanpa menjatuhkan satu koneksi pun. Prasyarat kritis: selalu jalankan nginx -t sebelum nginx -s reload untuk memvalidasi sintaks konfigurasi. File konfigurasi yang buruk menyebabkan reload gagal dengan konfigurasi lama yang tetap aktif — yang sebenarnya merupakan perilaku aman.
Untuk skala yang saya jalankan di Commsult Indonesia (ribuan permintaan per menit, bukan jutaan), Nginx adalah pilihan yang tepat: familiar, terdokumentasi dengan baik, berfungsi ganda sebagai load balancer dan web server, dan gratis. HAProxy memiliki kemampuan health check yang lebih kuat (termasuk active health check dalam open source) dan dibangun khusus untuk load balancing dengan set fitur yang lebih kaya — layak dipertimbangkan untuk volume traffic lebih tinggi atau ketika Anda memerlukan load balancing UDP. Cloud Load Balancing GCP dan load balancing Cloudflare sangat baik untuk distribusi traffic global dengan failover otomatis lintas region, tetapi menambahkan biaya dan kompleksitas operasional yang tidak dibenarkan untuk workload klien UKM Indonesia yang berjalan di region Singapura.
Sumber & Bacaan Lanjutan