# Deployment Zero-Downtime dengan NGINX Blue-Green di VPS Tunggal

> Implementasi blue-green deployment di VPS tunggal menggunakan NGINX dan Docker — tukar traffic live antara dua kontainer dengan script shell dan raih rilis benar-benar tanpa downtime.

URL: https://www.matthewswong.com/id/blog/zero-downtime-nginx-blue-green-deploy/

- Author: Matthews Wong (https://www.matthewswong.com/id/about/)
- Published: 2025-06-10
- Updated: 2025-06-10
- Category: DevOps

Setiap kali Anda merestart kontainer Docker untuk men-deploy versi baru, ada celah — betapapun singkatnya — di mana aplikasi Anda tidak tersedia. Untuk proyek sampingan dengan traffic rendah, celah itu masih bisa ditoleransi. Untuk layanan produksi dengan pengguna nyata dan SLA, tidak. Saya mengimplementasikan blue-green deployment menggunakan NGINX dan Docker biasa di DigitalOcean Droplet setelah seorang klien mengeluh tentang gangguan singkat selama siklus rilis nightly kami. Solusinya tidak membutuhkan Kubernetes, load balancer eksternal, atau tooling berbayar — hanya bash script, dua slot kontainer, dan NGINX reload yang cerdas.

## Konsep Blue-Green

Blue-green deployment menjaga dua lingkungan produksi yang identik — disebut Blue dan Green — selalu tersedia. Setiap saat, satu lingkungan aktif (melayani traffic pengguna) dan yang lain idle (siap menerima deployment berikutnya). Ketika Anda men-deploy versi baru, Anda menjalankannya di slot idle, menjalankan health check, lalu membalik upstream NGINX untuk mengarah ke slot baru. Slot lama tetap berjalan untuk rollback instan — jika ada yang terlihat salah setelah pembalikan, Anda mengubah upstream kembali dan memuat ulang NGINX. Seluruh cutover memakan waktu kurang dari satu detik.

### Mengapa Tidak Cukup Dengan Rolling Restart?

Perilaku restart default Docker (`docker stop` + `docker start`) menciptakan jendela downtime. Bahkan dengan startup yang cepat, biasanya ada 2-10 detik di mana tidak ada kontainer yang mendengarkan di port. NGINX mengembalikan 502 Bad Gateway selama jendela ini. `depends_on` Docker Compose dengan health check membantu, tetapi graceful shutdown kontainer lama dan kesiapan kontainer baru tidak tersinkronisasi secara atomis. Blue-green menghindari ini dengan tidak pernah menghentikan kontainer aktif sampai yang baru dikonfirmasi sehat dan melayani traffic.

### NGINX sebagai Pembalik Traffic

Perintah `nginx -s reload` NGINX memuat ulang file konfigurasi dan memperbarui target upstream tanpa menjatuhkan koneksi yang sedang berlangsung. Ketika Anda mengubah blok upstream untuk mengarah ke port kontainer baru lalu memuatnya, NGINX menyelesaikan semua permintaan aktif di upstream lama sebelum mengalihkan koneksi baru ke yang baru. Perilaku ini — disebut graceful reload — adalah kunci yang membuat zero-downtime blue-green menjadi mungkin dengan NGINX vanilla tanpa plugin atau modul berbayar.

> Tambahkan `proxy_next_upstream error timeout http_502 http_503` ke blok location NGINX Anda. Ini memberitahu NGINX untuk secara otomatis mencoba ulang permintaan di upstream server berikutnya jika upstream utama mengembalikan error atau timeout. Dikombinasikan dengan menjaga kedua kontainer blue dan green berjalan selama jendela transisi, ini memastikan bahkan in-flight request pada saat pembalikan upstream ditangani secara transparan.

## Script Deployment

Inti dari setup blue-green adalah bash script yang: mendeteksi kontainer mana yang sedang live (blue atau green), memulai kontainer lain dengan image baru, melakukan polling endpoint health check sampai merespons 200, memperbarui file upstream NGINX, memuat ulang NGINX secara graceful, lalu menghentikan kontainer yang sebelumnya live. Script ini idempoten — Anda bisa menjalankannya beberapa kali dengan aman. Script keluar dengan kode non-zero jika health check gagal, membiarkan kontainer lama berjalan dan NGINX tidak berubah, sehingga tidak ada pengguna yang pernah melihat deployment yang rusak.

### Desain Health Check

Endpoint health check harus mencerminkan kesiapan aplikasi yang sebenarnya, bukan hanya startup HTTP server. Endpoint /health yang baik di aplikasi Node.js/Express memeriksa konektivitas database, ketersediaan cache, dan koneksi layanan eksternal yang diperlukan. Jika dependensi apa pun tidak tersedia, health check mengembalikan HTTP 503, script deployment melihat kegagalan, dan pertukaran blue-green dibatalkan. Ini berarti migrasi database yang gagal atau environment variable yang salah dikonfigurasi akan mencegah deployment buruk tersebut menerima traffic live.

> **Sesi WebSocket dan Koneksi Long-Poll**

> Jika aplikasi Anda mempertahankan koneksi WebSocket atau long-polling, graceful reload NGINX tidak akan secara paksa mengakhiri koneksi tersebut — mereka tetap di upstream lama sampai klien memutuskan koneksi. Ini biasanya diinginkan, tetapi berarti kontainer lama mungkin terus menangani traffic selama beberapa menit setelah pertukaran. Jangan hentikan kontainer lama segera setelah reload NGINX. Sebaiknya tunggu setidaknya 60 detik (atau monitor koneksi aktif dengan `ss -tnp | grep '<'port>`) sebelum menghentikan kontainer lama untuk menghindari pemutusan paksa sesi WebSocket aktif.

## Strategi Rollback

Keindahan blue-green adalah rollback yang instan dan tidak memerlukan deployment baru. Karena kontainer lama masih berjalan setelah cutover (hanya tidak menerima koneksi baru via NGINX), rollback cukup dengan mengarahkan upstream NGINX kembali ke port lama dan memuat ulang. Tambahkan script `rollback.sh` yang mencerminkan script deploy namun melewati startup kontainer — cukup balik upstream dan reload. Biarkan kontainer lama berjalan setidaknya 30 menit setelah deploy yang sukses sebelum menghapusnya, memberi Anda jendela rollback yang bersih.

## Integrasi dengan GitHub Actions

Script deployment terintegrasi dengan baik ke GitHub Actions menggunakan marketplace action `appleboy/ssh-action`. Workflow CI Anda membangun dan mendorong image Docker di setiap push ke main, lalu SSH ke server produksi dan menjalankan `./blue-green-deploy.sh '<'image-tag>`. Workflow gagal jika loop health check timeout, mengirim notifikasi kegagalan ke Slack atau email sebelum kode yang rusak mencapai pengguna. Simpan private key SSH dan IP server di GitHub Actions secrets — jangan pernah hard-code di file workflow.

## Biaya dan Kompleksitas vs Kubernetes

Setup blue-green ini berjalan di Droplet DigitalOcean $12-24/bulan tunggal tanpa infrastruktur tambahan. Kubernetes dengan GKE atau DOKS untuk jaminan zero-downtime yang sama biayanya setidaknya $35-75/bulan untuk control plane saja, belum termasuk biaya node. Untuk workload kecil hingga menengah di mana Anda mengontrol seluruh stack, pendekatan bash + NGINX + Docker secara dramatis lebih murah dan lebih mudah di-debug. Kubernetes menjadi sepadan dengan kompleksitas operasionalnya ketika Anda membutuhkan horizontal Pod autoscaling, isolasi namespace multi-tenant, atau jaminan resource tingkat cluster — tidak satu pun dari ini yang dibutuhkan deployment VPS single-service.

## Sumber & Bacaan Lanjutan

- NGINX — Dokumentasi ngx_http_upstream_module — https://nginx.org/en/docs/http/ngx_http_upstream_module.html
- Martin Fowler — BlueGreenDeployment — https://martinfowler.com/bliki/BlueGreenDeployment.html
- Docker — Referensi docker run — https://docs.docker.com/engine/reference/commandline/run/

## Source links

- https://nginx.org/en/docs/http/ngx_http_upstream_module.html
- https://martinfowler.com/bliki/BlueGreenDeployment.html
- https://docs.docker.com/engine/reference/commandline/run/

## FAQ

### Mengapa restart kontainer Docker biasa tidak cukup untuk deployment zero-downtime?

Ketika Anda menjalankan `docker stop` lalu `docker start`, biasanya ada celah 2–10 detik di mana tidak ada kontainer yang mendengarkan di port tersebut. Selama jeda ini NGINX mengembalikan 502 Bad Gateway ke setiap permintaan yang masuk. Blue-green deployment menghindari hal ini dengan tetap menjalankan kontainer aktif sampai kontainer baru dikonfirmasi sehat dan siap melayani traffic.

### Bagaimana NGINX melakukan perpindahan upstream tanpa menjatuhkan koneksi yang sedang berlangsung?

Perintah `nginx -s reload` memuat ulang konfigurasi dan memperbarui target upstream tanpa memutus koneksi aktif — perilaku ini disebut graceful reload. Ketika blok upstream diperbarui ke port kontainer baru dan NGINX di-reload, ia menyelesaikan semua permintaan yang sedang diproses di upstream lama sebelum mengalihkan koneksi baru ke yang baru. Menambahkan `proxy_next_upstream error timeout http_502 http_503` juga memastikan permintaan yang mengenai upstream yang sedang dalam transisi secara otomatis dicoba ulang ke slot yang sehat.

### Apa yang dilakukan bash script blue-green, dan apa yang terjadi jika health check gagal?

Script mendeteksi slot mana (blue atau green) yang sedang live, menjalankan slot lain dengan image baru, melakukan polling endpoint `/health` hingga mengembalikan HTTP 200, memperbarui file upstream NGINX, memuat ulang NGINX secara graceful, lalu menghentikan kontainer yang sebelumnya live. Jika health check tidak pernah mengembalikan 200, script keluar dengan kode non-zero, membiarkan kontainer lama tetap berjalan, dan NGINX tidak berubah — sehingga tidak ada deployment yang rusak yang pernah mencapai pengguna.

### Bagaimana koneksi WebSocket atau long-poll ditangani saat proses blue-green swap?

Graceful reload NGINX tidak memutus paksa koneksi WebSocket atau long-poll yang sudah aktif — koneksi tersebut tetap di upstream lama sampai klien memutuskan koneksi sendiri. Artinya kontainer lama mungkin masih menangani traffic beberapa menit setelah upstream dibalik. Post ini merekomendasikan untuk menunggu setidaknya 60 detik (atau memantau koneksi aktif dengan `ss -tnp`) sebelum menghentikan kontainer lama agar sesi yang aktif tidak terputus paksa.

### Bagaimana perbandingan biaya setup blue-green ini dibandingkan menggunakan Kubernetes?

Setup bash + NGINX + Docker ini berjalan di Droplet DigitalOcean seharga $12–24/bulan tanpa infrastruktur tambahan. Kubernetes di GKE atau DOKS membutuhkan biaya setidaknya $35–75/bulan hanya untuk control plane, belum termasuk biaya node. Untuk workload single-service skala kecil hingga menengah, pendekatan VPS jauh lebih murah dan lebih mudah di-debug, sedangkan Kubernetes baru sepadan kompleksitasnya ketika Anda butuh horizontal Pod autoscaling, isolasi namespace multi-tenant, atau jaminan resource tingkat cluster.

---

- HTML version: https://www.matthewswong.com/id/blog/zero-downtime-nginx-blue-green-deploy/
- English: https://www.matthewswong.com/en/blog/zero-downtime-nginx-blue-green-deploy/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
