VPS untuk Laravel: Spesifikasi, OS, dan Hardening Awal


 

Membeli VPS itu gampang. Yang sering bikin pusing justru langkah sesudahnya: server sudah aktif, IP sudah di tangan, tapi belum ada gambaran jelas apa yang harus diamankan dulu sebelum aplikasi Laravel apa pun mendarat di sana. Banyak yang langsung loncat ke instalasi Nginx dan PHP, lalu baru sadar belakangan kalau login root masih pakai kata sandi, firewall belum menyala, dan tidak ada yang memblokir percobaan login berulang dari bot.

Artikel ini adalah bagian pertama seri Deploy Laravel ke VPS. Fokusnya satu: menyiapkan fondasi server yang rapi. Bukan instalasi aplikasinya — itu bagian artikel kedua dan seterusnya. Yang Anda kerjakan di sini: memilih spesifikasi yang masuk akal, memasang Ubuntu LTS, membuat user non-root, memindahkan login ke SSH key, menyalakan firewall, memasang fail2ban, dan menyiapkan swap. Selesai membaca, Anda punya server yang siap menerima Nginx dan PHP-FPM tanpa perlu mengulang pekerjaan dasarnya.

Pilih spesifikasi yang realistis, bukan yang paling murah atau paling besar

Spesifikasi VPS untuk Laravel paling gampang ditentukan dari tiga hal: berapa banyak proses PHP yang berjalan bersamaan, apakah database dan Redis ikut tinggal di server yang sama, dan seberapa besar trafik yang Anda perkirakan di tiga bulan pertama. Untuk aplikasi kecil sampai menengah — panel admin, API internal, situs company profile dengan form, toko online yang baru jalan — titik awal yang sehat adalah 2 vCPU, RAM 4 GB, dan disk SSD 50 GB.

Kenapa 4 GB, bukan 2 GB? Karena di server yang sama biasanya ada Nginx, PHP-FPM dengan beberapa worker, database, dan queue worker. Masing-masing mengambil jatah memori sendiri. Di RAM 2 GB, satu lonjakan worker PHP atau satu query database yang berat sudah cukup membuat sistem mulai memakai swap secara agresif, dan respons aplikasi ikut melambat. Sebaliknya, langsung mengambil 8 vCPU dan 16 GB untuk aplikasi yang pengunjungnya masih puluhan per hari hanya membakar biaya bulanan tanpa manfaat yang terasa.

Patokan kasarnya seperti ini: aplikasi kecil dengan database di server yang sama mulai dari 2 vCPU dan 4 GB. Kalau queue worker jalan terus, Redis dipakai untuk cache dan antrean, atau ada proses impor data berkala, naikkan ke 4 vCPU dan 8 GB. Kalau trafik sudah ribuan permintaan per jam dan response time mulai goyah, saatnya memisahkan database ke server sendiri atau menambah worker — bukan sekadar menaikkan spesifikasi secara membabi buta. Selalu cek dulu apa yang penuh: CPU, RAM, atau disk. Perintah htop dan df -h memberi jawaban itu dalam hitungan detik, dan keputusan upgrade jadi berdasar angka, bukan firasat.

Soal lokasi server, pilih region yang dekat dengan mayoritas pengguna Anda. Untuk pengguna di Indonesia, region Singapura biasanya memberi latensi yang jauh lebih baik daripada region Eropa atau Amerika. Selisih puluhan milidetik ini terasa di setiap halaman yang memuat banyak aset dan permintaan API.

Ubuntu LTS sebagai sistem operasi

Untuk seri ini, sistem operasinya Ubuntu 24.04 LTS (Noble Numbat). Alasan pemilihannya praktis: rilis LTS mendapat dukungan standar selama lima tahun, repositori paketnya membawa PHP 8.3 yang masih relevan untuk Laravel, dan hampir semua panduan server mengasumsikan perintah apt serta struktur berkas Ubuntu. Menghindari rilis non-LTS berarti Anda tidak dipaksa upgrade besar setiap sembilan bulan hanya demi menjaga dukungan keamanan.

Catatan penting soal PHP: dokumentasi deployment Laravel mensyaratkan PHP minimal 8.2 beserta ekstensi Ctype, cURL, DOM, Fileinfo, Filter, Hash, Mbstring, OpenSSL, PCRE, PDO, Session, Tokenizer, dan XML. PHP 8.3 bawaan Ubuntu 24.04 melewati lantai itu, jadi Anda tidak perlu menambah repositori pihak ketiga hanya untuk mendapatkan versi PHP yang cukup baru. Satu hal yang wajib dilakukan sebelum instalasi apa pun: jalankan pembaruan paket. Pada Oktober 2026, Ubuntu merilis perbaikan keamanan PHP (USN-8948-1) untuk kerentanan PHP2Shell, dan paket PHP 8.3 yang sudah diperbaiki ditandai 8.3.6-0ubuntu0.24.04.13. Menjalankan apt upgrade sebelum instalasi memastikan Anda tidak memasang versi yang masih rentan.

Masuk pertama kali ke server biasanya masih sebagai root lewat kata sandi dari panel penyedia VPS. Itu wajar untuk langkah awal, tapi jangan jadikan itu kondisi permanen. Semua langkah di bawah ini dikerjakan dari sesi root tersebut, lalu diakhiri dengan mematikan login root dan login kata sandi.

Langkah 1: Perbarui sistem dan pasang perkakas dasar

Perintah pertama di server baru selalu pembaruan. Jangan memasang apa pun sebelum daftar paketnya segar:

apt update && apt upgrade -y
apt install -y curl wget git unzip htop ufw fail2ban software-properties-common

Hasil yang diharapkan: proses upgrade selesai tanpa galat, dan perintah ufw --version serta fail2ban-client --version menampilkan nomor versinya. Kalau ada paket yang tertahan (held back), jalankan apt list --upgradable dan periksa apakah paket itu terkait kernel — kernel baru biasanya baru aktif setelah reboot, yang bisa Anda tunda sampai seluruh fondasi selesai.

Sekalian atur zona waktu ke Asia/Jakarta supaya stempel waktu log gampang dibaca:

timedatectl set-timezone Asia/Jakarta
timedatectl

Hasil yang diharapkan: baris Time zone menampilkan Asia/Jakarta (WIB, +0700).

Langkah 2: Buat user non-root bernama deploy

Bekerja harian sebagai root itu seperti membawa kunci utama ke mana-mana: satu perintah yang salah ketik bisa menghapus berkas sistem. User deploy akan menjadi akun kerja Anda — pemilik proses deploy, pemilik direktori aplikasi, dan satu-satunya akun yang boleh masuk lewat SSH nantinya.

adduser deploy
usermod -aG sudo deploy

Perintah adduser bersifat interaktif: ia akan meminta kata sandi untuk user baru dan beberapa data opsional (nama lengkap dan sejenisnya) yang boleh dikosongkan dengan Enter. Setelah itu, verifikasi keanggotaannya:

id deploy

Hasil yang diharapkan: keluaran memuat groups=...sudo.... Opsi -aG penting — tanpa -a, perintah usermod -G sudo akan mengganti seluruh daftar grup user, bukan menambahkannya.

Langkah 3: Pindahkan login ke SSH key

Kata sandi bisa ditebak bot lewat percobaan berulang. Kunci SSH tidak. Kalau Anda belum punya key pair di komputer lokal, buat dulu di komputer Anda (bukan di server):

ssh-keygen -t ed25519 -C "deploy-vps-laravel"

Terima lokasi bawaan (~/.ssh/id_ed25519) dan isi passphrase — passphrase ini lapisan tambahan kalau berkas kunci di laptop Anda sampai bocor. Kemudian kirim kunci publiknya ke server:

ssh-copy-id deploy@IP_SERVER_ANDA

Ganti IP_SERVER_ANDA dengan IP VPS Anda. Setelah itu, uji login sebagai user baru dari terminal baru, sementara sesi root lama tetap dibiarkan terbuka:

ssh deploy@IP_SERVER_ANDA

Kalau login berhasil tanpa meminta kata sandi user (hanya passphrase kunci, bila Anda memasangnya), kunci sudah bekerja. Sesi root lama jangan ditutup dulu — ia adalah jalan kembali Anda kalau ada yang meleset di langkah hardening SSH berikutnya.

Sekiranya ssh-copy-id tidak tersedia di komputer Anda, salin manual isi ~/.ssh/id_ed25519.pub dari komputer lokal ke berkas /home/deploy/.ssh/authorized_keys di server, lalu kunci permission-nya:

mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh

Permission ini bukan formalitas. SSH akan mengabaikan berkas authorized_keys yang permission-nya terlalu longgar, dan Anda akan terkunci di luar tanpa pesan galat yang jelas.

Langkah 4: Kunci konfigurasi SSH

Sekarang perketat daemon SSH. Buka berkas /etc/ssh/sshd_config dengan editor Anda:

nano /etc/ssh/sshd_config

Pastikan tiga baris berikut ada dan tidak diawali tanda #:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

Artinya: root tidak boleh login lewat SSH sama sekali, kata sandi tidak diterima, hanya kunci yang boleh masuk. Sebelum me-restart layanannya, uji sintaksnya:

sshd -t

Kalau tidak ada keluaran, sintaksnya bersih. Kalau ada galat, perbaiki dulu — jangan restart dengan konfigurasi rusak. Kemudian:

systemctl restart ssh

Hasil yang diharapkan: systemctl status ssh menampilkan active (running). Sekarang buka terminal baru dan coba dua hal: login sebagai deploy (harus berhasil) dan login sebagai root (harus ditolak). Baru setelah login deploy terbukti jalan, Anda boleh menutup sesi root lama. Urutan ini yang menyelamatkan Anda dari insiden klasik: mematikan kata sandi, lalu sadar kunci belum terpasang dengan benar.

Kesalahan umum di langkah ini: mengubah port SSH ke angka acak dengan asumsi itu "lebih aman". Mengganti port hanya mengurangi kebisingan log dari bot, bukan menambah keamanan yang berarti, dan ia menambah satu hal lagi yang bisa salah di firewall, fail2ban, dan konfigurasi deploy Anda nanti. Port 22 yang dijaga kunci, firewall, dan fail2ban sudah cukup untuk fondasi ini.

Langkah 5: Nyalakan UFW sebelum mengaktifkan apa pun

UFW adalah firewall bawaan Ubuntu. Aturan mainnya: tolak semua koneksi masuk secara default, lalu buka hanya yang dibutuhkan. Urutan perintahnya penting — izinkan SSH dulu, baru aktifkan firewall. Membalik urutannya berarti mengunci diri sendiri di luar server:

ufw allow OpenSSH
ufw enable
ufw status verbose

Hasil yang diharapkan: status active, aturan OpenSSH tercantum sebagai ALLOW, dan kebijakan default deny (incoming) serta allow (outgoing). Perintah ufw allow OpenSSH memakai profil aplikasi bernama OpenSSH, yang setara dengan membuka port 22/TCP. Selama seri ini berjalan, Anda akan menambahkan Nginx Full (port 80 dan 443) di artikel berikutnya — setelah Nginx terpasang dan terbukti menjawab lewat HTTP.

Kesalahan umum: mengaktifkan UFW dari dalam sesi SSH tanpa aturan SSH, lalu panik. Kalau itu terjadi, satu-satunya jalan pulang adalah konsol darurat dari panel penyedia VPS. Jadi biasakan memeriksa ufw status sebelum menutup sesi apa pun setelah mengubah aturan firewall.

Langkah 6: Pasang fail2ban untuk memblokir percobaan login berulang

Firewall membatasi port apa yang terbuka; fail2ban membatasi siapa yang boleh terus mengetuk. Fail2ban membaca log autentikasi dan memblokir sementara IP yang gagal login berkali-kali. fail2ban sudah ikut terpasang di langkah 1. Jangan pernah mengedit /etc/fail2ban/jail.conf langsung — berkas itu bisa tertimpa saat upgrade paket. Buat berkas override /etc/fail2ban/jail.local:

nano /etc/fail2ban/jail.local

Isinya:

[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
banaction = ufw

[sshd]
enabled = true
port = 22
maxretry = 5
bantime = 1h

Artinya: IP yang gagal login 5 kali dalam 10 menit diblokir selama satu jam, dan pemblokirannya dilakukan lewat UFW sehingga ikut terlihat di ufw status. Aktifkan dan periksa:

systemctl enable --now fail2ban
fail2ban-client status sshd

Hasil yang diharapkan: status jail sshd menampilkan Currently failed dan Currently banned (keduanya boleh nol di server baru — yang penting jail-nya aktif, bukan angkanya). Untuk mengintip IP yang sedang diblokir kapan saja: fail2ban-client status sshd lalu ufw status.

Satu peringatan yang sering dilupakan: karena login kata sandi sudah dimatikan, bot yang menebak kata sandi tidak akan pernah berhasil — fail2ban di sini berfungsi sebagai peredam kebisingan dan lapisan kedua, bukan satu-satunya penjaga. Jangan pernah mengendurkan aturan SSH dengan alasan "sudah ada fail2ban".

Langkah 7: Siapkan swap 2 GB

Swap adalah ruang darurat di disk saat RAM penuh. Di VPS 4 GB, swap 2 GB memberi napas tambahan saat proses sesekali memuncak — misalnya saat Composer mengurai dependensi besar atau saat worker menumpuk. Swap bukan pengganti RAM: kalau server terus-menerus hidup dari swap, yang perlu diperbaiki adalah kapasitasnya, bukan ukuran swap-nya.

fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile

Agar swap aktif lagi setiap reboot, tambahkan baris ini ke /etc/fstab:

/swapfile none swap sw 0 0

Lalu turunkan kecenderungan kernel memakai swap agar RAM tetap diprioritaskan. Buat berkas /etc/sysctl.d/99-swappiness.conf berisi:

vm.swappiness = 10

Terapkan dengan sysctl -p /etc/sysctl.d/99-swappiness.conf, dan verifikasi:

swapon --show
free -h

Hasil yang diharapkan: swapon --show menampilkan /swapfile sebesar 2 GB, dan free -h menampilkan baris Swap dengan total 2,0 GB. Kalau fallocate gagal di penyedia tertentu (ada VPS yang sistem berkasnya tidak mendukungnya), gantinya adalah dd if=/dev/zero of=/swapfile bs=1M count=2048 — lebih lambat, tapi hasilnya sama.

Langkah 8: Nyalakan pembaruan keamanan otomatis

Fondasi yang bagus bisa lapuk dalam sebulan kalau tidak ada yang memperbarui paket keamanannya. Aktifkan unattended-upgrades supaya tambalan keamanan terpasang sendiri:

apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades

Perintah kedua bersifat interaktif dan akan menanyakan apakah pembaruan otomatis diaktifkan — jawab Yes. Verifikasi timer dan konfigurasinya:

systemctl status apt-daily-upgrade.timer
cat /etc/apt/apt.conf.d/20auto-upgrades

Hasil yang diharapkan: timer aktif, dan berkas konfigurasi menampilkan APT::Periodic::Update-Package-Lists "1"; serta APT::Periodic::Unattended-Upgrade "1";. Pembaruan otomatis ini hanya memasang tambalan keamanan dari repositori Ubuntu, bukan meng-upgrade versi PHP atau Nginx Anda secara diam-diam — jadi ia tidak akan merusak konfigurasi yang Anda susun di artikel berikutnya.


Tabel ringkasan

Bagian fondasiKeputusanPerintah atau berkas kunci
Spesifikasi awal2 vCPU, RAM 4 GB, SSD 50 GBNaikkan setelah mengukur, bukan sebelum
Sistem operasiUbuntu 24.04 LTSDukungan standar 5 tahun, PHP 8.3 bawaan
User kerjadeploy dengan sudoadduser deploy, usermod -aG sudo deploy
Login SSHKunci Ed25519, root dan kata sandi dimatikan/etc/ssh/sshd_config, sshd -t, systemctl restart ssh
FirewallUFW aktif, hanya SSH terbukaufw allow OpenSSH, ufw enable
Blokir brute forcefail2ban jail sshd, blokir 1 jam/etc/fail2ban/jail.local, fail2ban-client status sshd
Swap2 GB, swappiness 10/swapfile, /etc/fstab, /etc/sysctl.d/99-swappiness.conf
PembaruanTambalan keamanan otomatisunattended-upgrades, apt-daily-upgrade.timer

Checklist akhir

  • Login sebagai deploy dengan SSH key berhasil dari terminal baru, login root ditolak.
  • ufw status verbose menampilkan status aktif dengan aturan OpenSSH.
  • fail2ban-client status sshd menunjukkan jail aktif.
  • swapon --show menampilkan swap 2 GB dan free -h mengonfirmasinya.
  • timedatectl menampilkan zona Asia/Jakarta.
  • Timer apt-daily-upgrade aktif untuk tambalan keamanan.
  • Sesi root lama sudah ditutup setelah semua verifikasi lolos — bukan sebelumnya.

Yang sering ditanyakan di titik ini

Apakah spesifikasi 2 vCPU dan 4 GB cukup kalau database dan Redis ikut di server yang sama? Untuk tahap awal, ya — selama Anda mengukur. Kalau htop menunjukkan RAM konsisten di atas 80 persen atau load average melampaui jumlah vCPU dalam waktu lama, itu sinyal menaikkan RAM, bukan menambah swap. Dan kalau Anda berencana menjalankan database produksi yang serius, pisahkan database ke server khusus sedini mungkin — artikel seri ini tetap relevan karena fondasi hardening-nya sama di server mana pun.

Di artikel berikutnya, fondasi ini langsung dipakai: Nginx dan PHP-FPM dipasang, server block diarahkan ke direktori public Laravel, dan HTTPS dari Let's Encrypt diaktifkan. Tanpa fondasi ini, semua langkah itu berdiri di atas server yang masih bisa dimasuki siapa saja lewat root dan kata sandi.

Bagian mana dari fondasi ini yang paling sering Anda lewatkan saat menyiapkan server baru — firewall, fail2ban, atau justru swap? Ceritakan di komentar, dan sebutkan juga spesifikasi VPS yang Anda pakai sekarang supaya pembaca lain bisa membandingkan.

Baca juga: panduan langkah demi langkah menyiapkan VPS Ubuntu pertama dan hardening dasarnya di VPS Pertama: Setup Ubuntu dan Hardening Awal, dan gambaran cara satu VPS melayani banyak layanan lewat Satu VPS Banyak Layanan: Nginx Reverse Proxy.

Komentar