Backup dan Restore Database

Backup dan Restore Database

Bitnesia • Aug 27, 2026 63 •EN

Bab 22 menutup rangkaian instalasi database di Bagian V dengan memasang web UI untuk PostgreSQL, MySQL/MariaDB, dan MongoDB. Bab 23 mengangkat topik yang justru paling sering diabaikan sampai insiden nyata benar-benar terjadi: backup dan restore database. Query DROP TABLE yang salah sasaran, disk yang rusak mendadak, atau serangan ransomware yang mengenkripsi seluruh data production hanya butuh hitungan detik untuk terjadi. Sementara itu, proses pemulihannya bisa memakan waktu berjam-jam kalau Sysadmin tidak pernah menyiapkan strategi backup yang teruji sebelumnya. Kita akan memahami perbedaan mendasar antara backup logical dan physical, mempraktikkan backup serta restore untuk keempat database yang sudah berjalan sejak Bab 18 sampai Bab 21 (PostgreSQL, MySQL, MariaDB, dan MongoDB), menulis satu script bash yang mengotomasi seluruh proses dump, kompresi, dan retention sekaligus, lalu menutup bab dengan menjadwalkan script tersebut lewat systemd timer agar backup berjalan sendiri tanpa perlu diingat-ingat secara manual setiap hari.

23.1 Strategi Backup: Logical vs Physical

Setiap tool backup database bekerja lewat salah satu dari dua pendekatan besar: logical backup atau physical backup. Logical backup membaca data lewat query normal ke database yang sedang berjalan, lalu menuliskan hasilnya sebagai representasi terstruktur seperti perintah SQL atau dokumen BSON, persis seperti cara kerja mariadb-dump yang sudah sempat kita praktikkan di Bagian 20.4. Sebaliknya, physical backup menyalin langsung file mentah tempat database menyimpan datanya di disk (data directory), tanpa peduli struktur logis di dalamnya sama sekali.

AspekLogical BackupPhysical Backup
Cara kerjaMembaca data lewat query, menulis ulang sebagai SQL/dokumenMenyalin file data mentah di data directory
Contoh toolpg_dump, mysqldump, mariadb-dump, mongodumppg_basebackup, mariadb-backup, snapshot filesystem/LVM
PortabilitasTinggi, hasil dump bisa dipindah antar versi dan platform berbedaRendah, umumnya wajib versi dan arsitektur yang identik
Kecepatan restore pada dataset besarRelatif lambat, karena setiap baris ditulis ulang lewat queryJauh lebih cepat, karena hanya menyalin file kembali ke tempatnya
GranularitasBisa per database atau per table/collection tertentuUmumnya seluruh instance/cluster sekaligus

Bab ini berfokus pada logical backup lewat pg_dump, mysqldump, mariadb-dump, dan mongodump, karena portabilitasnya paling cocok untuk kebutuhan harian Sysadmin: memindahkan data antar server, antar lingkungan development dan production, atau sekadar menyimpan salinan yang mudah diperiksa isinya lewat editor teks biasa. Physical backup tetap punya tempatnya sendiri, terutama untuk database berukuran ratusan gigabyte ke atas yang waktu restore-nya menjadi krusial saat insiden terjadi, lewat tool resmi seperti pg_basebackup bawaan PostgreSQL, mariadb-backup untuk MariaDB, atau sekadar snapshot LVM seperti yang sudah kita praktikkan di Bagian 7.2.3 pada level filesystem. Pembahasan mendalam ketiga tool physical backup tersebut berada di luar cakupan bab ini. Namun, prinsip snapshot LVM dari Bagian 7.2.3 sudah cukup untuk memberi gambaran bagaimana physical backup bekerja tanpa perlu menghentikan service database yang sedang aktif.

Catatan dari lapangan yang berlaku untuk kedua pendekatan ini: backup yang tidak pernah diuji proses restore-nya bukanlah backup yang bisa diandalkan. Banyak insiden kehilangan data justru baru terungkap saat proses restore darurat sedang sangat dibutuhkan, yaitu ketika ternyata file dump korup, kredensial sudah kedaluwarsa, atau script backup diam-diam gagal berbulan-bulan tanpa ada yang menyadarinya. Prinsip ini akan kita perdalam lagi lewat strategi 3-2-1 pada Bab 40.

23.2 Backup dan Restore PostgreSQL dengan pg_dump dan pg_restore

pg_dump dan pg_restore sudah terpasang otomatis sejak instalasi PostgreSQL di Bagian 18.1.2 sebagai bagian dari paket client, sehingga tidak ada langkah instalasi tambahan yang perlu dilakukan di sini. Keduanya terhubung ke database melalui cara yang identik dengan psql, memakai role webapp_user yang sudah dibuat di Bagian 18.3.1, bukan role superuser postgres yang seharusnya hanya dipegang Sysadmin untuk keperluan administratif.

23.2.1 Backup dengan pg_dump dan Pilihan Format Dump

pg_dump mendukung beberapa format keluaran sekaligus lewat flag -F. Format plain (-F p) menghasilkan file teks SQL biasa yang mudah dibaca dan diedit manual, format custom (-F c) menghasilkan file biner terkompresi yang mendukung restore selektif lewat pg_restore, sedangkan format directory (-F d) memecah dump menjadi banyak file dalam satu folder agar bisa di-dump secara paralel lewat flag -j. Format custom menjadi pilihan paling umum untuk backup rutin karena ukurannya lebih kecil dan fleksibel saat restore.

Langkah Praktik

  1. Siapkan direktori tempat menyimpan hasil backup.
    sudo mkdir -p /var/backups/database
  2. Jalankan pg_dump dengan format custom terhadap database webapp_db.
    pg_dump -h 127.0.0.1 -U webapp_user -d webapp_db -F c -f /var/backups/database/webapp_db.dump
    Perintah ini meminta password webapp_user secara interaktif, sesuai rule scram-sha-256 untuk koneksi TCP yang sudah dibahas di Bagian 18.2.1. Cara menyiapkan password secara non-interaktif untuk kebutuhan script otomasi dibahas terpisah di Bagian 23.6.1.

Verifikasi dan Troubleshooting

  • Periksa ukuran file hasil dump, pastikan tidak nol byte.
    ls -lh /var/backups/database/webapp_db.dump
  • Perintah file /var/backups/database/webapp_db.dump pada file yang sehat biasanya mengembalikan label PostgreSQL custom database dump. Ini merupakan cara cepat memastikan file benar-benar dump PostgreSQL yang valid, bukan file kosong atau rusak akibat proses yang terputus di tengah jalan.
  • Pesan pg_dump: error: connection to server ... failed biasanya berarti PostgreSQL belum berjalan atau alamat host salah ketik, sedangkan FATAL: password authentication failed menandakan password webapp_user salah, identik dengan troubleshooting koneksi di Bagian 18.3.1.

23.2.2 Restore dengan pg_restore dan psql

Cara restore berbeda tergantung format dump yang dipakai saat backup. File format plain dieksekusi langsung lewat psql sebagai kumpulan perintah SQL biasa, sedangkan file format custom maupun directory wajib memakai pg_restore karena isinya berupa arsip biner, bukan teks SQL murni.

Langkah Praktik

  1. Buat database baru sebagai tujuan restore, mensimulasikan skenario pemulihan ke server yang berbeda dari sumber backup.
    sudo -u postgres psql -c "CREATE DATABASE webapp_db_restore OWNER webapp_user;"
  2. Restore file dump format custom ke database baru tersebut.
    pg_restore -h 127.0.0.1 -U webapp_user -d webapp_db_restore --no-owner /var/backups/database/webapp_db.dump
    Flag --no-owner mengabaikan perintah kepemilikan object yang tersimpan di dalam dump, berguna saat role di server tujuan restore tidak persis sama dengan role di server sumber backup.
  3. Untuk melihat isi dump tanpa benar-benar menjalankannya, gunakan opsi --list sebagai daftar isi (table of contents) dump.
    pg_restore --list /var/backups/database/webapp_db.dump

Verifikasi dan Troubleshooting

  • Konfirmasikan data benar-benar utuh dengan membandingkan isi table notes dari Bagian 18.3.2 di database hasil restore.
    psql -h 127.0.0.1 -U webapp_user -d webapp_db_restore -c "SELECT * FROM notes;"
  • Pesan pg_restore: error: could not execute query: ERROR: relation "notes" already exists muncul jika target database sudah berisi table yang sama. Tambahkan flag --clean --if-exists agar pg_restore menghapus object lama terlebih dahulu sebelum membuatnya ulang. Namun, perlu diingat bahwa flag ini bersifat destruktif terhadap data yang sudah ada di database tujuan.
  • Restore dari file format plain memakai psql, bukan pg_restore.
    psql -h 127.0.0.1 -U webapp_user -d webapp_db_restore -f /var/backups/database/webapp_db.sql

23.3 Backup dan Restore MySQL dengan mysqldump

mysqldump sudah tersedia sejak instalasi paket mysql-server di Bagian 19.2.1, sebagai bagian dari mysql-client yang ikut terpasang sebagai dependency. Skenario di sini melanjutkan database webapp_db dan account webapp_user yang sudah dibuat di Bagian 19.3.2.

23.3.1 Backup dengan mysqldump

Langkah Praktik

  1. Jalankan mysqldump dengan opsi --single-transaction agar dump table InnoDB diambil dari satu snapshot transaksi yang konsisten, tanpa mengunci tabel dan menghentikan sementara akses aplikasi yang sedang menulis data.
    mysqldump -u webapp_user -p --single-transaction webapp_db > /var/backups/database/webapp_db.sql
    Opsi --single-transaction secara otomatis menonaktifkan penguncian table selama proses dump berjalan. Namun, konsistensinya hanya terjamin penuh untuk table bermesin storage InnoDB. Table lama bermesin MyISAM tetap membutuhkan penguncian singkat saat di-dump, sehingga pola migrasi ke InnoDB yang sudah menjadi default MySQL sejak versi 5.5 tetap relevan untuk diperhatikan Sysadmin yang mewarisi database lawas.
  2. Mampatkan hasil dump langsung lewat pipe ke gzip untuk menghemat ruang disk, pola yang akan dipakai ulang pada script otomasi di Bagian 23.6.2.
    mysqldump -u webapp_user -p --single-transaction webapp_db | gzip > /var/backups/database/webapp_db.sql.gz

Verifikasi dan Troubleshooting

  • Dump yang berhasil sampai selesai selalu diakhiri baris komentar -- Dump completed on beserta timestamp di baris paling akhir file. Cara cepat memeriksa dump tidak terpotong di tengah jalan (misalnya akibat koneksi jaringan putus atau disk penuh) adalah memastikan baris ini benar-benar ada.
    tail -n 3 /var/backups/database/webapp_db.sql
  • Pesan mysqldump: Got error: 1045: Access denied menandakan password salah, identik dengan troubleshooting login MySQL di Bagian 19.3.2.

23.3.2 Restore dari File Dump

Langkah Praktik

  1. Buat database tujuan restore terlebih dahulu, karena mysqldump secara default tidak menyertakan perintah CREATE DATABASE kecuali dijalankan dengan flag tambahan --databases.
    mysql -u webapp_user -p -e "CREATE DATABASE webapp_db_restore;"
  2. Restore file SQL ke database yang baru dibuat.
    mysql -u webapp_user -p webapp_db_restore < /var/backups/database/webapp_db.sql
  3. Jika sumber dump berupa file terkompresi, dekompresi lewat pipe tanpa perlu menyimpan file mentah sementara.
    gunzip -c /var/backups/database/webapp_db.sql.gz | mysql -u webapp_user -p webapp_db_restore

Verifikasi dan Troubleshooting

  • Konfirmasikan struktur dan isi table sudah kembali seperti semula.
    mysql -u webapp_user -p webapp_db_restore -e "SHOW TABLES;"
  • Pesan ERROR 1049 (42000): Unknown database berarti langkah pembuatan database tujuan pada langkah pertama belum dijalankan atau salah ketik nama database-nya.

23.4 Backup dan Restore MariaDB dengan mariadb-dump

Bagian 20.4 sudah membahas mariadb-dump secara mendalam, termasuk directive sandbox mode yang otomatis disisipkan sejak MariaDB 11.0 sebagai mitigasi celah keamanan MDEV-21778. Bagian ini melengkapi praktik tersebut melalui alur backup dan restore yang konsisten dengan pola PostgreSQL dan MySQL di atas, memakai account webapp_user alih-alih root agar sesuai dengan kebutuhan script otomasi non-interaktif di Bagian 23.6.

23.4.1 Backup dan Restore dengan mariadb-dump

Langkah Praktik

  1. Backup database webapp_db memakai account webapp_user yang sudah memiliki privilege ALL PRIVILEGES sejak Bagian 20.3.1, cukup untuk menjalankan mariadb-dump tanpa perlu privilege tambahan apa pun.
    mariadb-dump -u webapp_user -p --single-transaction webapp_db > /var/backups/database/webapp_db_mariadb.sql
  2. Restore ke database baru, dengan asumsi client mariadb yang dipakai sudah mendukung directive sandbox mode sesuai daftar versi di Bagian 20.4.1, sehingga baris pertama file dump tidak perlu dipotong.
    sudo mariadb -e "CREATE DATABASE webapp_db_restore;"
    mariadb -u webapp_user -p webapp_db_restore < /var/backups/database/webapp_db_mariadb.sql

Verifikasi dan Troubleshooting

  • Jika restore dilakukan ke server MariaDB versi lawas atau ke MySQL, terapkan kembali trik tail -n +2 yang sudah dibahas tuntas di Bagian 20.4.2 untuk melewati baris directive sandbox mode.
  • Pesan error dan cara verifikasi lainnya identik dengan Bagian 23.3.2, karena MariaDB mewarisi format pesan error dari basis kode MySQL yang sama.

23.5 Backup dan Restore MongoDB dengan mongodump dan mongorestore

mongodump dan mongorestore sudah terpasang sejak instalasi mongodb-org di Bagian 21.2.2, sebagai bagian dari paket mongodb-org-tools yang memang sudah disiapkan sejak awal untuk kebutuhan bab ini. Skenario melanjutkan database webapp_catalog dan account webapp_user yang dibuat di Bagian 21.4.2, lengkap dengan authentication yang sudah diaktifkan sejak Bagian 21.4.1.

23.5.1 Backup dengan mongodump

Langkah Praktik

  1. Jalankan mongodump memakai flag --archive agar seluruh collection digabung menjadi satu file stream, dilengkapi flag --gzip untuk kompresi langsung tanpa proses tambahan.
    mongodump --uri="mongodb://webapp_user:[email protected]:27017/webapp_catalog?authSource=webapp_catalog" --archive=/var/backups/database/webapp_catalog.archive --gzip
    Parameter authSource=webapp_catalog di dalam connection string ini setara dengan flag --authenticationDatabase webapp_catalog yang sudah dipakai di Bagian 21.4.2, karena user webapp_user memang dibuat di database webapp_catalog, bukan di database admin.

Verifikasi dan Troubleshooting

  • Periksa ukuran file arsip hasil backup.
    ls -lh /var/backups/database/webapp_catalog.archive
  • Pesan Authentication failed biasanya berarti kombinasi username, password, atau nilai authSource tidak cocok, identik dengan troubleshooting login MongoDB di Bagian 21.4.2.

23.5.2 Restore dengan mongorestore

Langkah Praktik

  1. Restore arsip ke database yang sama menggunakan mongorestore, memakai flag --archive dan --gzip yang sama persis dengan flag backup.
    mongorestore --uri="mongodb://webapp_user:[email protected]:27017/webapp_catalog?authSource=webapp_catalog" --archive=/var/backups/database/webapp_catalog.archive --gzip
    Tanpa flag tambahan apa pun, mongorestore hanya menambahkan dokumen baru ke collection yang sudah ada, sehingga dokumen dengan nilai _id yang sama akan gagal disisipkan ulang dan dilaporkan sebagai error duplikat, bukan menimpa data lama.

Verifikasi dan Troubleshooting

  • Konfirmasikan jumlah dokumen di collection products dari Bagian 21.3.2 sudah kembali seperti sebelum backup.
    mongosh -u webapp_user -p --authenticationDatabase webapp_catalog webapp_catalog --eval "db.products.countDocuments()"
  • Flag --drop membuat mongorestore menghapus terlebih dahulu setiap collection yang namanya cocok dengan isi arsip sebelum menuliskan data baru, berguna untuk skenario pemulihan penuh yang sengaja menimpa seluruh data lama. Perlakukan flag ini dengan hati-hati karena bersifat destruktif dan tidak bisa dibatalkan; jangan pernah menjalankannya ke database production tanpa memastikan lebih dulu bahwa arsip sumbernya benar-benar valid dan lengkap.

23.6 Script Bash Otomasi Backup Multi-Database

Menjalankan empat perintah dump secara manual setiap hari jelas tidak realistis untuk kebutuhan production. Bagian ini menyusun satu script bash yang menjalankan backup keempat database sekaligus, mengompresnya, lalu menghapus file backup lama sesuai kebijakan retention, yaitu batas usia file backup yang masih boleh disimpan sebelum dihapus otomatis untuk mencegah disk penuh. Pola ini mengikuti kebiasaan task administrasi otomatis yang akan diperdalam lagi di Bab 35. Perlu dicatat lebih dulu satu batasan penting: MySQL dan MariaDB tidak boleh berjalan bersamaan di satu server yang sama seperti sudah diperingatkan di Bagian 20.1.1. Oleh karena itu, pada praktiknya script ini hanya mengaktifkan salah satu blok MySQL atau MariaDB sesuai database yang benar-benar berjalan di server tersebut, bukan menjalankan keduanya sekaligus dalam satu host yang sama.

23.6.1 Menyiapkan Kredensial Non-Interaktif secara Aman

Script yang berjalan otomatis lewat systemd timer di Bagian 23.7 tidak bisa mengetikkan password secara interaktif, sehingga kredensial harus tersimpan di file yang dibaca langsung oleh masing-masing tool. Setiap database punya konvensinya sendiri, dan menuliskan password polos langsung di dalam script adalah kebiasaan buruk yang harus dihindari karena isi script mudah terbaca siapa pun yang punya akses baca ke file tersebut.

Langkah Praktik

  1. Buat user sistem khusus untuk menjalankan seluruh proses backup, mengikuti prinsip least privilege yang sama seperti Bagian 5.2.2, Bagian 15.6.2, dan Bagian 22.3.1.
    sudo useradd --system --no-create-home --shell /usr/sbin/nologin backupdb
  2. Buat direktori khusus untuk menyimpan seluruh file kredensial, dibatasi hanya bisa diakses oleh user backupdb itu sendiri.
    sudo mkdir -p /etc/backup-db
    sudo chown backupdb:backupdb /etc/backup-db
    sudo chmod 700 /etc/backup-db
  3. Buat file .pgpass untuk PostgreSQL, mengikuti format resmi hostname:port:database:username:password yang didokumentasikan langsung oleh proyek PostgreSQL.
    sudo -u backupdb nano /etc/backup-db/pgpass
    127.0.0.1:5432:webapp_db:webapp_user:S4ngatRahasiaPG!2026
    File ini wajib berpermission 600, karena PostgreSQL akan mengabaikan seluruh isinya begitu saja jika permission-nya lebih longgar dari itu.
    sudo chmod 600 /etc/backup-db/pgpass
  4. Buat option file untuk MySQL atau MariaDB (sesuaikan salah satu, tergantung database yang aktif di server ini), berformat [client] yang didukung langsung oleh client mysql/mariadb lewat flag --defaults-extra-file.
    sudo -u backupdb nano /etc/backup-db/db-credentials.cnf
    [client]
    user=webapp_user
    password=S4ngatRahasia!2026
    sudo chmod 600 /etc/backup-db/db-credentials.cnf
    Catatan dari lapangan yang penting: flag --defaults-extra-file wajib diletakkan sebagai argumen paling pertama pada perintah mysqldump/mariadb-dump, sebelum flag apa pun yang lain. Meletakkannya di posisi lain membuat client mengabaikannya begitu saja tanpa pesan error yang jelas, kesalahan yang sering membuat Sysadmin baru bingung kenapa file kredensial "tidak terbaca".
  5. Buat file berisi environment variable untuk MongoDB, karena mongodump/mongorestore tidak memiliki mekanisme option file resmi seperti tiga database relasional di atas.
    sudo -u backupdb nano /etc/backup-db/mongo.env
    MONGO_USER=webapp_user
    MONGO_PASSWORD=PasswordWebappCatalog!2026
    MONGO_AUTH_DB=webapp_catalog
    sudo chmod 600 /etc/backup-db/mongo.env

Verifikasi dan Troubleshooting

  • Uji file pgpass langsung tanpa script, pastikan pg_dump tidak lagi meminta password secara interaktif.
    sudo -u backupdb env PGPASSFILE=/etc/backup-db/pgpass pg_dump -h 127.0.0.1 -U webapp_user -d webapp_db -F c -f /tmp/test.dump
  • Jika PostgreSQL tetap menampilkan prompt password, periksa kembali permission file pgpass dengan ls -la /etc/backup-db/pgpass, harus persis -rw-------.
  • Ganti seluruh nilai password contoh di atas dengan password kuat milik sendiri sebelum dipraktikkan di server sungguhan, dan jangan pernah menaruh keempat file kredensial ini ke dalam version control seperti Git.
  • Catatan jujur soal risiko pendekatan environment variable untuk MongoDB: berbeda dari pgpass dan option file yang tidak pernah menaruh password sebagai argumen command line, connection string berisi password pada langkah mongodump/mongorestore nanti tetap sempat terlihat lewat ps aux atau isi /proc/<pid>/cmdline oleh user lain di server yang sama selama proses berjalan, karena Mongo shell tools memang belum menyediakan mekanisme option file resmi seperti tiga database relasional di atas. Batasi akses shell lokal server hanya untuk Sysadmin tepercaya sebagai mitigasi, dan jangan anggap risiko ini sepenuhnya identik dengan tiga metode kredensial lainnya.

23.6.2 Menulis Script Backup: Dump, Kompresi, dan Retention

Langkah Praktik

  1. Buat file script baru.
    sudo nano /usr/local/bin/backup-database.sh
  2. Isi dengan script berikut. Blok MySQL dan blok MariaDB sengaja ditulis berdampingan; aktifkan hanya salah satunya dengan menghapus tanda pagar # di baris yang relevan, sesuai database yang benar-benar berjalan di server ini.
    #!/bin/bash
    set -euo pipefail
    
    BACKUP_DIR="/var/backups/database"
    RETENTION_DAYS=7
    TIMESTAMP=$(date +%Y%m%d-%H%M%S)
    CRED_DIR="/etc/backup-db"
    
    mkdir -p "$BACKUP_DIR"
    
    echo "[$(date '+%F %T')] Memulai backup database"
    
    # PostgreSQL
    PGPASSFILE="$CRED_DIR/pgpass" pg_dump -h 127.0.0.1 -U webapp_user -d webapp_db \
      -F c -f "$BACKUP_DIR/postgresql-webapp_db-$TIMESTAMP.dump"
    echo "[$(date '+%F %T')] Backup PostgreSQL selesai"
    
    # MySQL (aktifkan baris ini jika server menjalankan MySQL)
    # mysqldump --defaults-extra-file="$CRED_DIR/db-credentials.cnf" --single-transaction webapp_db \
    #   | gzip > "$BACKUP_DIR/mysql-webapp_db-$TIMESTAMP.sql.gz"
    
    # MariaDB (aktifkan baris ini jika server menjalankan MariaDB)
    # mariadb-dump --defaults-extra-file="$CRED_DIR/db-credentials.cnf" --single-transaction webapp_db \
    #   | gzip > "$BACKUP_DIR/mariadb-webapp_db-$TIMESTAMP.sql.gz"
    
    # MongoDB
    mongodump --uri="mongodb://${MONGO_USER}:${MONGO_PASSWORD}@127.0.0.1:27017/${MONGO_AUTH_DB}?authSource=${MONGO_AUTH_DB}" \
      --archive="$BACKUP_DIR/mongodb-webapp_catalog-$TIMESTAMP.archive" --gzip
    echo "[$(date '+%F %T')] Backup MongoDB selesai"
    
    # Retention: hapus file backup yang lebih tua dari RETENTION_DAYS
    find "$BACKUP_DIR" -type f -mtime +"$RETENTION_DAYS" -delete
    echo "[$(date '+%F %T')] Retention diterapkan, file lebih dari $RETENTION_DAYS hari dihapus"
    
    echo "[$(date '+%F %T')] Backup database selesai"
    Baris set -euo pipefail di awal script menghentikan eksekusi begitu ada satu perintah yang gagal, termasuk kegagalan di tengah pipe seperti mysqldump | gzip, alih-alih membiarkan script terus berjalan seolah semuanya baik-baik saja padahal salah satu tahap backup sudah gagal diam-diam. Pembahasan lebih mendalam soal error handling di script shell menyusul di Bab 35.
  3. Jadikan script bisa dieksekusi, lalu serahkan kepemilikan script beserta direktori backup dari Bagian 23.2.1 ke user backupdb, karena proses ini nantinya berjalan sebagai user tersebut, bukan root.
    sudo chmod +x /usr/local/bin/backup-database.sh
    sudo chown backupdb:backupdb /usr/local/bin/backup-database.sh
    sudo chown backupdb:backupdb /var/backups/database
  4. Uji jalankan script secara manual sebagai user backupdb, dengan environment variable MongoDB dimuat lebih dulu dari file mongo.env.
    sudo -u backupdb bash -c 'set -a; source /etc/backup-db/mongo.env; set +a; /usr/local/bin/backup-database.sh'

Verifikasi dan Troubleshooting

  • Pastikan seluruh file dump baru muncul di direktori backup dengan timestamp hari ini.
    ls -lh /var/backups/database
  • Cek exit code script secara eksplisit untuk memastikan tidak ada tahap yang gagal secara diam-diam.
    echo $?
  • Error Permission denied saat script mencoba membaca file di /etc/backup-db biasanya berarti kepemilikan atau permission file kredensial belum sesuai dengan user backupdb yang menjalankan script, cek ulang langkah-langkah di Bagian 23.6.1.
  • Pesan MONGO_USER: unbound variable muncul jika script dijalankan langsung tanpa memuat mongo.env lebih dulu, karena baris set -euo pipefail di awal script membuat bash langsung berhenti begitu menemukan variable yang belum pernah didefinisikan. Kegagalan cepat ini sengaja dipertahankan, bukan dianggap bug, karena jauh lebih aman daripada mongodump terlanjur jalan dengan username/password kosong.

23.7 Menjadwalkan Backup Otomatis dengan Systemd Timer

Script yang sudah teruji manual di Bagian 23.6.2 tinggal dijadwalkan lewat pasangan service dan timer unit systemd, mengikuti pola yang sama persis dengan Bagian 5.3.1.

23.7.1 Membuat Service dan Timer Unit

Langkah Praktik

  1. Buat service unit dengan Type=oneshot, karena job ini dijalankan sekali per jadwal lalu selesai, bukan proses yang hidup terus-menerus.
    sudo nano /etc/systemd/system/backup-database.service
    [Unit]
    Description=Backup Otomatis Database (PostgreSQL, MySQL/MariaDB, MongoDB)
    After=network.target
    
    [Service]
    Type=oneshot
    User=backupdb
    Group=backupdb
    EnvironmentFile=/etc/backup-db/mongo.env
    ExecStart=/usr/local/bin/backup-database.sh
    Directive EnvironmentFile membaca pasangan KEY=VALUE dari /etc/backup-db/mongo.env lalu menyuntikkannya sebagai environment variable proses, menggantikan langkah source manual yang dipakai saat pengujian di Bagian 23.6.2.
  2. Buat timer unit dengan nama dasar yang sama persis, agar systemd otomatis mengaitkan keduanya tanpa directive tambahan, dijadwalkan setiap dini hari pukul 01.00.
    sudo nano /etc/systemd/system/backup-database.timer
    [Unit]
    Description=Jadwal Backup Otomatis Database
    
    [Timer]
    OnCalendar=*-*-* 01:00:00
    Persistent=true
    RandomizedDelaySec=300
    
    [Install]
    WantedBy=timers.target
    Sama seperti penjelasan di Bagian 5.3.1, Persistent=true memastikan backup tetap terpicu begitu server kembali menyala jika ternyata sedang mati saat jadwal seharusnya berjalan, sedangkan RandomizedDelaySec mencegah beban I/O menumpuk di detik yang sama persis jika pola ini nantinya dipasang di banyak server sekaligus.
  3. Reload systemd, lalu enable dan start timer-nya, bukan service-nya secara langsung.
    sudo systemctl daemon-reload
    sudo systemctl enable --now backup-database.timer

Verifikasi dan Troubleshooting

  • Lihat jadwal eksekusi berikutnya beserta seluruh timer aktif lain di server ini.
    systemctl list-timers
  • Untuk menguji job tanpa menunggu jadwal pukul 01.00 tiba, trigger service-nya secara manual.
    sudo systemctl start backup-database.service
  • Periksa hasil eksekusi lewat log, termasuk seluruh baris echo yang ditulis script di Bagian 23.6.2.
    journalctl -u backup-database.service -n 50
  • Jika service gagal dengan status Permission denied pada EnvironmentFile, pastikan file /etc/backup-db/mongo.env tetap bisa dibaca oleh user backupdb yang didefinisikan lewat directive User=, bukan hanya oleh root.
  • Backup yang sudah berjalan otomatis lewat timer ini tetap harus diuji proses restore-nya secara berkala, bukan sekadar dipastikan file dump-nya ada. Kebiasaan menguji restore secara rutin inilah yang membedakan strategi backup yang benar-benar bisa diandalkan dari strategi backup yang baru "kelihatan aman", topik yang dibahas lebih dalam lewat prinsip 3-2-1 pada Bab 40, termasuk kebutuhan menyalin hasil backup ini ke lokasi off-site seperti cloud storage yang disinggung pada Bab 41.

Sampai di sini, keempat database yang sudah berjalan sejak Bagian V dimulai kini punya jalur backup dan restore yang jelas: pg_dump/pg_restore untuk PostgreSQL, mysqldump untuk MySQL, mariadb-dump untuk MariaDB, dan mongodump/mongorestore untuk MongoDB, seluruhnya terotomasi lewat satu script bash yang berjalan setiap dini hari lewat systemd timer. Bagian V pun resmi ditutup di titik ini. Bab 24 membuka Bagian VI dengan topik yang berbeda sama sekali, yaitu file sharing lintas platform lewat Samba, dimulai dari konsep protokol SMB/CIFS yang menjadi dasarnya.