Pagi ini aku lihat CPU nginx di server kelihatan tinggi. Refleks pertama: reload. Dan itu langkah yang salah urutan, karena begitu reload, kondisi yang mau diselidiki ikut hilang. Catatan ini soal apa yang akhirnya ketemu, apa yang diperbaiki, dan satu kebiasaan yang mau kuubah.
Yang Ketemu Setelah Reload
Sesudah reload, CPU server sebenarnya sudah tenang (97% idle). Tapi satu worker nginx masih makan sekitar 5–6% dari satu core, dan itu tidak wajar untuk server yang traffic situsnya kecil. Access log-nya jelas: dari 200 baris terbaru, 199 berasal dari satu IP (47.128.x.x), semuanya GET /robots.txt, sekitar 15 request per detik, ke hostname situs lama yang sudah kumatikan.
Request itu jatuh ke server block default dan dijawab return 444 (koneksi di-drop), jadi secara HTTP murah banget. Masalahnya ada di port 443: sebelum nginx sempat menjawab apa pun, harus selesai dulu TLS handshake, dan blok default masih mengirim sertifikat self-signed. Lima belas handshake per detik dari satu bot, terus-menerus, itulah yang menghabiskan CPU.
Fix: Tolak Handshake-nya
Nginx (sejak 1.19.4) punya ssl_reject_handshake. Di blok default 443, dua baris sertifikat self-signed kuganti satu baris ini:
server {
listen 443 ssl default_server;
server_name _;
# Tolak handshake TLS untuk host/SNI yang tidak dikenal
ssl_reject_handshake on;
return 444;
}
Handshake untuk hostname yang tidak dikenal sekarang ditolak di tahap paling awal, tanpa kirim sertifikat dan tanpa memproses request HTTP. Situs yang sah tidak terpengaruh, karena masing-masing punya server block dan SNI sendiri.
Langkahnya tetap hati-hati: simpan salinan file lama dan diff-nya, tulis config baru, nginx -t, baru reload. Hasilnya:
- semua worker nginx 0% CPU,
- tidak ada lagi baris log dari bot itu (handshake-nya mati sebelum sampai ke access log),
- dua situs yang kucek sesudahnya tetap membalas 200.
Satu hal yang perlu jujur kusebut: ini mengurangi biaya per request, bukan menghentikan botnya. Dia masih bisa terus mengetuk. IP-nya sengaja belum kublok di firewall, itu keputusan terpisah.
Biar Lain Kali Ada Datanya: sysstat
Yang bikin penyelidikan ini setengah buta: tidak ada riwayat CPU. Waktu aku lihat lonjakan, datanya sudah lewat. Paket sysstat ternyata sudah terpasang, cuma mati: ENABLED="false" di /etc/default/sysstat. Mengubahnya butuh hak root, jadi bagian ini kukerjakan manual:
sudo sed -i 's/^ENABLED="false"/ENABLED="true"/' /etc/default/sysstat
sudo systemctl enable --now sysstat
Tiga hal yang baru kutahu atau kukoreksi sendiri sepanjang jalan:
- Pengumpulan datanya lewat
sysstat-collect.timer, bukan entri cron di/etc/cron.d/sysstat. Aku sempat menunggu slot cron (menit 5, 15, 25…) dan data tidak muncul, padahal yang bekerja timer di menit 00, 10, 20. - Retensi default cuma 7 hari (
HISTORY=7), bukan 28 seperti perkiraanku. - Sampel pertama cuma baseline. Habis diaktifkan,
sar -uhanya menampilkan barisLINUX RESTART. Baris CPU baru muncul di sampel kedua, 10 menit kemudian, sebagai rata-rata interval di antara keduanya. Awalnya kukira ada yang rusak.
Sampel yang masuk: idle 98,21%, load average 0,12 / 0,05 / 0,03. Resolusinya 10 menit, jadi lonjakan yang cuma beberapa detik tetap tidak terlihat, tapi yang berlangsung beberapa menit kelihatan sebagai penurunan %idle.
Pelajaran
- Ukur dulu, baru reload. Kalau ada lonjakan, ambil dulu
topdan potongan log selagi kondisinya masih ada. Reload mengganti worker, bukan menyembuhkan akar masalah, dan bisa menghapus bukti. - Hostname yang sudah mati tetap menarik bot. Situs yang kumatikan masih terus diketuk, dan biayanya muncul di tempat yang tidak terduga: handshake TLS, bukan HTTP.
- Aktifkan pencatatan sebelum butuh.
sysstatgratis dan kecil; menyalakannya setelah ada masalah itu terlambat satu kejadian.