Proteksi DoS #
Di internet publik, server kita tidak hanya menghadapi pengguna manusia yang berselancar secara normal, tetapi juga ancaman serangan Denial of Service (DoS). Tujuan utama dari serangan DoS adalah untuk melumpuhkan server dengan cara menghabiskan seluruh sumber daya yang tersedia — seperti memori RAM, kapasitas CPU, bandwidth jaringan, hingga slot antrean koneksi (connection sockets) — sehingga pengguna sah lainnya tidak dapat lagi mengakses layanan kita.
Nginx dikenal secara global memiliki arsitektur berbasis kejadian (event-driven) yang sangat tangguh dalam menangani ribuan koneksi simultan dengan memori yang sangat kecil. Namun, tanpa konfigurasi pengerasan (hardening) yang tepat, Nginx kita tetap dapat dilumpuhkan oleh serangan DoS tingkat aplikasi. Di artikel ini, kita akan membedah perbedaan mitigasi Nginx vs solusi DDoS eksternal, membatasi koneksi simultan menggunakan limit_conn, menangkal serangan lambat (Slow HTTP Attacks) via penyetelan timeout, membatasi ukuran unggahan berkas, hingga melakukan pembatasan bandwidth (bandwidth throttling).
Batasan Nginx vs Solusi Dedicated DDoS Protection #
Sebelum kita melakukan konfigurasi, kita harus bersikap realistis mengenai kapasitas pertahanan Nginx.
- Volumetric DDoS Attacks: Serangan ini bekerja di tingkat jaringan (Layer 3 & 4) dengan cara mengirimkan trafik raksasa (puluhan Gigabyte hingga Terabyte per detik, misalnya via NTP/DNS Amplification atau SYN Flood) untuk membanjiri pipa bandwidth masuk server. Nginx tidak akan mampu menangani serangan jenis ini. Pipa bandwidth server kita akan tersumbat sebelum paket data tersebut sampai ke perangkat lunak Nginx. Untuk mitigasi ini, kita wajib menggunakan solusi eksternal seperti Cloudflare, AWS Shield, atau DDoS Scrubbing Centers di depan infrastruktur kita.
- Application-Layer DoS (Layer 7): Serangan ini menargetkan kelemahan pemrosesan di tingkat aplikasi dengan trafik yang relatif kecil namun boros sumber daya. Misalnya, serangan membuka koneksi secara perlahan (Slowloris), banjir kueri pencarian database, atau banjir koneksi unduhan file besar. Nginx sangat efektif dan berada di posisi terbaik untuk meredam serangan jenis ini sebelum request menyentuh server backend kita.
limit_conn: Membatasi Koneksi Simultan per Alamat IP #
Sementara rate limiting (limit_req) membatasi laju request per detik, direktif limit_conn digunakan untuk membatasi jumlah koneksi aktif secara simultan dari satu IP tunggal.
Skenario ini sangat penting untuk mencegah:
- Satu pengguna membuka puluhan tab browser atau menjalankan skrip unduhan paralel yang memonopoli koneksi server.
- Serangan banjir koneksi (connection flooding) yang mencoba menghabiskan soket TCP sistem operasi server kita.
Langkah 1: Definisikan Zone Koneksi di Konteks http
#
Sama seperti rate limiting, kita harus membuat area memori bersama (shared memory zone) di tingkat blok http:
http {
# Zone A: Melacak jumlah koneksi berdasarkan IP klien (10m = 160.000 IP)
limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;
# Zone B: Melacak total koneksi ke server virtual tertentu
limit_conn_zone $server_name zone=conn_per_server:10m;
# Kustomisasi respons saat limit terlampaui (Gunakan HTTP 429)
limit_conn_status 429;
limit_conn_log_level warn;
}
Langkah 2: Terapkan limit_conn pada Lokasi yang Sesuai #
Kita dapat menerapkan batasan ini secara global di server block atau secara spesifik pada lokasi folder tertentu (misalnya direktori unduhan berkas):
server {
listen 443 ssl;
server_name example.com;
# Maksimum 15 koneksi simultan aktif per IP untuk seluruh website
limit_conn conn_per_ip 15;
# Maksimum 2000 koneksi total yang boleh masuk ke server virtual ini
# (Untuk melindungi server dari kelebihan kapasitas internal)
limit_conn conn_per_server 2000;
location / {
try_files $uri $uri/ =404;
}
# Aturan lebih ketat untuk direktif unduhan file besar
location /downloads/ {
# Batasi secara ekstrem: hanya boleh 2 koneksi simultan per IP
# (Mencegah user menggunakan download manager dengan multi-connection speed)
limit_conn conn_per_ip 2;
root /var/www/data;
}
}
Menangkal Serangan Lambat (Slow HTTP Attacks / Slowloris) #
Salah satu teknik serangan aplikasi paling mematikan bagi web server tradisional adalah Slowloris (atau Slow HTTP GET/POST attack).
Cara kerja Slowloris sangat sederhana namun cerdik:
- Penyerang membuka ratusan koneksi TCP ke server kita.
- Penyerang mengirimkan header request HTTP, namun sengaja mengirimkannya secara sangat lambat (misalnya hanya mengirim satu baris header setiap 9 detik).
- Karena request belum selesai terkirim secara lengkap, Nginx terpaksa menjaga koneksi tersebut tetap terbuka di memori untuk menunggu sisa data.
- Jika penyerang melakukan ini pada ribuan koneksi bersamaan, seluruh soket worker Nginx akan terpakai penuh hanya untuk menunggu, sehingga pengguna asli tidak akan bisa terhubung sama sekali.
Berikut adalah ilustrasi bagaimana penentuan batas waktu (timeout) di Nginx dapat memutuskan koneksi lambat penyerang secara proaktif:
sequenceDiagram
autonumber
actor Attacker as Penyerang (Slowloris)
actor Nginx as Nginx Web Server
Attacker->>Nginx: TCP Handshake (Koneksi Terbuka)
Attacker->>Nginx: Kirim Header Parsial: "User-Agent: Mozilla"
Note over Nginx: client_header_timeout mulai berjalan (10 detik)
Note over Attacker: Menunggu 9 detik sebelum mengirim baris berikutnya...
Attacker->>Nginx: Kirim Header Parsial: "Accept: text/html"
Note over Nginx: Timer client_header_timeout diperbarui/direset
Note over Attacker: Menunggu 15 detik (Melebihi batas timeout!)...
Note over Nginx: Batas waktu client_header_timeout (10s) terlampaui!
Nginx->>Attacker: HTTP 408 Request Timeout / Tutup Koneksi
Note over Nginx: Socket dibebaskan kembali untuk melayani user sahKonfigurasi Timeout untuk Mitigasi Slow Attacks #
Untuk menangkal serangan ini, kita harus memperketat batas waktu tunggu (timeout) di Nginx agar koneksi yang tidak produktif dapat diputuskan secepat mungkin:
http {
# 1. Batas waktu membaca header request dari klien (Default: 60s, rekomendasi: 10s)
# Jika klien tidak menyelesaikan pengiriman header dalam 10 detik, Nginx menutup koneksi.
client_header_timeout 10s;
# 2. Batas waktu membaca body request (Default: 60s, rekomendasi: 10s)
# Berlaku untuk proses upload data atau form POST yang sengaja digantung lambat.
client_body_timeout 10s;
# 3. Batas waktu pengiriman respons kembali ke klien (Default: 60s, rekomendasi: 10s)
# Jika klien sengaja lambat membaca data yang kita kirim (Slow Read Attack).
send_timeout 10s;
# 4. Batas waktu koneksi keep-alive idle tetap terbuka (Rekomendasi: 65s)
keepalive_timeout 65s;
# 5. Jumlah request maksimum dalam satu koneksi keep-alive
keepalive_requests 1000;
}
Dengan setelan timeout 10 detik di atas, Nginx kita akan menjadi sangat responsif dalam membuang koneksi sampah yang sengaja digantung oleh penyerang, tanpa mengganggu browser pengguna sah pada koneksi internet seluler yang sedikit lambat.
Membatasi Ukuran Request (Client Request Body Limits) #
Skenario serangan DoS lainnya adalah Buffer Overflow atau Resource Exhaustion dengan cara mengirimkan request dengan isi body yang sangat raksasa (misalnya mencoba mengunggah file sampah berukuran ratusan Gigabyte) untuk memenuhi ruang penyimpanan disk sementara atau memakan memori RAM server kita.
Nginx menyediakan cara mudah untuk membatasi ukuran request masuk:
http {
# 1. Batasi ukuran maksimum body request (Default Nginx: 1m, rekomendasi: 10m)
# Sesuaikan dengan batas upload maksimum aplikasi Anda (misal 10 Megabyte)
# Jika user upload file > 10m, Nginx langsung tolak dengan status 413 Payload Too Large
client_max_body_size 10m;
# 2. Tentukan ukuran buffer memori untuk membaca body request
# Jika body request kurang dari 128k, dibaca langsung di RAM (sangat cepat).
# Jika lebih besar, Nginx akan menulisnya ke file sementara di disk (menghindari OOM).
client_body_buffer_size 128k;
# 3. Batasi buffer untuk header request klien
# Mencegah serangan Header Flooding (mengirim header berukuran raksasa)
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
}
Pembatasan Bandwidth (Bandwidth Throttling) #
Ketika server kita menyajikan file statis berukuran besar (seperti PDF laporan tahunan, file ZIP software, atau video demo), penyerang dapat menjalankan banyak bot untuk mengunduh file tersebut secara berulang kali. Hal ini dapat menghabiskan kuota bandwidth bulanan server (bandwidth exhaustion) dan membuat koneksi situs melambat bagi pengguna lain.
Kita dapat mengontrol kecepatan transfer data menggunakan kombinasi direktif limit_rate dan limit_rate_after:
server {
listen 443 ssl;
server_name example.com;
location /static/downloads/ {
# Batasi bandwidth per koneksi (misalnya maksimal 500 Kilobyte per detik)
limit_rate 500k;
# Throttling bandwidth baru aktif setelah unduhan melewati 2 Megabyte pertama
# (Mengizinkan file kecil terunduh cepat tanpa batas, tapi file besar akan direm)
limit_rate_after 2m;
root /var/www/html;
}
}
Teknik ini memastikan bahwa untuk 2MB data pertama, browser pengguna akan mengunduhnya dengan kecepatan penuh jaringan mereka (meningkatkan responsivitas awal). Begitu ukuran unduhan melebihi 2MB, Nginx secara otomatis menurunkan kecepatan transfernya menjadi konstan 500 KB/s untuk sisa file tersebut.
Tuning Kernel TCP/IP Linux (System-Level Hardening) #
Nginx berjalan di atas sistem operasi Linux, yang berarti ketangguhan Nginx dalam menghadapi serangan DoS sangat bergantung pada kinerja tumpukan (stack) TCP/IP kernel Linux di bawahnya. Ketika terjadi serangan banjir koneksi, Nginx mungkin masih memiliki memori yang cukup, tetapi kernel Linux bisa jadi sudah menyerah karena kehabisan antrean soket TCP.
Untuk memperkuat pertahanan, kita dapat melakukan tuning parameter kernel Linux dengan mengedit berkas /etc/sysctl.conf dan memuatnya menggunakan perintah sudo sysctl -p:
# /etc/sysctl.conf
# 1. Aktifkan TCP SYN Cookies (Sangat Penting untuk Mitigasi SYN Flood)
# Ketika antrean SYN penuh, kernel mulai menggunakan SYN cookies untuk memvalidasi
# koneksi tanpa perlu mengalokasikan resource memori untuk status SYN_RECV.
net.ipv4.tcp_syncookies = 1
# 2. Tingkatkan kapasitas antrean koneksi baru yang belum selesai (backlog)
net.ipv4.tcp_max_syn_backlog = 2048
# 3. Tingkatkan batas maksimum koneksi yang diantrekan oleh OS (somaxconn)
# Harus disesuaikan dengan nilai listen backlog di Nginx
net.core.somaxconn = 1024
# 4. Kurangi batas waktu pemutusan koneksi yang sudah ditutup (FIN timeout)
# Membantu membersihkan socket TIME_WAIT lebih cepat dari memori
net.ipv4.tcp_fin_timeout = 15
# 5. Aktifkan penggunaan ulang socket TIME_WAIT untuk koneksi baru
net.ipv4.tcp_tw_reuse = 1
Dengan mengombinasikan optimasi kernel di atas bersama parameter timeout Nginx, server kita akan menjadi jauh lebih tangguh dalam bertahan dari serangan banjir koneksi yang mencoba melumpuhkan tumpukan jaringan sistem.
Melindungi Upstream dari HTTP Flood (Reverse Proxy Hardening) #
Saat bertindak sebagai Reverse Proxy, salah satu jenis DoS yang paling merusak adalah ketika penyerang membanjiri server dengan request yang valid secara format, tetapi memaksa backend aplikasi melakukan kueri database yang sangat berat (heavy HTTP flood). Nginx mungkin aman, tetapi server backend (seperti Node.js, PHP-FPM, atau Java) akan kehabisan memori atau terkunci.
Selain menggunakan limit_req, kita harus mengamankan koneksi antara Nginx dan Upstream Backend agar Nginx tidak ikut terkunci saat backend melambat:
upstream backend_app {
server 127.0.0.1:8080;
# Reuses connections to upstream (sangat menghemat port socket TCP local)
keepalive 32;
}
server {
listen 443 ssl;
server_name app.example.com;
location / {
proxy_pass http://backend_app;
# 1. Batasi waktu tunggu pembentukan koneksi ke backend (Default: 60s)
# Jika backend lumpuh, jangan biarkan Nginx menggantung koneksi klien
proxy_connect_timeout 5s;
# 2. Batasi waktu tunggu pengiriman data ke backend
proxy_send_timeout 10s;
# 3. Batasi waktu tunggu membaca respons dari backend
# Jika kueri DB backend memakan waktu > 10 detik, putuskan & beri status 504
proxy_read_timeout 10s;
# Konfigurasi keepalive HTTP/1.1 untuk upstream
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
Setelan proxy_read_timeout 10s memastikan bahwa jika server backend kita lumpuh atau terkunci oleh serangan banjir kueri database, Nginx akan langsung memutuskan koneksi internal tersebut dalam 5 detik dan mengembalikan respons error HTTP 504 Gateway Timeout ke klien secara instan. Ini mencegah menumpuknya antrean koneksi di memori Nginx.
Integrasi dengan Fail2ban untuk Pemblokiran Otomatis #
Meskipun Nginx berhasil menolak request DoS atau brute force menggunakan status 429/503, request tersebut tetap sampai ke web server kita dan menggunakan daya CPU untuk memproses penolakannya. Untuk efisiensi pertahanan maksimal, kita harus memblokir IP penyerang di tingkat firewall sistem operasi (iptables/nftables) agar paket data dibuang sebelum menyentuh Nginx.
Cara standar industri untuk melakukan ini secara otomatis adalah menggunakan Fail2ban. Fail2ban adalah service latar belakang yang memantau berkas log Nginx, mendeteksi IP yang memicu pemblokiran berulang, lalu memblokir IP tersebut di firewall Linux secara dinamis.
Langkah 1: Instalasi Fail2ban #
sudo apt update
sudo apt install fail2ban -y
Langkah 2: Buat Filter Nginx Custom #
Buat berkas filter baru di /etc/fail2ban/filter.d/nginx-limit-req.conf untuk mendeteksi log rate-limiting Nginx:
# /etc/fail2ban/filter.d/nginx-limit-req.conf
[Definition]
# Cocokkan log error Nginx yang memicu "limiting requests"
failregex = limiting requests, excess:.* client: <HOST>
ignoreregex =
Langkah 3: Konfigurasi Jail di Fail2ban #
Tambahkan aturan penjara (jail) di berkas /etc/fail2ban/jail.local untuk mengaktifkan pemblokiran:
# /etc/fail2ban/jail.local
[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
# Jika IP terdeteksi memicu rate limit 5 kali dalam waktu 10 menit (600s)
maxretry = 5
findtime = 600
# Blokir IP tersebut selama 2 jam (7200s) di firewall
bantime = 7200
Nyalakan dan aktifkan service Fail2ban:
sudo systemctl restart fail2ban
sudo systemctl enable fail2ban
Dengan konfigurasi ini, jika ada bot nakal yang terus-menerus menabrak rate limit Nginx sebanyak 5 kali, Fail2ban akan langsung mendeteksinya dari log error, memanggil perintah iptables untuk memblokir IP tersebut secara penuh selama 2 jam, dan membuang semua paket data bot tersebut di tingkat kernel sistem.
Ringkasan #
- Gunakan Cloudflare untuk Volumetric DDoS: Nginx tidak dapat menangani serangan banjir trafik tingkat jaringan skala besar. Gunakan CDN/DDoS Protection eksternal untuk menyaring trafik volumetric sebelum masuk ke server.
- Batasi Koneksi per IP: Pasang direktif
limit_connpada lokasi sensitif (seperti file unduhan) untuk mencegah monopoli socket koneksi oleh download manager atau bot penyerang.- Perketat Timeout Kontrol: Atur
client_header_timeoutdanclient_body_timeoutke nilai rendah (10 detik) untuk memutuskan koneksi gantung dari serangan Slowloris secara proaktif.- Kunci
client_max_body_size: Jangan biarkan penyerang mengunggah berkas berukuran tidak terbatas yang dapat memicu kehabisan memori server, setel batas maksimal yang logis untuk sistem aplikasi kita.- Terapkan Throttling Bandwidth: Gunakan
limit_rateuntuk melindungi kapasitas jaringan server kita dari eksploitasi pengunduhan berkas raksasa secara massal.