Backup Homelab dengan Restic: Aturan 3-2-1 yang Automatis
Backup Bukan Backup Sampai Bisa Dipulihkan
Hampir semua orang punya backup. Hampir tidak ada yang pernah tes restore. Dua hal itu berbeda jauh, dan yang kedua menentukan apakah backup itu benar-benar berguna.
Di homelab, biasanya backup berupa file tar.gz yang ditulis ke disk USB setiap akhir pekan. Masalahnya: disk USB gagal, formatnya rusak, atau file tar.gz terakhir hanya berisi symlink yang menunjuk ke data yang sudah berubah. Semua lolos karena tidak ada yang pernah mencoba memulihkan.
Yang kita mau-built bukan sekadar menyalin file, tapi sistem yang punya sifat berikut:
- Terjadual otomatis tanpa perlu diingat manusia.
- Menyimpan banyak versi, bukan cuma versi terakhir.
- Hanya menyalin bagian yang berubah, sehingga tidak menggandakan 500 GB setiap hari.
- Bisa di-restore ke tempat mana pun, bukan hanya ke server asalnya.
Restic menjawab semua itu, dan jalan mulus di Docker.
Aturan 3-2-1
Sebelum masuk ke konfigurasi, pahami dulu aturan dasarnya:
- Tiga salinan dari data penting.
- Dua media atau lokasi berbeda.
- Satu salinan yang tidak tersentuh di lokasi utama.
Contoh penerapan di homelab:
| Salinan | Lokasi | Media |
|---|---|---|
| 1 | Disk lokal server | NVMe |
| 2 | Disk eksternal atau NAS | HDD |
| 3 | Object storage | S3-compatible |
Bucket S3 adalah pilihan ketiga yang murah dan jauh dari rumah. Kalau provider S3 yang dipakai punya Immutable Object Lock, itu satu lapis tambahan terhadap ransomware yang menyamar jadi proses backup.
Kenapa Restic, Bukan Borg atau rsync
Restic menyimpan data dalam bentuk blob yang di-address lewat hash isi file. Konsekuensinya:
- Deduplikasi otomatis. File identik di dua folder hanya disimpan sekali.
- Deduplikasi lintas backup. Snapshot kedua hanya membawa blok yang berubah sejak snapshot pertama.
- Enkripsi bawaan (AES-256) plus hashing SHA-256 untukChecking integritas.
- Format repo seragam: lokal, SFTP, S3, B2, REST. Semuanya sama.
Perbandingan dengan rsync incremental: rsync menyalin langsung dari filesystem, sehingga membutuhkan file asli untuk restore, dan tidak bisa menentukan file mana yang berubah sejak snapshot terakhir tanpa membaca semua metadata. Restic menyimpan blok, jadi cepat dan aman disimpan di media yang hanya bisa ditulis sekali.
Siapkan Credential
Jangan tuliskan password di dalam command atau di dalam file compose. Pakai environment file dengan permission ketat.
Buat dulu API key dari provider S3 Anda, lalu simpan credential-nya di file terpisah:
install -d -m 700 /mnt/data/ayahzahra/secrets
tee /mnt/data/ayahzahra/secrets/restic.env >/dev/null <<'EOF'
RESTIC_REPOSITORY=s3:s3.example.net/homelab-backup
AWS_ACCESS_KEY_ID=ISI_DENGAN_KEY_ANDA
AWS_SECRET_ACCESS_KEY=ISI_DENGAN_SECRET_ANDA
EOF
chmod 600 /mnt/data/ayahzahra/secrets/restic.env
Password repo harus panjang dan acak. Kalau hilang, semua snapshot jadi tidak terbaca selamanya. Simpan di password manager, bukan hanya di server ini.
openssl rand -base64 32 > /mnt/data/ayahzahra/secrets/restic_password
chmod 600 /mnt/data/ayahzahra/secrets/restic_password
docker-compose.yml
services:
backup:
image: restic/restic:0.17.3
container_name: homelab-backup
restart: unless-stopped
volumes:
- /mnt/data/ayahzahra:/source:ro
- /mnt/data/ayahzahra/secrets/restic_password:/run/secrets/restic_password:ro
env_file:
- /mnt/data/ayahzahra/secrets/restic.env
environment:
RESTIC_PASSWORD_FILE: /run/secrets/restic_password
entrypoint: ["/bin/sh", "-c"]
command: >
restic backup /source
--tag homelab
--exclude /source/.Trash
--exclude /source/node_modules
--exclude '*.tmp'
healthcheck:
test: ["CMD-SHELL", "restic snapshots --last 1 >/dev/null 2>&1"]
interval: 1h
timeout: 30s
retries: 3
Kunci penting di sini:
:ropada mount/source. Kalau proses backup somehow bisa menulis ke sumber, Anda sedang menyalin data dari dirinya sendiri.--tag homelabsupaya snapshot bisa difilter saat prune.- Exclude untuk cache besar yang tidak pernah berguna di-backup:
node_modules, cache build,.Trash.
Inisialisasi Repo dan Jadwal Cron
Sekali saja:
cd /opt/homelab
docker compose up -d backup
docker exec homelab-backup restic init
docker exec homelab-backup restic snapshots
Lalu pasang jadwal. Backup harian jam 03:15, di luar jam sibuk:
15 3 * * * cd /opt/homelab && docker exec homelab-backup restic backup /source --tag homelab --exclude /source/.Trash >> /var/log/homelab-backup.log 2>&1
Snapshot retensi: simpan 7 harian, 4 mingguan, 6 bulanan. Perintah prune yang aman dijalankan setiap akhir pekan:
docker exec homelab-backup restic forget \
--tag homelab \
--keep-daily 7 --keep-weekly 4 --keep-monthly 6 \
--prune
Selalu jalankan --prune dalam perintah yang sama dengan forget. Kalau terpisah, repo akan membengkak karena snapshot yang sudah dianggapkedua masih menyimpan blob-nya sampai prune dijalankan.
Pantau Snapshot Terakhir
Backup yang gagal diam-diam adalah skenario terburuk. Poll status snapshot terakhir dari script kecil:
#!/usr/bin/env bash
set -euo pipefail
LAST=$(docker exec homelab-backup restic snapshots --last 1 --json | jq -r '.[0].time')
AGE=$(( ($(date +%s) - $(date -d "$LAST" +%s)) / 3600 ))
if [ "$AGE" -gt 26 ]; then
echo "Backup terakhir sudah ${AGE} jam lalu"
exit 1
fi
echo "Backup terakhir ${AGE} jam lalu, OK"
Pasang sebagai pemeriksaan berkala, atau kirim output ke kanal notifikasi. Kalau ini tidak alerted, Anda akan baru tahu backup rusak saat benar-benar butuh restore.
Uji Restore yang Benar
Ini bagian yang paling sering dilewati, dan justru paling menentukan.
Uji restore ke lokasi baru, bukan menimpa file asalnya:
# lihat isi snapshot terbaru
docker exec homelab-backup restic ls latest --tag homelab
# restore satu direktori ke path sementara
docker exec homelab-backup restic restore latest \
--tag homelab --include /source/ayahzahra/data \
--target /tmp/restore-test
Lalu verifikasi dua hal:
- File benar-benar ada di
target, ukurannya cocok dengan aslinya. - Isinya bukan file kosong. Kalau bind mount salah,
restoretetap keluar sukses tapi folder tujuan kosong.
Kalau snapshot berasal dari database yang sedang berjalan, restore file-nya saja tidak cukup. Untuk SQLite, dump dulu secara logis, baru backup hasil dump-nya. Untuk Nextcloud, database dan direktori data harus berasal dari waktu yang konsisten.
Contoh dump sebelum backup:
docker exec nextcloud-db sqlite3 /var/www/html/data/nextcloud.db \
".backup '/var/www/html/data/backup/nextcloud-$(date +%F).db'"
Uji restore sebaiknya dijadwalkan juga, misalnya tiap awal bulan, dan hasilnya cukup berupa jumlah file atau checksum, bukan dump penuh ke disk lokal.
Hal yang Sering Terlewat
- Waktu: snapshot hanya konsisten kalau tidak ada file yang berubah saat dibaca. Untuk data statis seperti foto dan dokumen, tidak masalah. Untuk database dan virtual disk, dump dulu.
- Log: simpan output backup minimal 30 hari. Log yang tidak disimpan tidak bisa dipakai saat lupa password atau saat snapshot benar-benar gagal.
- Offsite: repo di tempat yang sama dengan rumah berarti satu ransomware bisa menghapus semuanya.
- Uji restore: jalankan terjadwal dan laporkan hasilnya, bukan hanya dijalankan lalu ditinggal.
Kesimpulan
Setup Restic di Docker cukup tiga langkah: inisialisasi repo, jadwal backup harian, dan forget --prune mingguan. Yang menentukan kualitasnya bukan langkah-langkah tersebut, tapi tiga hal tambahan: password repo disimpan di tempat aman, satu salinan benar-benar offsite, dan restore diuji secara terjadwal.
Backup yang tidak pernah dipulihkan bukan backup. Ia hanya memberi rasa aman.