Server hardening adalah mengunci server sebelum dipakai: pintu yang gak dibutuhkan ditutup, dan pintu yang dibutuhkan dikunci dengan benar. Bayangin pindah ke rumah kontrakan baru. Kamu ganti kunci pintu depan dengan kunci yang cuma kamu pegang, kunci master pemilik gak dipakai buat masuk dari luar, semua jendela ditutup kecuali yang memang dipakai, rumahnya diservis rutin, dan tukang yang kerja di situ cuma dapat kunci ruangan yang dia perlukan. Server juga begitu: SSH key, root gak boleh login, firewall, update otomatis, dan aplikasi yang jalan tanpa hak root.
🧪 Tebakan cepat: di server
203.0.113.10kamu menulisPasswordAuthentication no, lalu restart SSH. Tapi public key laptopmu belum pernah dipasang di server. Waktu kamu login lagi, apa yang terjadi? Jawabannya ada di bagian "Pintu SSH: key, bukan password".
Enam hal yang dicek
Di Lab, server web-01 (alamat 203.0.113.10, user deploy) diaudit dengan enam pemeriksaan. Tiap pemeriksaan gagal di server baru, dan lulus begitu konfigurasinya dibetulkan:
| Pemeriksaan | Server baru (gagal) | Sesudah hardening (lulus) |
|---|---|---|
| Login SSH pakai password | PasswordAuthentication yes |
PasswordAuthentication no |
| Root login lewat SSH | PermitRootLogin yes |
PermitRootLogin no |
| Firewall | Status: inactive |
aktif, default deny incoming |
| Port yang terbuka | 22, 80, 443, 3306 | cuma 22, 80, 443 |
| Update keamanan | manual, kalau ingat | unattended-upgrades aktif |
| User aplikasi | root |
deploy (tanpa hak root) |
Dua prinsip di balik tabel ini: attack surface (permukaan serangan, semua pintu yang bisa dicoba orang) dibuat sekecil mungkin, dan least privilege (hak paling kecil): tiap user dan program cuma dapat hak yang benar-benar dia perlukan.
Pintu SSH: key, bukan password
SSH adalah cara kamu masuk ke terminal server dari jauh. Password bisa ditebak: bot di internet mencoba ribuan kombinasi tiap hari ke port 22 (ini namanya brute force). SSH key gak bisa ditebak begitu. Kuncinya sepasang: private key tetap di laptopmu dan gak pernah dikirim ke mana pun, public key ditaruh di server, di file ~/.ssh/authorized_keys. Server menguji bahwa kamu memegang private key-nya tanpa private key itu pernah lewat jaringan.
Urutannya penting: pasang key dulu, baru matikan password.
# Di laptop: bikin sepasang key, lalu kirim public key-nya ke server
ssh-keygen -t ed25519
ssh-copy-id [email protected]
Setelah login pakai key berhasil, ubah /etc/ssh/sshd_config di server:
# /etc/ssh/sshd_config
PasswordAuthentication no # login cuma boleh pakai key
PermitRootLogin no # user root gak boleh login lewat SSH
sudo sshd -t # cek penulisan config, diam kalau benar
sudo systemctl restart ssh # di Ubuntu; distro lain: sshd
PasswordAuthentication nomenutup login pakai password. Bot yang menebak password langsung ditolak.PermitRootLogin nomenutup root sama sekali. Kamu masuk sebagaideploy, lalu pakaisudountuk perintah admin, jadi tiap tindakan tercatat atas nama user yang jelas. Nilaiprohibit-passwordjuga sering dipakai: root masih boleh masuk, tapi cuma pakai key.sshd -tmengetes config sebelum restart. Salah ketik di config bisa bikin SSH gak mau jalan.
Kalau public key belum dipasang, login berikutnya ditolak, karena password sudah gak diterima dan key-nya gak ada:
$ ssh [email protected]
[email protected]: Permission denied (publickey).
Kamu terkunci di luar servermu sendiri. Itu jawaban tebakannya. Di VPS biasanya masih ada konsol darurat dari penyedia, tapi lebih aman gak sampai ke situ.
Firewall: tolak semua, buka yang perlu
Firewall memutuskan koneksi mana yang boleh masuk. Di Ubuntu alatnya UFW (Uncomplicated Firewall), lapisan sederhana di atas iptables. UFW sudah terpasang, tapi belum aktif. Aturannya: tolak semua yang masuk, lalu buka cuma port yang dipakai.
sudo ufw default deny incoming # semua koneksi masuk ditolak
sudo ufw default allow outgoing # server boleh keluar (update, API)
sudo ufw allow 22/tcp # SSH, buka SEBELUM enable
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
sudo ufw status verbose
Hasil ufw status verbose di Lab:
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
Default: deny (incoming)artinya port yang gak disebut otomatis tertutup.- Port
3306(MySQL) gak ada di daftar. Database cukup didengar aplikasi di server yang sama, jadi gak perlu dibuka ke internet. - Baris
(v6)adalah aturan yang sama untuk alamat IPv6.
Update otomatis dan user tanpa root
Banyak serangan memakai celah yang patch-nya sudah keluar, cuma servernya belum di-update. unattended-upgrades memasang update keamanan otomatis tiap hari:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Aplikasimu juga jangan jalan sebagai root. Kalau ada celah di aplikasi, penyerang dapat hak yang sama dengan proses itu. Jalankan sebagai user biasa lewat systemd:
# /etc/systemd/system/app.service
[Service]
User=deploy
ExecStart=/usr/bin/node /srv/app/server.js
User=deploybikin proses jalan sebagaideploy. Celah di aplikasi cuma dapat hakdeploy, bukan seluruh server.- Aplikasinya mendengar port tinggi seperti
3000, dan Nginx di port 80 dan 443 meneruskan request ke situ. Port di bawah 1024 butuh hak khusus, dan itu bukan alasan menjalankan aplikasi sebagai root.
⚠️ Jebakan yang sering ketemu
- Mematikan password sebelum key terpasang. Hasilnya
Permission denied (publickey).dan kamu terkunci. Biarkan sesi SSH yang lama tetap terbuka, lalu tes login di terminal kedua sebelum menutupnya. ufw enablesebelumufw allow 22/tcp. Firewall menolak SSH baru, termasuk punyamu. Buka port SSH dulu.- Config di
sshd_config.dmengalahkan file utama. Di Ubuntu, file di/etc/ssh/sshd_config.d/dibaca duluan, dan untuk tiap pengaturan sshd memakai nilai pertama yang ditemuinya. Di beberapa image cloud ada file di situ berisiPasswordAuthentication yes. Cek nilai yang benar-benar berlaku dengansudo sshd -T | grep -i passwordauthentication. - Membuka port database ke internet.
3306atau5432yang terbuka keAnywheremengundang brute force ke database. Tutup di firewall, dan biarkan database mendengar di127.0.0.1saja.
TL;DR: Server hardening = memperkecil attack surface dan memberi hak sekecil mungkin. Pakai SSH key (private key di laptop, public key di authorized_keys server), lalu di /etc/ssh/sshd_config set PasswordAuthentication no dan PermitRootLogin no (atau prohibit-password), tes dengan sshd -t, dan pasang key dulu supaya gak terkunci. Firewall di Ubuntu pakai UFW: default deny incoming, buka cuma 22, 80, 443 (SSH dibuka sebelum ufw enable), database jangan dibuka. Aktifkan unattended-upgrades untuk update keamanan otomatis, dan jalankan aplikasi sebagai user biasa (User=deploy), bukan root.