Lewati ke konten
NTHL.me

Minimal Debian 13 VPS Setup

VPS baru sering memberi kesan aman karena isinya masih sedikit. Kenyataannya justru sebaliknya. Pada fase inilah kita belum tahu konfigurasi apa yang ditinggalkan image provider, service apa yang mendengarkan jaringan, atau metode login apa yang masih terbuka. Panduan ini menyiapkan baseline Debian yang sederhana. Sistem diperbarui, waktu disinkronkan, firewall diaktifkan, SSH dipaksa memakai key, pembaruan keamanan dibuat otomatis, lalu seluruh hasilnya diperiksa lagi.

Fokus utamanya adalah Debian 13 Trixie. Sebagian besar langkah juga tetap berlaku untuk Debian 12 Bookworm, tetapi contoh di bawah mengikuti perilaku Debian 13. Semua perintah server dijalankan sebagai root. Model ini cocok untuk VPS milik satu administrator, meskipun server bersama atau lingkungan produksi yang lebih besar sebaiknya memakai akun admin terpisah dengan sudo.

Minimal Debian 13 VPS Setup
Sebelum mulai. Pastikan provider menyediakan recovery console atau serial console, dan pastikan Anda memiliki SSH public key yang benar-benar dapat dipakai. Hardening remote access tanpa jalur pemulihan adalah cara yang sangat efisien untuk mengunci diri sendiri dari server.

1. Perbarui sistem lebih dulu

Jangan mengeraskan konfigurasi di atas paket yang sudah tertinggal. Mulailah dari package index yang baru dan selesaikan upgrade sistem sebelum mengubah firewall atau SSH.

apt update
apt full-upgrade -y
apt autoremove --purge -y
apt clean

Jika kernel, libc, systemd, atau komponen inti ikut berubah, reboot lebih awal biasanya lebih bersih daripada melanjutkan konfigurasi di atas proses lama yang belum dimuat ulang.

2. Sinkronkan waktu

Waktu server bukan sekadar kosmetik. Log insiden, sertifikat TLS, TOTP, rotasi log, dan banyak mekanisme autentikasi bergantung pada jam yang konsisten. Untuk server, UTC biasanya paling mudah dipelihara karena tidak terpengaruh daylight-saving atau lokasi operator.

timedatectl set-timezone UTC
timedatectl set-ntp true
timedatectl status

Jika image provider tidak memasang layanan sinkronisasi waktu, instal systemd-timesyncd atau gunakan daemon NTP lain yang memang sudah menjadi bagian dari stack Anda. Jangan menjalankan dua daemon waktu sekaligus.

3. Pasang alat dasar

VPS minimal sengaja datang dengan sedikit utilitas. Beberapa paket berikut cukup untuk administrasi sehari-hari tanpa mengubah server menjadi gudang software.

apt install -y curl wget git unzip htop ca-certificates gnupg lsb-release needrestart

needrestart membantu menunjukkan service atau proses yang masih memakai library lama setelah upgrade. Ia bukan alat keamanan dengan sendirinya, tetapi berguna untuk mengetahui kapan sebuah update belum benar-benar aktif hanya karena paketnya sudah selesai dipasang.

4. Batasi pintu masuk dengan UFW

Firewall yang sehat dimulai dari prinsip sederhana. Koneksi masuk ditolak kecuali ada alasan jelas untuk membukanya. Untuk SSH, gunakan rate limit agar koneksi berulang dari sumber yang sama diperlambat. HTTP dan HTTPS baru dibuka ketika server memang menjalankan web service.

apt install -y ufw

ufw default deny incoming
ufw default allow outgoing

ufw limit 22/tcp

# Buka hanya bila memang diperlukan:
# ufw allow 80/tcp
# ufw allow 443/tcp

ufw enable
ufw status verbose
Jangan menyalakan UFW sebelum memastikan port SSH yang benar sudah diizinkan. Jika SSH berjalan pada port selain 22, ganti rule di atas dengan port tersebut. Periksa juga firewall milik provider; firewall di guest OS dan firewall di panel provider adalah dua lapisan berbeda.

5. Tambahkan Fail2Ban

Setelah password login dimatikan, Fail2Ban bukan lagi garis pertahanan utama SSH. Namun ia tetap berguna untuk menahan scanner yang berulang, mengurangi noise pada log, dan memperlambat sumber yang terus mencoba autentikasi.

apt install -y fail2ban

Buat konfigurasi lokal agar perubahan tidak menyentuh file bawaan paket:

cat > /etc/fail2ban/jail.local <<'EOF'
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5

bantime.increment = true
bantime.factor    = 2
bantime.maxtime   = 1w

[sshd]
enabled = true
backend = systemd
EOF
fail2ban-client -t
systemctl enable --now fail2ban
fail2ban-client status
fail2ban-client status sshd

Progressive banning membuat pelanggar berulang menerima masa ban yang semakin panjang. Tetap anggap ini sebagai rem tambahan, bukan pengganti public-key authentication atau firewall.

6. Aktifkan pembaruan keamanan otomatis

Server yang hanya diam di internet tetap menua. Celah keamanan baru muncul pada software yang kemarin dianggap aman. Karena itu patch rutin lebih berharga daripada konfigurasi hardening yang rumit tetapi tidak pernah diperbarui.

apt install -y unattended-upgrades apt-listchanges

cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
EOF
systemctl list-timers apt-daily.timer apt-daily-upgrade.timer
unattended-upgrade --dry-run

unattended-upgrades bekerja melalui mekanisme APT dan timer systemd. Dry run memberi kesempatan untuk melihat perilakunya sebelum kita mempercayakan update otomatis kepada server.

7. Hardening kernel dan jaringan—secukupnya

Internet penuh dengan daftar sysctl yang menjanjikan “hardening maksimal”. Masalahnya, sebagian parameter itu hanya benar untuk topologi tertentu. Baseline yang baik seharusnya mengurangi perilaku jaringan yang tidak dibutuhkan tanpa mematahkan routing, VPN, container, atau service yang kelak dipasang.

Simpan pengaturan lokal di /etc/sysctl.d/. Ini lebih jelas pada sistem modern yang memakai systemd-sysctl saat boot.

cat > /etc/sysctl.d/90-nthl-hardening.conf <<'EOF'
# TCP SYN flood fallback
net.ipv4.tcp_syncookies = 1

# Do not accept ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

# Do not send redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Reject source-routed packets
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0

# Ignore broadcast ICMP echo requests
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Do not create setuid core dumps
fs.suid_dumpable = 0
EOF

sysctl --system
Jangan menyalin parameter routing secara buta. net.ipv4.ip_forward=0, net.ipv6.conf.all.forwarding=0, dan strict rp_filter=1 dapat menjadi masalah pada WireGuard, container networking, multi-homed host, NAT, atau routing asimetris. Gunakan hanya jika Anda memahami topologi server.

8. Kunci SSH menjadi key-only

Di tahap ini firewall sudah aktif dan server sudah diperbarui. Sekarang kita menghapus bagian paling mudah diserang dari SSH yaitu password login. Root masih boleh masuk, tetapi hanya dengan public key. Ini mempertahankan workflow VPS sederhana sambil menutup autentikasi password dan keyboard-interactive.

Pastikan key bekerja sebelum menyentuh konfigurasi

Jalankan bagian ini dari komputer lokal. Jika provider sudah memasang key Anda saat provisioning, cukup uji login. Jika belum, buat key Ed25519 dan salin public key ke server.

ssh-keygen -t ed25519
ssh-copy-id root@your-server-ip
ssh root@your-server-ip
Jika root password login sudah dinonaktifkan oleh provider, ssh-copy-id mungkin tidak dapat dipakai. Dalam kasus itu, pasang public key melalui control panel provider, cloud-init, recovery console, atau mekanisme provisioning yang tersedia. Untuk create SSH Keys disini saya menggunakan windows powershell.

Periksa konfigurasi efektif OpenSSH

Debian memuat file /etc/ssh/sshd_config.d/*.conf di awal konfigurasi. OpenSSH memakai nilai pertama yang ditemukan untuk sebagian besar directive, sehingga nama file bukan sekadar kosmetik. Drop-in yang datang lebih awal dapat mengalahkan file yang datang belakangan.

ls -la /etc/ssh/sshd_config.d/
grep -RniE '^(PermitRootLogin|PasswordAuthentication|KbdInteractiveAuthentication|X11Forwarding)' /etc/ssh/sshd_config /etc/ssh/sshd_config.d 2>/dev/null

sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|x11forwarding)'

Buat policy NTHL sebagai drop-in awal. Nama 00-nthl-hardening.conf dipilih agar biasanya dibaca sebelum drop-in provider seperti 50-cloud-init.conf. Hasil akhirnya tetap harus diverifikasi dengan sshd -T. Jangan mengandalkan nama file saja.

cat > /etc/ssh/sshd_config.d/00-nthl-hardening.conf <<'EOF'
PermitRootLogin prohibit-password
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no

MaxAuthTries 3
X11Forwarding no

ClientAliveInterval 300
ClientAliveCountMax 2
EOF
sshd -t

sshd -T | grep -E '^(permitrootlogin|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|maxauthtries|x11forwarding|clientaliveinterval|clientalivecountmax)'

systemctl reload ssh

Nilai efektif yang kita harapkan setidaknya mencakup:

permitrootlogin prohibit-password
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
maxauthtries 3
x11forwarding no
clientaliveinterval 300
clientalivecountmax 2
Jangan tutup sesi SSH yang sedang aktif. Buka terminal kedua, login ulang menggunakan key, dan pastikan sesi baru berhasil sebelum keluar dari sesi lama. Selalu jalankan sshd -t sebelum reload.

9. Audit permukaan serangan

Hardening sering terlalu fokus pada file konfigurasi dan lupa melihat kenyataan yang paling sederhana. Proses apa yang benar-benar berjalan, dan port apa yang benar-benar mendengarkan jaringan. Satu service yang tidak dibutuhkan lebih baik dimatikan daripada “diamankan” dengan sepuluh parameter tambahan.

ss -tulpen

systemctl --type=service --state=running --no-pager
systemctl --failed --no-pager

ufw status numbered

Pada VPS minimal, idealnya hanya service yang memang digunakan yang terlihat listening. Jangan mematikan service hanya karena namanya asing. Cari tahu fungsinya lebih dulu, terutama service yang berasal dari image atau agent provider.

10. Buat VPS Check

Setelah hardening selesai, kita membutuhkan satu cara untuk melihat keadaan server tanpa harus mengingat belasan command. Script berikut hanya membaca status. Ia tidak mengubah konfigurasi. Tujuannya bukan menggantikan monitoring, melainkan memberi pemeriksaan cepat setelah reboot, upgrade besar, atau perubahan jaringan.

cat > /usr/local/sbin/vps-check <<'SCRIPT'
#!/usr/bin/env bash
set -u

GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'

has_cmd() {
  command -v "$1" >/dev/null 2>&1
}

section() {
  printf '\n%b== %s ==%b\n' "$YELLOW" "$1" "$NC"
}

status_pct() {
  local value="${1:-0}"

  if [ "$value" -ge 90 ]; then
    printf '%bHIGH%b' "$RED" "$NC"
  elif [ "$value" -ge 70 ]; then
    printf '%bMODERATE%b' "$YELLOW" "$NC"
  else
    printf '%bNORMAL%b' "$GREEN" "$NC"
  fi
}

section 'SYSTEM'
printf 'Hostname: %s\n' "$(hostname)"
printf 'Kernel: %s\n' "$(uname -r)"
printf 'Uptime: %s\n' "$(uptime -p)"

section 'RESOURCES'
MEM_TOTAL=$(free -m | awk '/^Mem:/ {print $2}')
MEM_USED=$(free -m | awk '/^Mem:/ {print $3}')
MEM_PCT=$((MEM_USED * 100 / MEM_TOTAL))
ROOT_USE=$(df -P / | awk 'NR==2 {gsub(/%/,"",$5); print $5}')
CPU_USAGE=$(LC_ALL=C top -bn1 | awk '
  /Cpu\(s\)/ {
    for (i=1; i<=NF; i++) {
      if ($i ~ /^id/) {
        printf "%.0f", 100-$(i-1)
        exit
      }
    }
  }')

printf 'CPU: %s%% - %s\n' "$CPU_USAGE" "$(status_pct "$CPU_USAGE")"
printf 'RAM: %s%% - %s\n' "$MEM_PCT" "$(status_pct "$MEM_PCT")"
printf 'Root disk: %s%% - %s\n' "$ROOT_USE" "$(status_pct "$ROOT_USE")"

section 'FIREWALL & FAIL2BAN'
if has_cmd ufw; then
  ufw status
else
  echo 'UFW: not installed'
fi

if has_cmd fail2ban-client; then
  fail2ban-client status
  fail2ban-client status sshd 2>/dev/null | grep -E 'Currently banned|Total banned' || true
else
  echo 'Fail2Ban: not installed'
fi

section 'SSH POLICY'
if has_cmd sshd; then
  sshd -T 2>/dev/null | grep -E \
    '^(permitrootlogin|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|maxauthtries|x11forwarding)'
else
  echo 'sshd: not found'
fi

section 'TIME'
if has_cmd timedatectl; then
  printf 'NTP synchronized: %s\n' "$(timedatectl show -p NTPSynchronized --value)"
fi

section 'FAILED UNITS'
FAILED_UNITS=$(systemctl --failed --no-legend --no-pager 2>/dev/null || true)
if [ -n "$FAILED_UNITS" ]; then
  echo "$FAILED_UNITS"
else
  echo 'None'
fi

section 'LISTENING PORTS'
ss -tulpen

section 'APT'
if systemctl list-unit-files apt-daily-upgrade.timer >/dev/null 2>&1; then
  printf 'apt-daily-upgrade.timer: %s / %s\n' \
    "$(systemctl is-enabled apt-daily-upgrade.timer 2>/dev/null || true)" \
    "$(systemctl is-active apt-daily-upgrade.timer 2>/dev/null || true)"
fi

PENDING=$(apt-get -s upgrade 2>/dev/null | awk '/^Inst/ {count++} END {print count+0}')
printf 'Pending package upgrades: %s\n' "$PENDING"
SCRIPT

chmod 750 /usr/local/sbin/vps-check
vps-check

Angka CPU, RAM, dan disk pada script ini adalah indikator cepat, bukan sistem observability. Untuk server yang benar-benar penting, gunakan monitoring dengan histori, alert, dan metrik yang dapat dibandingkan dari waktu ke waktu.

11. Reboot dan periksa sekali lagi

Konfigurasi belum benar-benar selesai sebelum kita tahu ia tetap bekerja setelah boot baru. Reboot server, login kembali menggunakan SSH key, lalu jalankan pemeriksaan.

reboot

Setelah server kembali:

vps-check
  • SSH key berhasil login dan password authentication tetap mati.
  • UFW aktif dengan hanya port yang memang diperlukan.
  • Fail2Ban berjalan tanpa configuration error.
  • Jam server tersinkronisasi.
  • Tidak ada failed systemd unit yang tidak dijelaskan.
  • Daftar listening port sesuai fungsi server.
  • Timer pembaruan otomatis aktif.

Penutup

Tidak ada konfigurasi yang membuat VPS kebal. Hardening hanya mengubah keadaan awal yang longgar menjadi sistem yang lebih disiplin. Lebih sedikit pintu, lebih sedikit cara masuk, lebih sedikit service yang dibiarkan tanpa alasan, dan lebih banyak jejak ketika sesuatu berjalan tidak semestinya.

Terakhir Diperbaharui:
Berkomentarlah dengan santun dan tetap pada topik. Komentar berisi spam, tautan promosi, atau ujaran kebencian dapat dihapus. Komentar baru mungkin tampil setelah dimoderasi.

Komentar