Skip to main content
BlogDevOps

Load Balancer Nginx di Produksi: Konfigurasi, Health Check, dan Failover

Panduan konfigurasi load balancer Nginx lengkap untuk produksi — upstream group, passive health check, routing least-conn, SSL termination, dan reload aman tanpa downtime.

Matthews Wong

Software Engineer

Juni 202511 menit baca
DevOps

Konfigurasi load balancer yang naif untuk setup multi-server adalah round-robin ke tiga upstream server tanpa health check, tanpa batas koneksi, dan tanpa penyetelan timeout. Jika satu server backend kehabisan memori dan mulai mengembalikan 504, Nginx dengan setia akan terus mengirim sepertiga traffic ke sana selama beberapa menit sebelum monitoring memberi peringatan. Load balancer produksi memerlukan logika health check aktif, failover yang anggun, dan konfigurasi upstream yang tepat. Panduan ini mencakup apa yang perlu dikonfigurasi saat menjalankan Nginx sebagai load balancer untuk web API.

Dasar-Dasar Konfigurasi Upstream Group

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.

Bobot Server dan Server Backup

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.

Konfigurasi Timeout

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.

Passive Health Check dengan max_fails dan fail_timeout

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;
    }
}

SSL Termination di Load Balancer

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.

Rate Limiting dan Connection Limiting

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.

Zero-Downtime Reload dan Pengujian Konfigurasi

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.

Pendapat Saya: Nginx vs HAProxy vs Cloud Load Balancer

Untuk skala menengah (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 kecil hingga menengah yang berjalan di satu region.

Artikel Terkait

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Mengapa least_conn lebih baik daripada round-robin untuk koneksi WebSocket atau sesi berumur panjang?

Round-robin mendistribusikan permintaan secara bergiliran, yang bekerja baik untuk panggilan API stateless berumur pendek. Untuk koneksi WebSocket atau sesi yang berumur panjang, least_conn lebih tepat karena ia merutekan setiap koneksi baru ke server dengan koneksi aktif paling sedikit, mencegah satu backend menumpuk beban yang tidak proporsional sementara server lain menganggur.

Bagaimana passive health check Nginx bekerja, dan apa setelan yang direkomendasikan?

Passive health check Nginx menandai backend sebagai tidak tersedia berdasarkan kegagalan yang diamati, bukan dengan probing aktif. Parameter max_fails mengatur berapa banyak kegagalan berturut-turut yang memicu status tidak tersedia, dan fail_timeout mengatur berapa lama server keluar dari pool sebelum dicoba kembali. Titik awal produksi yang praktis adalah max_fails=3 fail_timeout=30s — tiga kegagalan berturut-turut menarik server selama 30 detik, setelah itu satu permintaan uji menentukan apakah server bergabung kembali ke pool.

Apa cara paling aman untuk menerapkan perubahan load balancer Nginx tanpa downtime?

Selalu jalankan nginx -t terlebih dahulu untuk memvalidasi sintaks konfigurasi sebelum menerapkan perubahan — file konfigurasi yang buruk menyebabkan reload gagal dengan aman sementara konfigurasi lama tetap aktif. Kemudian gunakan nginx -s reload, yang memunculkan worker process baru dengan konfigurasi terbaru sementara koneksi aktif selesai secara normal pada worker lama. Uji perubahan di staging terlebih dahulu, dan pertimbangkan pendekatan canary dengan menerapkan perubahan ke satu load balancer dalam cluster sebelum semua.

Mengapa SSL sebaiknya diakhiri di load balancer daripada di setiap server backend?

Mengakhiri SSL di load balancer Nginx memusatkan manajemen sertifikat ke satu titik, mengurangi beban CPU pada server backend karena TLS handshake sangat intensif CPU, dan menyederhanakan konfigurasi backend karena server tersebut hanya menangani HTTP biasa di jaringan internal. Certbot dengan plugin Nginx dapat mendapatkan dan memperbarui otomatis sertifikat Let's Encrypt langsung pada load balancer.

Kapan sebaiknya memilih HAProxy atau cloud load balancer daripada Nginx?

Nginx adalah pilihan tepat pada volume traffic sedang (ribuan permintaan per menit) karena familiar, berfungsi ganda sebagai load balancer dan web server, serta gratis. HAProxy menawarkan kemampuan health check yang lebih kuat, termasuk active health check dalam edisi open source-nya, dan layak dipertimbangkan pada volume traffic lebih tinggi atau ketika load balancing UDP dibutuhkan. Opsi cloud seperti GCP Cloud Load Balancing atau Cloudflare sangat baik untuk distribusi traffic global dengan failover lintas region, tetapi menambahkan biaya dan kompleksitas operasional yang sulit dijustifikasi untuk beban kerja regional seperti klien UKM Indonesia yang berjalan di region Singapura.