Halo, Rekan ArtonLabs. Tulisan ini tentang hal yang semua orang setuju penting dan sedikit orang benar-benar lakukan dengan benar: backup.
Backup yang baik punya tiga sifat: berjalan tanpa diingat, disimpan di tempat lain, dan sudah pernah dicoba dipulihkan. rclone adalah alat baris perintah yang bicara dengan hampir semua penyimpanan awan, termasuk apa pun yang kompatibel S3, dan cron yang memastikannya berjalan tiap malam. Tulisan ini menyusun backup berkas dan database ke Cloudflare R2 atau Backblaze B2, dengan retensi, enkripsi, dan pemeriksaan pemulihan. Control panel seperti VinzaPanel menyediakan ini lewat UI; di sini kita lihat yang bekerja di baliknya.
Daftar Isi
- Memilih Penyimpanan Tujuan
- Memasang dan Mengonfigurasi rclone
- Membuat Dump Database
- Skrip Backup
- Enkripsi dengan rclone crypt
- Menjadwalkan dengan Cron
- Retensi dan Biaya
- Uji Pemulihan
Memilih Penyimpanan Tujuan
Semua yang kompatibel S3 bisa dipakai: AWS S3, Cloudflare R2, Backblaze B2, Wasabi, MinIO yang Anda jalankan sendiri. Untuk backup, yang penting adalah biaya penyimpanan per gigabyte dan biaya keluar data saat memulihkan. R2 dan B2 tidak menagih biaya keluar, yang membuat pemulihan besar tidak terasa mahal. Buat bucket khusus backup dengan kunci akses yang hanya punya hak tulis dan baca ke bucket itu, bukan kunci akun utama.
Memasang dan Mengonfigurasi rclone
sudo -v ; curl https://rclone.org/install.sh | sudo bash
rclone version
Konfigurasi bisa interaktif lewat rclone config, atau langsung dari baris perintah, yang lebih cocok untuk server:
rclone config create r2 s3 provider=Cloudflare \
access_key_id=KUNCI secret_access_key=RAHASIA \
endpoint=https://AKUN_ID.r2.cloudflarestorage.com acl=private
rclone lsd r2:
Untuk B2 pakai provider=Backblaze dengan endpoint dari dasbornya. Berkas konfigurasi tersimpan di ~/.config/rclone/rclone.conf milik pengguna yang menjalankan; pastikan izinnya 600, karena di situlah kunci akses Anda.
Membuat Dump Database
Jangan menyalin folder data database yang sedang berjalan; salinannya bisa tidak konsisten. Buat dump dengan alat resmi:
mysqldump --single-transaction --routines aplikasi | gzip > /backup/db/aplikasi-$(date +%F).sql.gz
pg_dump -Fc aplikasi > /backup/db/aplikasi-$(date +%F).dump
mongodump --db aplikasi --archive=/backup/db/aplikasi-$(date +%F).archive --gzip
--single-transaction membuat dump MySQL konsisten tanpa mengunci tabel untuk mesin InnoDB. Untuk aplikasi Django dengan tipe data khusus seperti UUID yang bisa berbeda antar versi MariaDB, kami juga menyimpan ekspor tingkat aplikasi (manage.py dumpdata) sebagai cadangan kedua; pelajaran dari migrasi antar server yang pernah bermasalah persis di situ.
Skrip Backup
#!/bin/bash
set -euo pipefail
TGL=$(date +%F)
LOG=/var/log/backup.log
exec >>"$LOG" 2>&1
echo "== mulai $TGL $(date +%T)"
mkdir -p /backup/db
mysqldump --single-transaction aplikasi | gzip > /backup/db/aplikasi-$TGL.sql.gz
find /backup/db -name '*.sql.gz' -mtime +7 -delete
rclone sync /home/webapp/app/media r2:backup-server/media --transfers 8
rclone copy /backup/db r2:backup-server/db
rclone copy /home/webapp/app/.env r2:backup-server/config/
echo "== selesai $(date +%T)"
sync membuat tujuan sama persis dengan sumber, termasuk menghapus yang sudah tidak ada; cocok untuk folder media. copy hanya menambah, cocok untuk dump yang retensinya Anda atur terpisah. set -euo pipefail menghentikan skrip pada kesalahan pertama, sehingga backup yang setengah jadi tidak tercatat sebagai berhasil. Dan jangan lupakan berkas konfigurasi dengan rahasia; tanpa .env, aplikasi yang dipulihkan tidak bisa dijalankan.
Enkripsi dengan rclone crypt
Kalau penyimpanan tujuan dikelola pihak lain, enkripsi di sisi Anda sebelum data keluar server:
rclone config create r2crypt crypt remote=r2:backup-server password=$(rclone obscure 'sandi-panjang') filename_encryption=standard
rclone sync /home/webapp/app/media r2crypt:media
Remote r2crypt membungkus r2; nama berkas dan isinya dienkripsi sebelum diunggah. Simpan sandinya di tempat yang tidak ada di server itu sendiri. Backup terenkripsi yang sandinya hilang sama dengan tidak punya backup.
Menjadwalkan dengan Cron
sudo chmod 700 /usr/local/sbin/backup.sh
sudo crontab -e
# setiap hari pukul 02:30
30 2 * * * /usr/local/sbin/backup.sh
Pastikan jam server benar (timedatectl) supaya nama berkas bertanggal dan jadwalnya cocok dengan yang Anda bayangkan; server dengan zona UTC menjalankan "02:30" pada 09:30 WIB.
Cron tidak memuat profil shell, jadi tulis jalur lengkap untuk semua perintah, atau tetapkan PATH di atas crontab. Kalau lebih suka systemd, timer dengan Persistent=true menjalankan backup yang terlewat saat mesin mati; kami membahasnya di artikel tentang systemd. Di VinzaPanel, jadwal yang sama dibuat dari Cron Manager atau dari halaman backup.
Folder Besar dan Batas Bandwidth
Untuk folder dengan ratusan ribu berkas, --fast-list mengurangi jumlah permintaan ke penyimpanan dan mempercepat perbandingan. --bwlimit 8M membatasi unggahan agar backup malam tidak merebut seluruh bandwidth server, dan --bwlimit "08:00,2M 23:00,off" mengatur batas menurut jam. Secara bawaan rclone membandingkan ukuran dan waktu ubah; --checksum membandingkan hash dan lebih teliti tetapi lebih lambat. Tambahkan --log-level INFO --log-file /var/log/rclone.log supaya ada jejak berkas mana yang berubah setiap malam.
Memberi Tahu Saat Gagal
Backup yang gagal diam-diam lebih berbahaya daripada tidak ada backup, karena Anda merasa aman. Cara termudah: di akhir skrip, kirim permintaan ke layanan pemantau "dead man's switch" seperti Healthchecks.io; kalau sinyal tidak datang pada jadwalnya, Anda menerima email. Cara lain, kirim pesan ke Telegram lewat API bot hanya saat skrip keluar dengan kode galat. Dan sekali seminggu, buka bucket dan pastikan berkas terbaru benar-benar bertanggal kemarin.
Retensi dan Biaya
Dump harian disimpan tujuh hari di server (baris find ... -delete) dan lebih lama di bucket. Untuk retensi di bucket, gunakan aturan siklus hidup (lifecycle) penyimpanan, misalnya hapus objek di db/ setelah 30 hari; atau jalankan rclone delete --min-age 30d r2:backup-server/db dari skrip. Untuk situs berukuran beberapa gigabyte, biaya bulanan di R2 atau B2 umumnya di bawah harga secangkir kopi. Backup mingguan yang disimpan lebih lama (misalnya 6 bulan) berguna untuk kasus "data ini rusak sejak kapan, ya?", yang sering baru disadari setelah berminggu-minggu.
Uji Pemulihan
rclone copy r2:backup-server/db/aplikasi-2026-08-20.sql.gz /tmp/
gunzip -c /tmp/aplikasi-2026-08-20.sql.gz | mysql aplikasi_uji
rclone sync r2:backup-server/media /tmp/media-uji --dry-run
Sekali sebulan, pulihkan ke database uji dan hitung beberapa baris tabel penting; bandingkan dengan produksi. Jalankan --dry-run pada media untuk melihat apa yang akan dipulihkan tanpa menulis. Catat berapa lama pemulihan memakan waktu; angka itu yang akan Anda butuhkan saat menjelaskan kepada atasan berapa lama situs akan kembali. Backup yang tidak pernah dipulihkan hanyalah harapan, dan harapan bukan rencana pemulihan bencana.
Sampai jumpa, Rekan ArtonLabs. Jadwalkan satu uji pemulihan bulan ini; itu permintaan kecil kami setelah Anda membaca tulisan ini.