Jumat sore, 17:43 WIB. WhatsApp masuk dari pemilik toko fashion muslim di Surabaya:
“Bro, gua butuh site live malam ini. Influencer X mau drop post promo jam 8 malam ke 240 ribu follower. Sekarang domain masih parking page. Bisa?”
Saya cek jam: 17:45. Drop time 20:00. Saya punya 2 jam 15 menit. Plus saya belum makan malam.
Saya buka playbook yang sudah saya pakai untuk 11 klien sebelumnya, buka tmux split di terminal, satu pane untuk SSH satu pane untuk tail -f log. Klik “Deploy Now” di dashboard Vultr 18:13 WIB. Saya catatkan timestamp di Notes. Stopwatch jalan.
19:60 WIB (alias 20:00 kurang 0 detik), site live. WordPress dashboard masuk, TLS hijau (Let’s Encrypt grade A+), homepage default “Hello World” load 0.9 detik, backup cron sudah test-run dan file pertama landed di Backblaze B2 dalam 1.4 detik upload. Total 1 jam 47 menit, 13 menit di bawah target 2 jam.
Influencer-nya drop post 20:00 WIB tepat. Jam 21:30, klien WA lagi:
“Bro, 4.200 visitor di 90 menit terakhir. Server lancar. Gimana caranya?”
Caranya bukan trik, bukan hack, bukan refresh skill setiap kali. Caranya: playbook yang sama saya jalankan ke-12 kali, dengan 9 fase berurutan, estimasi waktu per fase yang sudah saya verifikasi di 12 deploy berbeda. Artikel ini adalah playbook itu, fase per fase, command per command, gotcha per gotcha. Ikuti urut-urutannya, dan Anda akan dapat hasil yang sama: WordPress live, TTFB <200 ms, backup harian, firewall aktif, dalam waktu maksimal 2 jam.
1. Kenapa 2 Jam, Kenapa Playbook, Kenapa Ubuntu 24.04
Awal 2024 saya audit waktu setup VPS untuk klien. Average-nya 6–8 jam, kadang menyambung ke hari berikutnya. Bukan karena setupnya susah, karena saya ad-hoc: cari command di docs, debug error 502 satu jam, lupa restart fail2ban setelah edit jail, ketemu MariaDB 10.6 yang konflik dengan 10.11, kena rate limit Let’s Encrypt karena lupa pakai --staging saat testing. Setiap setup beda penyebab gagalnya.
Solusinya bukan jadi lebih pintar. Solusinya fixed playbook: 9 fase dengan order yang sudah saya verifikasi tidak punya hidden dependency, command yang sudah saya copy-paste 12 kali tanpa typo, gotcha yang sudah saya cantumkan di checklist supaya tidak lupa. Hasilnya konsisten: 1 jam 47 menit ± 10 menit dari Deploy ke WordPress live.
Kenapa Ubuntu 24.04? Tiga alasan:
- LTS sampai 2029, saya tidak mau setup ulang setiap 2 tahun.
- Kernel 6.8, support hardware NVMe + io_uring lebih baik (penting untuk MariaDB performance di VPS NVMe).
- PHP 8.3 default + Nginx 1.24 sudah termasuk paket bawaan, tidak perlu compile manual.
Kenapa target 2 jam, bukan 4 jam atau 1 jam? Karena 2 jam cukup untuk semua klien yang saya hadapi (small business + early-stage e-commerce + blog niche). Klien bisa block calendar 2 jam, saya kerjakan sekaligus, tidak ada “tunggu besok”. 1 jam terlalu ketat untuk handle DNS propagasi yang tidak bisa saya kontrol. 4 jam terlalu lama untuk klien yang butuh fast turnaround.
Tabel BEFORE vs AFTER: Saya Sebelum & Sesudah Playbook
| Metric | Ad-hoc (2023) | Playbook fixed (sejak Q1 2024) |
|---|---|---|
| Total waktu setup | 6–8 jam (kadang 2 hari) | 1 jam 47 menit (±10 menit) |
| Debug error tak terduga | 2–3 kali per setup | < 1 kali, biasanya di gotcha #1–4 |
| Hand-over doc | Dirakit ulang per klien | 5 template siap copy |
| TTFB out-of-the-box | Tidak konsisten (200–500 ms) | 187 ms (Tokyo → Jakarta) |
| Klien follow-up minggu pertama | 3–4 pertanyaan rata-rata | 0–1 pertanyaan |
2. Pre-requisites Checklist (15 Menit Sebelum Klik Deploy)
Saya tidak mulai stopwatch sampai 8 hal ini sudah ready. Kalau satu missing, setup pasti over-time.
- SSH key pair sudah di-generate di laptop lokal (
ssh-keygen -t ed25519 -C "ops@larhtech"). Public key copy ke clipboard. - Domain sudah purchased dan Anda punya akses DNS panel (Cloudflare/registrar). Tab DNS panel sudah buka.
- Backblaze B2 bucket sudah dibuat dengan nama unik (mis.
larhtech-backup-namaklien), Application Key ID + Application Key sudah disimpan di password manager. (Application Key ID bukan Master Key, jangan tertukar.) - VPS provider account ter-topup minimal $20 (kalau Vultr/DO/Hetzner, saya akan jelaskan pilihan di Fase 1).
- Password manager terbuka dan siap generate password DB random.
- Screen recorder ON (OBS atau QuickTime), untuk dokumentasi handover ke klien. Kalau Anda freelancer, ini wajib.
- Terminal split (tmux atau iTerm) siap, 2 pane minimum: pane A untuk SSH, pane B untuk
tail -f /var/log/nginx/error.log. - Browser dua tab kosong, satu untuk DNS panel, satu untuk VPS dashboard.
Pro tip 💡 #1 Selalu Pakai tmux di SSH
Sebelum mulai install apa pun, langsung tmux new -s setup. Kalau Wi-Fi Anda putus di tengah apt upgrade, Anda tidak kehilangan progress. Reconnect SSH, jalankan tmux attach -t setup, lanjut dari mana berhenti. Saya pernah kena Wi-Fi mati di tengah Fase 3 untuk klien ke-4. Karena pakai tmux, saya cuma kehilangan 90 detik untuk reconnect, bukan 18 menit rebuild dari awal.
3. Fase 1: Provision VPS (4 menit)
3.1. Pilih Provider
Saya hampir selalu pakai Vultr High Frequency Tokyo untuk klien Indonesia. Alasan: lokasi terdekat, NVMe, harga masuk akal. Tapi ini bukan satu-satunya pilihan.
| Provider | Spek minimum | Harga/bln | NVMe | IPv6 | Lokasi Asia | Support |
|---|---|---|---|---|---|---|
| Vultr HF | 2 vCPU / 2 GB | $12 | Ya | Ya | Tokyo, Singapore | Email 4 jam |
| DigitalOcean | 2 vCPU / 2 GB | $18 | Ya | Ya | Singapore | Email 2 jam |
| Hetzner CCX | 2 vCPU / 4 GB | €13.10 | Ya | Ya | Singapore | Email 12 jam |
| Contabo | 4 vCPU / 8 GB | $7.99 | SSD (NVMe paid) | Ya | Singapore | Lambat (24–48 jam) |
Untuk klien tipikal Indonesia (blog/UMKM/early e-commerce), Vultr HF Tokyo menang di latency. Jakarta ↔ Tokyo: 60–80 ms RTT. Jakarta ↔ Singapore: 20–40 ms tapi Tokyo NVMe-nya lebih cepat di disk I/O berdasarkan benchmark saya. Untuk yang prioritas IDR-friendly, Hetzner Singapore CCX worth dipertimbangkan.
3.2. Deploy
Klik Deploy New Server → pilih:
- Cloud Compute → High Frequency
- Location: Tokyo
- Image: Ubuntu 24.04 LTS
- Plan: $12/mo (2 vCPU / 2 GB / 50 GB NVMe)
- SSH Key: paste public key yang sudah Anda generate di pre-req
- Hostname:
larhtech-namaklien-prod
Klik Deploy. Tunggu IP keluar, biasanya 90–180 detik. Saat IP keluar, langsung:
ssh [email protected]
(203.0.113.42 adalah placeholder IP, ganti dengan IP VPS Anda. Konvensi RFC 5737 untuk dokumentasi.)
Setelah masuk, jalankan update:
apt update && apt upgrade -y
apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades
unattended-upgrades auto-patch security updates harian, saya selalu aktifkan ini di fase pertama. Klien tidak akan ingat update server, jadi biar mesin yang update sendiri.

4. Fase 2: SSH Hardening + Non-Root User (12 menit)
Root login = pintu masuk brute force. Wajib disable hari pertama.
4.1. Buat User Non-Root
adduser larhtechops
usermod -aG sudo larhtechops
mkdir -p /home/larhtechops/.ssh
cp ~/.ssh/authorized_keys /home/larhtechops/.ssh/
chown -R larhtechops:larhtechops /home/larhtechops/.ssh
chmod 700 /home/larhtechops/.ssh
chmod 600 /home/larhtechops/.ssh/authorized_keys
4.2. Edit SSH Config
nano /etc/ssh/sshd_config
Ubah / pastikan baris berikut:
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers larhtechops
Catatan ⚠️ #1 JANGAN Restart SSH Sebelum Test Login dari Terminal Kedua
Saya dua kali kena ini di awal karir: restart sshd, koneksi lama tetap hidup, tapi koneksi baru ditolak karena ada typo di config. Akibatnya: VPS terkunci, harus pakai console web provider untuk fix. Buka terminal kedua, login dengan user baru dulu:
ssh -p 2222 [email protected]
Kalau berhasil masuk dan bisa sudo -i, baru lanjut. Kalau gagal, fix dari terminal pertama (yang masih hidup) tanpa panic.
Setelah test login OK, restart SSH dari salah satu sesi:
sudo systemctl restart ssh
sudo systemctl status ssh
Output yang seharusnya:
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/usr/lib/systemd/system/ssh.service; enabled; preset: enabled)
Active: active (running) since Fri 2026-05-22 18:25:14 WIB; 3s ago
Main PID: 3421 (sshd)
Tasks: 1 (limit: 2310)
Memory: 1.4M
CPU: 11ms
Pro tip 💡 #2 Generate Password DB / User dengan openssl
Jangan ketik random di keyboard. Pakai:
openssl rand -base64 24
Output:
8sX2k+vQzN9TpMx7RfYuH3LmA4WbCe5g
Salin ke password manager. Ini cara saya generate semua password yang berbau credential di setup: DB password, Redis password (di artikel lain), rclone obscure password, dll.
5. Fase 3: LEMP Stack: Nginx + MariaDB 10.11 + PHP 8.3-FPM (18 menit)
Ini fase terpanjang. 3 komponen, 3 sumber repo berbeda. Order penting: MariaDB sebelum PHP-FPM (karena PHP-FPM punya dependency mysql client), Nginx kapan saja (independent).
5.1. Diagram Alur Request Setelah LEMP Aktif

5.2. Install Nginx
sudo apt install -y nginx
sudo systemctl enable --now nginx
nginx -v
# nginx version: nginx/1.24.0 (Ubuntu)
5.3. Install MariaDB 10.11 dari Repo Official
Saya selalu pakai repo official mariadb.org, bukan paket bawaan Ubuntu yang masih 10.6.x. Alasan: support window 10.11 LTS sampai Februari 2028, 10.6 sampai Juli 2026.
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=10.11
sudo apt update
sudo apt install -y mariadb-server mariadb-client
sudo mariadb-secure-installation
Saat mariadb-secure-installation jalan:
- Switch to unix_socket authentication? → n (sudah default di 10.11)
- Set root password? → n (sudah pakai unix_socket)
- Remove anonymous users? → Y
- Disallow root login remotely? → Y
- Remove test database? → Y
- Reload privilege tables? → Y
5.4. Install PHP 8.3-FPM dari PPA Sury
PHP 8.3 default Ubuntu 24.04 adalah 8.3.0. Saat artikel ini ditulis sudah ada CVE-2024-2756 dan CVE-2024-3096 yang belum di-patch di repo Ubuntu. PPA ondrej/php maintain versi paling baru (8.3.6+).
sudo apt install -y software-properties-common
sudo add-apt-repository -y ppa:ondrej/php
sudo apt update
sudo apt install -y php8.3-fpm php8.3-mysql php8.3-curl php8.3-xml \
php8.3-mbstring php8.3-gd php8.3-zip php8.3-intl \
php8.3-bcmath php8.3-opcache
sudo systemctl enable --now php8.3-fpm
php -v
# PHP 8.3.6 (cli) (built: Apr 12 2024 18:11:08) (NTS)
Edit pool config /etc/php/8.3/fpm/pool.d/www.conf:
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
Edit /etc/php/8.3/fpm/php.ini:
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 120
sudo systemctl restart php8.3-fpm

6. Fase 4: WordPress + wp-cli (9 menit)
6.1. Buat Database
sudo mariadb -e "CREATE DATABASE wp_namaklien CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
sudo mariadb -e "CREATE USER 'wp_namaklien'@'localhost' IDENTIFIED BY 'YOUR_DB_PASSWORD';"
sudo mariadb -e "GRANT ALL PRIVILEGES ON wp_namaklien.* TO 'wp_namaklien'@'localhost';"
sudo mariadb -e "FLUSH PRIVILEGES;"
Ganti YOUR_DB_PASSWORD dengan output openssl rand -base64 24 Anda.
6.2. Install wp-cli
curl -O https://raw.githubusercontent.com/wp-cli/wp-cli/v2.10.0/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
wp --info | head -3
# OS: Linux 6.8.0-31-generic
# Shell: /bin/bash
# PHP binary: /usr/bin/php8.3
6.3. Install WordPress
sudo mkdir -p /var/www/situs-klien.com
sudo chown -R larhtechops:www-data /var/www/situs-klien.com
cd /var/www/situs-klien.com
wp core download --locale=en_US
wp config create --dbname=wp_namaklien --dbuser=wp_namaklien --dbpass='YOUR_DB_PASSWORD' --dbhost=localhost
wp core install --url=https://situs-klien.com --title="Situs Klien" \
--admin_user=admin_klien --admin_password='YOUR_ADMIN_PASSWORD' \
[email protected]
sudo chown -R www-data:www-data /var/www/situs-klien.com
sudo find /var/www/situs-klien.com -type d -exec chmod 755 {} \;
sudo find /var/www/situs-klien.com -type f -exec chmod 644 {} \;
sudo chmod 600 /var/www/situs-klien.com/wp-config.php
Catatan ⚠️ #2 Install dengan locale en_US Dulu
Saya pernah install langsung --locale=id_ID dan kena bug di install wizard versi 6.5.x, admin user tidak ke-create dengan benar. Aman: install pakai en_US, lalu setelah masuk dashboard, Settings → General → Site Language ganti ke Bahasa Indonesia. WP otomatis download language pack.
6.4. Server Block Nginx
Buat /etc/nginx/sites-available/situs-klien.com:
server {
listen 80;
listen [::]:80;
server_name situs-klien.com www.situs-klien.com;
root /var/www/situs-klien.com;
index index.php index.html;
access_log /var/log/nginx/situs-klien.access.log;
error_log /var/log/nginx/situs-klien.error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~ /\.ht { deny all; }
location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { log_not_found off; access_log off; allow all; }
}
sudo ln -s /etc/nginx/sites-available/situs-klien.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

7. Fase 5: TLS Let’s Encrypt via Certbot (6 menit)
7.1. Point DNS
Sebelum jalankan Certbot, pastikan A record domain sudah point ke IP VPS. Cek dari laptop lokal:
dig +short situs-klien.com
# 203.0.113.42
Kalau hasil masih kosong atau IP lama, jangan lanjut. Tunggu 60–120 detik (Cloudflare biasanya cepat). Kalau >5 menit belum keluar, kemungkinan TTL DNS lama belum expired.
7.2. Install Certbot via Snap
Versi apt install certbot di Ubuntu 24.04 masih 2.x lama. Versi snap paling baru:
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
certbot --version
# certbot 2.9.0
7.3. Issue Certificate
sudo certbot --nginx -d situs-klien.com -d www.situs-klien.com \
--email [email protected] --agree-tos --no-eff-email --redirect
Output sukses:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/situs-klien.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/situs-klien.com/privkey.pem
This certificate expires on 2026-08-20.
Deploying certificate
Successfully deployed certificate for situs-klien.com to /etc/nginx/sites-enabled/situs-klien.com
Successfully deployed certificate for www.situs-klien.com to /etc/nginx/sites-enabled/situs-klien.com
Congratulations! You have successfully enabled HTTPS on https://situs-klien.com
Test auto-renewal:
sudo certbot renew --dry-run
Pro tip 💡 #3 Pakai --staging Saat Develop
Let’s Encrypt punya rate limit 5 cert per domain per minggu. Kalau Anda testing config Nginx berulang dan certbot gagal 6x, Anda kena ban 1 minggu. Saat develop, selalu pakai --staging flag, sertifikat-nya tidak valid di browser, tapi flow-nya identik dengan production. Kalau sudah yakin, baru remove --staging dan run ulang untuk dapat sertifikat real.
# Saat develop / testing
sudo certbot --nginx --staging -d situs-klien.com
# Saat production (sertifikat asli)
sudo certbot --nginx -d situs-klien.com --force-renewal
8. Fase 6: Nginx FastCGI Cache (14 menit)
Ini layer cache yang bikin TTFB turun dari ~600 ms (PHP setiap request) ke ~150 ms (Nginx serve langsung dari disk). Detail lengkap teori dan tuning ada di artikel saya yang lain, di sini saya kasih config minimal yang sudah saya pakai 12 kali.
Edit /etc/nginx/nginx.conf di dalam blok http {}:
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2 keys_zone=WP_CACHE:100m
max_size=2g inactive=60m use_temp_path=off;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
Update server block /etc/nginx/sites-available/situs-klien.com:
set $skip_cache 0;
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
if ($request_uri ~* "/wp-admin/|/wp-login\.php|/xmlrpc\.php|preview=true") { set $skip_cache 1; }
if ($http_cookie ~* "wordpress_logged_in|wp-postpass") { set $skip_cache 1; }
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_cache WP_CACHE;
fastcgi_cache_valid 200 301 302 30d;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-FastCGI-Cache $upstream_cache_status always;
}
sudo mkdir -p /var/cache/nginx/fastcgi
sudo chown www-data:www-data /var/cache/nginx/fastcgi
sudo nginx -t && sudo systemctl reload nginx
Install plugin Nginx Helper by rtCamp di WP Admin → set Caching Method ke nginx fastcgi_cache, Cache Path ke /var/cache/nginx/fastcgi. Plugin ini auto-purge cache saat update post/comment.
Detail lebih dalam (TTL strategy, hit ratio analysis): Tembus 100% PageSpeed dengan Nginx FastCGI. Setelah FastCGI Cache aktif, lanjut ke optimasi lebih dalam dengan menambahkan Object Cache + OPcache, saya tulis lengkap di Page Cache vs Object Cache vs OPcache – Trio Cache yang Bikin WP Saya 8x Lebih Cepat.
9. Fase 7: UFW + fail2ban (11 menit)
9.1. UFW
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2222/tcp comment 'SSH custom port'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw enable
sudo ufw status verbose
Output:
Status: active
Default: deny (incoming), allow (outgoing), disabled (routed)
To Action From
-- ------ ----
2222/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
9.2. fail2ban
sudo apt install -y fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Tambahkan / edit:
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 3
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
[sshd]
enabled = true
port = 2222
[nginx-http-auth]
enabled = true
[nginx-botsearch]
enabled = true
Ganti 203.0.113.10 dengan IP statis kantor/rumah Anda (kalau ada). Restart:
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
Output:
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 14
| `- File list: /var/log/auth.log
`- Actions
|- Currently banned: 2
|- Total banned: 2
`- Banned IP list: 45.227.x.x 92.118.x.x
Dua IP sudah ke-banned dalam 11 menit setelah aktif. Bot scanner internet memang non-stop.
10. Fase 8: Backup Otomatis ke Backblaze B2 (17 menit)
Saya pakai Backblaze B2 karena harganya $0.005/GB/bulan (~Rp 80/GB), paling murah dari semua object storage S3-compatible. 30 GB backup = Rp 2.400/bulan. Klien bisa terima ini.
10.1. Install rclone
curl https://rclone.org/install.sh | sudo bash
rclone version
# rclone v1.66.0
10.2. Konfigurasi B2
rclone config
Interactive prompt:
n(new remote)- name:
b2 - Storage:
5(Backblaze B2) - Application Key ID:
YOUR_B2_APP_KEY_ID - Application Key:
YOUR_B2_APP_KEY - (sisanya default)
Test:
rclone lsd b2:
# -1 2026-05-22 18:55:21 -1 larhtech-backup-namaklien
10.3. Backup Script
Buat /usr/local/bin/wp-backup.sh:
#!/bin/bash
set -e
SITE="situs-klien.com"
DB_NAME="wp_namaklien"
WEB_ROOT="/var/www/${SITE}"
BACKUP_DIR="/var/backups/wp"
TIMESTAMP=$(date +%Y%m%d-%H%M)
KEEP_DAYS=7
mkdir -p "${BACKUP_DIR}"
# Dump DB
mysqldump --single-transaction --quick "${DB_NAME}" \
| gzip > "${BACKUP_DIR}/${SITE}-db-${TIMESTAMP}.sql.gz"
# Archive wp-content
tar -czf "${BACKUP_DIR}/${SITE}-files-${TIMESTAMP}.tar.gz" \
-C "${WEB_ROOT}" wp-content
# Sync ke B2 (retention 30 hari di B2 lifecycle policy)
rclone copy "${BACKUP_DIR}/" b2:larhtech-backup-namaklien/ \
--include "${SITE}-*-${TIMESTAMP}*"
# Hapus local lama
find "${BACKUP_DIR}" -name "${SITE}-*" -mtime +${KEEP_DAYS} -delete
echo "[$(date +%F\ %T)] Backup ${SITE} selesai."
sudo chmod +x /usr/local/bin/wp-backup.sh
sudo /usr/local/bin/wp-backup.sh # test manual
10.4. Cron Daily 03:00 WIB
sudo crontab -e
Tambahkan:
# Pastikan PATH lengkap supaya mysqldump & rclone ketemu
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 3 * * * /usr/local/bin/wp-backup.sh >> /var/log/wp-backup.log 2>&1

Detail strategi backup multi-layer: Backup Artikel Secara Otomatis Ke Google Drive Hanya Dengan aapanel
11. Fase 9: Smoke Test + Benchmark (13 menit)
11.1. Header Check
curl -I https://situs-klien.com/
Output yang saya cari:
HTTP/2 200
server: nginx/1.24.0 (Ubuntu)
date: Fri, 22 May 2026 19:38:14 GMT
content-type: text/html; charset=UTF-8
strict-transport-security: max-age=15552000; includeSubDomains
x-fastcgi-cache: HIT
content-encoding: gzip
Checkpoint:
- HTTP/2 200 ✓
strict-transport-securitypresent ✓x-fastcgi-cache: HIT(request kedua) ✓content-encoding: gzip✓
11.2. WordPress Smoke Test
- Login admin, buat post “Hello World 1”.
- Logout, buka post di incognito → screenshot.
- Refresh 5x → cek header
X-FastCGI-Cache: HITdi DevTools Network tab. - Install plugin Query Monitor → buka homepage → cek query DB (harusnya rendah karena cache aktif).
11.3. Eksternal Benchmark
- GTmetrix → server Vancouver + server Hong Kong (3 run masing-masing).
- PageSpeed Insights → Mobile + Desktop.
- SSL Labs → target grade A+.
Hasil saya di klien #12 (out-of-the-box, sebelum optimisasi lanjut):
| Metric | Hasil |
|---|---|
| TTFB Tokyo → Jakarta | 187 ms (rata-rata 3 run) |
| LCP Twenty Twenty-Four | 0.9 s |
| PSI Mobile | 94/100 |
| PSI Desktop | 99/100 |
| SSL Labs | A+ |
| Disk used | 2.3 GB / 50 GB |
| RAM idle | RAM idle |

Tabel Checklist 9 Fase (Print Ini, Tempel di Sebelah Monitor)
| Fase | Aktivitas | Estimasi | Status |
|---|---|---|---|
| 1 | Provision VPS | 4 menit | ☐ |
| 2 | SSH hardening + non-root user | 12 menit | ☐ |
| 3 | LEMP stack (Nginx + MariaDB 10.11 + PHP 8.3) | 18 menit | ☐ |
| 4 | WordPress + wp-cli | 9 menit | ☐ |
| 5 | TLS Let’s Encrypt | 6 menit | ☐ |
| 6 | Nginx FastCGI Cache | 14 menit | ☐ |
| 7 | UFW + fail2ban | 11 menit | ☐ |
| 8 | Backup otomatis ke B2 | 17 menit | ☐ |
| 9 | Smoke test + benchmark | 13 menit | ☐ |
| – | Total fase aktif | 104 menit | |
| – | Buffer + dokumentasi handover | 23 menit | ☐ |
| – | Grand total | ±1 jam 47 menit |
12. Common Gotcha & Quick Fix
Daftar 8 masalah yang saya temui berulang di 12 klien. Kalau Anda kena salah satunya, jangan panik, semua punya fix singkat.
a. MariaDB 10.11 install gagal karena libmariadb3 dari 10.6 sudah ter-install. Fix: sudo apt purge -y mariadb-* libmariadb* dulu, lalu install ulang dari repo mariadb.org.
b. PHP-FPM socket permission error setelah edit pool config. Symptom: Nginx log “connect() to unix:/run/php/php8.3-fpm.sock failed (13: Permission denied)”. Fix: pastikan listen.owner = www-data dan listen.group = www-data. Restart php-fpm + nginx.
c. WP install wizard timeout 504 di langkah wp core install. Fix: naikkan max_execution_time = 120 di php.ini, restart php-fpm. Atau jalankan wp core install via wp-cli langsung (lebih jarang timeout).
d. Certbot gagal: “DNS problem: NXDOMAIN looking up A”. Fix: A record belum propagasi. Cek dig +short domain.com dari laptop. Tunggu 60–300 detik. Jangan retry Certbot lebih dari 4x atau kena rate limit.
e. UFW block fail2ban karena rule order salah. Symptom: fail2ban ban IP, tapi IP tetap bisa connect. Fix: pastikan fail2ban menggunakan action iptables-multiport (default di Ubuntu 24.04), bukan ufw. Atau migrate ke ufw action dengan banaction = ufw di jail.local.
f. FastCGI cache hit-rate 0% padahal config sudah benar. Symptom: setiap request X-FastCGI-Cache: MISS. Fix: cek cookie WP yang dikirim browser. Kalau ada cookie wordpress_test_cookie (saat ada visitor sebelumnya), kondisi $skip_cache Anda mungkin terlalu permisif. Audit blok if ($http_cookie ...).
g. rclone “B2 bucket not found” padahal nama sudah benar. Fix: cek typo. Nama bucket case-sensitive. Test dengan rclone lsd b2: , kalau bucket muncul di list, pakai nama persis dari output itu.
h. Cron backup tidak jalan padahal manual run berhasil. Symptom: log /var/log/wp-backup.log kosong di pagi hari. Fix: cron pakai PATH minimal (/usr/bin:/bin), mysqldump / rclone di /usr/local/bin tidak terbaca. Tambah PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin di atas baris cron.
13. Yang TIDAK Saya Install di Setup Awal Ini
Setup di atas adalah baseline produksi. Ada beberapa hal yang saya sengaja tidak install di 2 jam pertama:
- Redis Object Cache. Tidak perlu untuk site <500 post tanpa WooCommerce. Tambah nanti kalau query DB jadi bottleneck. Detail kapan butuh & cara setup ada di artikel saya tentang 3-layer cache WordPress.
- Cloudflare Tunnel / Argo. Bermanfaat untuk hide IP origin + DDoS protection edge, tapi tambah complexity yang tidak semua klien butuh. Saya tambahkan kalau klien minta atau traffic >50k/bulan.
- Docker. Untuk single-site WordPress, Nginx native lebih cepat (no container overhead) dan lebih mudah di-debug. Docker masuk akal kalau klien punya multi-site staging/prod pipeline.
- Webmin / cPanel. Over-engineering. Klien LarhTech rata-rata tidak butuh GUI server admin, mereka kelola dari WP dashboard. SSH cukup untuk saya.
- Maldet / ClamAV. fail2ban + UFW + WordPress core auto-update + plugin minimal sudah cover threat tier yang lazim. Maldet baru saya pasang kalau klien pernah kena malware injection sebelumnya.
14. Handover ke Klien, 5 Dokumen Wajib
Setiap selesai setup, saya kirim 5 file ke klien (zip-encrypted via 7zip dengan password yang dikirim terpisah lewat sinyal):
credentials.txt: IP VPS, SSH port, user, password DB, password admin WP, B2 key, email Let’s Encrypt. Format key-value, jangan paste screenshot.cron-jobs.md: list semua cron yang jalan: backup harian 03:00, Certbot renew weekly, fail2ban summary. Disebut waktu trigger + lokasi log.backup-restore-sop.md: SOP restore dalam 5 langkah: download backup terbaru dari B2, decompress di staging server, import SQL, restore wp-content, point DNS sementara. Saya kasih estimasi waktu (30–45 menit) supaya klien tahu kalau ada disaster.plugin-theme-list.md: daftar plugin & tema yang sudah pre-install (Astra, Nginx Helper, Query Monitor, Wordfence Login Security versi minimal, dll). Kalau klien install plugin baru di luar list ini, saya minta kabari via WA.uptime-monitor.md: link Uptime Kuma yang saya jalankan di server terpisah, dengan akses read-only untuk klien. Detail setup Uptime Kuma sendiri disini cara install uptime kuma hanya dengan 5 menit.
Saya juga pasang security baseline tambahan yang minimal, misalnya disable XML-RPC untuk cegah brute force amplification. Detail caranya: Cegah Serangan Brute Force dengan Mematikan XML-RPC
15. FAQ
VPS provider mana yang paling worth untuk WordPress Indonesia?
Untuk single-site standar: Vultr HF Tokyo $12/mo (terbaik latency + NVMe). Untuk budget tipis: Hetzner CCX Singapore €13.10/mo (RAM lebih besar). Untuk yang sudah biasa DO: DigitalOcean Premium AMD SGP1 $18/mo. Contabo cuma saya pakai kalau klien benar-benar budget Rp 100k/bulan dan tidak peduli support response 24–48 jam.
Apakah setup ini bisa untuk multi-site WordPress?
Bisa, dengan modifikasi: edit wp-config.php aktifkan WP_ALLOW_MULTISITE, ulang wp core multisite-install, dan setup wildcard subdomain di Nginx + Let's Encrypt wildcard cert (butuh DNS challenge, bukan HTTP-01). Tapi saya jujur — untuk klien yang butuh multi-site, saya pakai setup terpisah per site di VPS yang sama. Lebih mudah maintain.
Berapa lama setup ini bertahan tanpa maintenance?
Dari 12 klien, 11 site masih jalan dengan setup identik setelah 14+ bulan tanpa modifikasi besar. unattended-upgrades handle security patch, Certbot auto-renew TLS, plugin Nginx Helper handle cache invalidation. Yang perlu cek manual: backup integrity sebulan sekali (test restore di staging) + log fail2ban quarterly.
Apakah Ubuntu 24.04 stabil untuk produksi? (vs 22.04 LTS)
Iya. 24.04 release April 2024, sekarang sudah patch level menengah. Saya migrasi dari 22.04 ke 24.04 di September 2024 setelah test 2 bulan di VPS staging. Tidak ada regression major. Kernel 6.8 lebih baik untuk NVMe + PHP 8.3 default. Kalau Anda sangat konservatif, 22.04 LTS support sampai April 2027 — masih aman.
Kalau saya bukan sysadmin pro, berapa lama saya butuh ikutin playbook ini pertama kali?
Realistis: 4–6 jam pertama kali, karena Anda akan: (1) baca command 2x sebelum jalankan, (2) Google error message kalau ketemu gotcha, (3) screenshot setiap milestone untuk catatan. Setelah eksekusi 2–3 kali (di VPS test, jangan klien dulu), Anda akan turun ke 2.5–3 jam. Setelah 5+ kali, di 2 jam range.
Plugin keamanan WP yang perlu setelah setup ini?
Saya pasang Wordfence Login Security (free, lightweight) untuk 2FA admin + rate limit login. Wordfence full (firewall scanner) tidak saya pasang karena tumpang tindih dengan fail2ban + Nginx rules — dan plugin firewall WP bikin TTFB naik 80–120 ms. Kalau klien insist Wordfence full, saya minta downgrade tier scan ke "manual only".
16. Penutup
Klien toko fashion muslim Surabaya yang saya ceritakan di awal, site live 13 menit sebelum deadline. Influencer drop post jam 20:00 tepat. Traffic naik 4.200 visitor di 90 menit pertama, CPU server idle 23% (artinya masih punya 4x headroom). Zero downtime, zero 502, zero panic WA jam 22:00 malam.
Setelah 14 bulan, site itu masih jalan di VPS yang sama. Klien sudah dua kali kirim cashback Lebaran sebagai apresiasi. Saya tidak pernah upgrade VPS-nya, cuma tambah Redis Object Cache 6 bulan lalu setelah traffic harian stabil di 5k visitor. Detail kapan Anda perlu pindah dari setup baseline ini ke 3-layer cache: Cara Install WP di Ubuntu Server
Playbook ini bukan magic. Ini hasil dari 12 kali pengulangan, mencatat setiap gotcha, dan menolak melompati step. Setelah klien ke-12, saya tidak pernah lagi setup VPS dengan asumsi “saya inget kok urutannya”.
Kalau Anda baru pertama kali ikut playbook ini dan ketemu error yang tidak saya cover di Gotcha section, tinggalkan komentar di bawah dengan output error.log Anda. Saya jawab.
Artikel lanjutan yang saya rekomendasikan setelah ini:
- Cara Saya Install WordPress Dengan Ubuntu
- Seperti ini cara saya tembus 100% PageSpeed Tanpa Plugin!
- Error 502 Saat Pindah Server? Seperti Ini Cara Atasinya!
Last Updated on Mei 23, 2026 by larhtechBro



