Satu VPS dengan satu IP publik bisa melayani banyak domain dan banyak aplikasi sekaligus. Nginx membaca nama domain dari SNI dan header Host, lalu meneruskan permintaan ke aplikasi yang tepat di belakangnya — semuanya tanpa membuka port aplikasi ke internet.

Ringkasan singkat
- Satu file konfigurasi per domain di
sites-available. - Empat header wajib: Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto.
- Tolak domain asing dengan
default_server+return 444. - Uji dengan header Host sebelum DNS propagasi.
Yang perlu disiapkan
- Nginx terpasang di Ubuntu 24.04.
- Domain yang record A-nya sudah mengarah ke IP server (cek
dig +short domain). - Aplikasi yang mendengarkan di localhost, misal port 3000 dan 8080.
- Certbot untuk sertifikat TLS.
1. Pola direktori
Simpan satu file per domain agar mudah dilacak:
sudo mkdir -p /var/www/app1
sudo nano /etc/nginx/sites-available/app1.contoh.com
Aktifkan dengan symlink, bukan dengan menyalin file. Dengan begitu hanya ada satu sumber kebenaran:
sudo ln -s /etc/nginx/sites-available/app1.contoh.com /etc/nginx/sites-enabled/
2. Reverse proxy dasar
server {
listen 80;
server_name app1.contoh.com;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}
Empat header itu bukan formalitas. Tanpa X-Forwarded-For, aplikasi mencatat IP Nginx untuk semua pengguna; tanpa X-Forwarded-Proto, aplikasi mengira koneksi masih HTTP dan bisa menghasilkan redirect loop.
3. Domain kedua dan seterusnya
server {
listen 80;
server_name api.contoh.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Tambahkan satu blok server per domain. Jangan menumpuk beberapa server_name dengan tujuan berbeda dalam satu blok — hasilnya sulit diprediksi saat ada perubahan.
4. WebSocket
Aplikasi realtime memerlukan header upgrade. Tambahkan di level http (biasanya di /etc/nginx/nginx.conf):
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
Lalu di dalam location:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
5. Tolak domain asing
Tanpa blok default, permintaan ke IP langsung atau domain lain akan dilayani situs pertama yang aktif. Itu membuat trafik tak dikenal masuk ke aplikasi kita:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
Kode 444 adalah kode internal Nginx: koneksi ditutup tanpa respons. Lebih hemat daripada mengirim 404 ke pemindai port.
6. Uji konfigurasi dan muat ulang
sudo nginx -t
sudo systemctl reload nginx
curl -I http://app1.contoh.com
curl -I http://api.contoh.com
nginx -t harus lolos sebelum reload. Reload gagal tidak mematikan Nginx, tetapi perubahanmu juga tidak berlaku dan itu mudah tertukar dengan "konfigurasi tidak bekerja".
7. Pasang TLS untuk semua domain
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d app1.contoh.com -d api.contoh.com
Satu sertifikat bisa memuat beberapa nama (SAN). Kalau domain bertambah, cukup jalankan Certbot lagi dengan -d tambahan; Certbot akan memperluas sertifikat yang ada.
8. Batas ukuran unggahan dan timeout
client_max_body_size 25m;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
Aplikasi yang menerima unggahan besar akan gagal dengan 413 Request Entity Too Large kalau batas ini tidak dinaikkan. Sebaliknya, jangan set ke 0 (tanpa batas) karena membuka jalan penyalahgunaan disk.
9. Mengarahkan ke container Docker
Kalau aplikasi berjalan di container, ikat port ke localhost agar tidak melewati firewall:
docker run -d --name app1 -p 127.0.0.1:3000:3000 app1:latest
Lalu proxy_pass http://127.0.0.1:3000; bekerja seperti biasa, dan port itu tidak terbuka ke internet.
10. Kompresi dan cache aset statis
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
location ~* \.(css|js|jpg|png|svg|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
Aset statis sebaiknya dilayani langsung oleh Nginx, bukan diteruskan ke aplikasi. Satu aturan ini biasanya memangkas waktu render halaman secara signifikan karena browser tidak lagi mengunduh ulang berkas yang sama.
11. Log terpisah per domain
access_log /var/log/nginx/app1.access.log;
error_log /var/log/nginx/app1.error.log;
Saat satu domain bermasalah, log gabungan membuat diagnosis lambat. Dengan file terpisah, kamu bisa langsung melihat permintaan dan error milik domain itu saja, lalu memutar log dengan logrotate agar disk tidak penuh.
12. Menguji tanpa menunggu DNS
Propagasi DNS bisa berjam-jam. Uji server block lebih dulu dengan mengirim header Host langsung ke localhost:
curl -I -H "Host: app1.contoh.com" http://127.0.0.1
Balasan 200 dengan halaman yang benar berarti konfigurasi sudah siap dan sisa masalahnya hanya DNS. Untuk HTTPS, gunakan --resolve agar nama domain diarahkan ke localhost tanpa mengubah DNS:
curl -I --resolve app1.contoh.com:443:127.0.0.1 https://app1.contoh.com
13. Menonaktifkan satu domain
sudo rm /etc/nginx/sites-enabled/app1.contoh.com
sudo nginx -t && sudo systemctl reload nginx
Hapus symlink, bukan file aslinya, supaya konfigurasinya masih bisa diaktifkan kembali tanpa mengetik ulang.
Masalah yang sering muncul
| Gejala | Penyebab | Solusi |
|---|---|---|
| 502 Bad Gateway | Aplikasi mati atau port salah | ss -lntp | grep 3000, cek log aplikasi |
| 504 Gateway Timeout | Aplikasi lambat, proxy menyerah | Naikkan proxy_read_timeout, perbaiki performa aplikasi |
| 413 Request Entity Too Large | Batas unggahan default 1 MB | client_max_body_size |
| IP pengguna selalu 127.0.0.1 | Header tidak diteruskan | Set X-Real-IP dan X-Forwarded-For |
| WebSocket langsung terputus | Header upgrade tidak ada | Tambahkan map dan Connection |
| Domain lain ikut tampil | Tidak ada default_server | Tambahkan blok return 444 |
Pertanyaan yang sering diajukan
Berapa domain yang bisa dilayani?
Batasan praktisnya RAM dan jumlah sertifikat, bukan Nginx. Puluhan domain di satu VPS kecil adalah hal biasa.
Perlu satu server block per aplikasi atau per domain?
Per domain. Kalau satu domain punya beberapa path ke aplikasi berbeda, gunakan location /api/ dengan proxy_pass sendiri.
Apakah Nginx menggantikan firewall?
Tidak. Nginx mengatur trafik HTTP; pembatasan port tetap tugas UFW.
Bagaimana melihat domain mana yang menerima trafik?
sudo tail -f /var/log/nginx/access.log
Baca juga:
0 comments:
Post a Comment