Setiap aplikasi web modern yang berjalan di production hampir selalu melewati satu gerbang utama: reverse proxy. Nginx adalah web server sekaligus reverse proxy paling populer di dunia, dipakai jutaan situs untuk meneruskan permintaan (request) dari pengguna ke aplikasi backend — entah itu aplikasi Flask, REST API Node.js + Express, ataupun layanan yang berjalan di dalam container Docker. Di tutorial ini kamu akan belajar mengonfigurasi Nginx sebagai reverse proxy dari nol, menambahkan load balancing, hingga mengamankan situsmu dengan HTTPS gratis menggunakan Let's Encrypt.

Apa Itu Reverse Proxy?

Reverse proxy adalah server yang duduk di depan satu atau beberapa aplikasi backend dan meneruskan permintaan klien ke backend tersebut. Berbeda dengan forward proxy (yang mewakili klien), reverse proxy mewakili server. Klien hanya tahu alamat Nginx, dan Nginx-lah yang memutuskan backend mana yang akan menangani request. Manfaatnya sangat besar:

  • Load balancing — membagi beban ke beberapa instance backend.
  • SSL termination — Nginx menangani HTTPS sehingga backend cukup HTTP biasa.
  • Caching & kompresi — mempercepat respons ke pengguna.
  • Keamanan — menyembunyikan detail backend dan bisa membatasi akses.
  • Satu pintu untuk banyak aplikasi — beberapa domain/subdomain diarahkan ke backend berbeda.

Prasyarat

Untuk mengikuti tutorial ini kamu butuh sebuah server Linux (Ubuntu/Debian disarankan) dengan akses sudo, dan satu domain (atau subdomain) yang sudah diarahkan (DNS) ke IP server tersebut. Kamu tidak perlu paham Docker, tapi jika backend-mu berjalan sebagai container, konsepnya sama saja.

Contoh di tutorial ini memakai domain api.contoh.com dan backend di port 5000. Ganti dengan domain dan port milikmu sendiri.

Langkah 1: Membuat Aplikasi Backend Sederhana

Agar punya sesuatu untuk di-proxy, buatlah API kecil dengan Flask. Simpan kode berikut sebagai app.py:

# app.py
from flask import Flask, jsonify

app = Flask(__name__)

@app.route("/")
def index():
    return jsonify({
        "message": "Halo dari backend!",
        "server": "backend-1",
    })

@app.route("/health")
def health():
    return jsonify({"status": "ok"})

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

Jalankan aplikasi di latar belakang. Untuk simulasi load balancing nanti, kita akan menjalankan beberapa instance di port berbeda.

bash
pip install flask

# Jalankan instance pertama di port 5000
python app.py &

# Instance kedua dan ketiga (untuk simulasi load balancing)
FLASK_RUN_PORT=5001 python app.py &
FLASK_RUN_PORT=5002 python app.py &

Supaya port 5001 dan 5002 benar-benar dipakai, ubah app.run(..., port=5000) menjadi port=int(os.environ.get("FLASK_RUN_PORT", 5000)) dan tambahkan import os di atas. Atau cukup jalankan tiga salinan file dengan port yang di-hardcode berbeda.

Langkah 2: Instalasi Nginx

bash
sudo apt update
sudo apt install -y nginx

# Aktifkan agar berjalan otomatis saat boot
sudo systemctl enable --now nginx
sudo systemctl status nginx

Setelah itu, buka IP server di browser. Jika muncul halaman Welcome to nginx!, berarti instalasi berhasil.

Langkah 3: Konfigurasi Reverse Proxy Dasar

Buat file konfigurasi baru untuk domainmu di direktori /etc/nginx/sites-available/, lalu tautkan ke sites-enabled.

bash
sudo nano /etc/nginx/sites-available/api.contoh.com

Isi dengan konfigurasi berikut:

python
server {
    listen 80;
    server_name api.contoh.com;

    location / {
        proxy_pass http://127.0.0.1:5000;
        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;
    }
}

Beberapa direktif penting: proxy_pass menentukan alamat backend, sementara proxy_set_header meneruskan informasi asli klien (IP, host, protokol) agar aplikasi backend tahu siapa pengguna sebenarnya. Ini krusial untuk logging dan pembuatan URL yang benar.

bash
# Aktifkan situs (symlink ke sites-enabled)
sudo ln -s /etc/nginx/sites-available/api.contoh.com /etc/nginx/sites-enabled/

# Nonaktifkan konfigurasi default jika perlu
sudo rm -f /etc/nginx/sites-enabled/default

# Uji konfigurasi lalu muat ulang Nginx
sudo nginx -t
sudo systemctl reload nginx

Jika semua benar, buka http://api.contoh.com dan kamu akan melihat respons JSON dari aplikasi Flask — padahal port 5000 tidak pernah diekspos langsung ke internet.

Langkah 4: Load Balancing dengan Beberapa Backend

Dengan satu backend saja, jika aplikasi mati maka seluruh situs ikut mati. Nginx bisa membagi beban ke beberapa instance lewat blok upstream.

python
upstream backend {
    least_conn;
    server 127.0.0.1:5000;
    server 127.0.0.1:5001;
    server 127.0.0.1:5002;
}

server {
    listen 80;
    server_name api.contoh.com;

    location / {
        proxy_pass http://backend;
        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;
    }
}

Direktif least_conn mengirim request ke server dengan koneksi aktif paling sedikit. Strategi lain yang bisa dipakai: round_robin (default), ip_hash (pengguna selalu ke server yang sama), atau random. Muat ulang Nginx lalu refresh beberapa kali — nilai server pada respons JSON akan berganti-ganti.

Langkah 5: HTTPS Gratis dengan Let's Encrypt

Langkah terakhir dan paling penting: mengamankan trafik dengan HTTPS. Certbot dari Let's Encrypt mengotomatiskan penerbitan dan perpanjangan sertifikat SSL secara gratis.

bash
sudo apt install -y certbot python3-certbot-nginx

# Terbitkan sertifikat dan modifikasi konfigurasi Nginx otomatis
sudo certbot --nginx -d api.contoh.com

Certbot akan menanyakan alamat email untuk notifikasi kedaluwarsa dan persetujuan syarat layanan. Setelah selesai, konfigurasi Nginx-mu otomatis ditambahkan blok HTTPS plus pengalihan otomatis dari HTTP ke HTTPS. Hasil akhirnya kurang lebih seperti ini:

python
server {
    listen 80;
    server_name api.contoh.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name api.contoh.com;

    ssl_certificate /etc/letsencrypt/live/api.contoh.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.contoh.com/privkey.pem;

    location / {
        proxy_pass http://backend;
        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;
    }
}

Perhatikan bahwa proxy_pass http://backend; memakai skema http — ini wajar karena Nginx-lah yang menangani SSL (SSL termination), sementara trafik antara Nginx dan backend berjalan di jaringan internal. Pastikan port backend tidak terbuka ke publik lewat firewall.

Sertifikat Let's Encrypt berlaku 90 hari, tetapi Certbot memasang timer systemd untuk memperpanjangnya otomatis. Kamu bisa mengujinya dengan:

bash
sudo certbot renew --dry-run

Kesimpulan

Selamat! Kamu sekarang punya Nginx yang berfungsi sebagai reverse proxy, membagi beban ke beberapa backend, dan melayani trafik melalui HTTPS. Ini adalah fondasi yang dipakai hampir semua aplikasi production modern. Untuk level berikutnya, kamu bisa menggabungkannya dengan Docker Compose agar seluruh stack (Nginx + backend) bisa di-deploy dengan satu perintah, atau mempelajari orkestrasi skala besar dengan Kubernetes. Selamat mencoba!