feat: add server-side backup scripts and restore guide
This commit is contained in:
@@ -163,21 +163,38 @@ npm run dev
|
|||||||
|
|
||||||
## Backup
|
## Backup
|
||||||
|
|
||||||
Project ini menyediakan script backup manual:
|
Project ini menyediakan dua lapis mekanisme backup:
|
||||||
|
|
||||||
|
### 1. Script lama (manual dasar)
|
||||||
```bash
|
```bash
|
||||||
./backup.sh
|
./backup.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Yang dibackup:
|
### 2. Script backup operasional yang direkomendasikan
|
||||||
- database MySQL
|
Gunakan script di folder `scripts/` untuk backup rutin via shell/cron:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/backup-database-kesiswaan.sh
|
||||||
|
./scripts/backup-dokumen-kesiswaan.sh
|
||||||
|
./scripts/backup-full-kesiswaan.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Yang diamankan:
|
||||||
|
- database MySQL/MariaDB
|
||||||
- `storage/app/public`
|
- `storage/app/public`
|
||||||
- file `.env`
|
- file `.env` (opsional pada full backup)
|
||||||
|
|
||||||
Lokasi backup default:
|
Lokasi backup default:
|
||||||
- `storage/app/backups-manual/database`
|
- `/var/backups/database-kesiswaan/database`
|
||||||
- `storage/app/backups-manual/storage`
|
- `/var/backups/database-kesiswaan/files`
|
||||||
- `storage/app/backups-manual/env`
|
- `/var/backups/database-kesiswaan/env`
|
||||||
|
- `/var/backups/database-kesiswaan/manifests`
|
||||||
|
|
||||||
|
Panduan restore lengkap tersedia di:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docs/BACKUP_RESTORE.md
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
# BACKUP_RESTORE.md - Database Kesiswaan
|
||||||
|
|
||||||
|
Panduan backup dan pemulihan data untuk project `database-kesiswaan`.
|
||||||
|
|
||||||
|
## Tujuan
|
||||||
|
|
||||||
|
Menyediakan mekanisme backup **tanpa UI aplikasi**, agar admin/server operator bisa menjalankan backup rutin langsung dari shell/cron.
|
||||||
|
|
||||||
|
Yang diamankan:
|
||||||
|
- database MySQL/MariaDB `database_kesiswaan`
|
||||||
|
- file dokumen di `storage/app/public`
|
||||||
|
- file `.env` (opsional, tapi sangat disarankan)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Struktur Script
|
||||||
|
|
||||||
|
Semua script ada di folder:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/var/www/database-kesiswaan/scripts
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1. Backup database saja
|
||||||
|
```bash
|
||||||
|
./scripts/backup-database-kesiswaan.sh
|
||||||
|
```
|
||||||
|
Output:
|
||||||
|
- file `.sql.gz`
|
||||||
|
- default lokasi: `/var/backups/database-kesiswaan/database`
|
||||||
|
|
||||||
|
### 2. Backup dokumen saja
|
||||||
|
```bash
|
||||||
|
./scripts/backup-dokumen-kesiswaan.sh
|
||||||
|
```
|
||||||
|
Output:
|
||||||
|
- file `.tar.gz`
|
||||||
|
- default lokasi: `/var/backups/database-kesiswaan/files`
|
||||||
|
|
||||||
|
### 3. Backup penuh (direkomendasikan)
|
||||||
|
```bash
|
||||||
|
./scripts/backup-full-kesiswaan.sh
|
||||||
|
```
|
||||||
|
Output:
|
||||||
|
- backup database
|
||||||
|
- backup dokumen
|
||||||
|
- salinan `.env`
|
||||||
|
- manifest backup
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lokasi Backup Default
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/var/backups/database-kesiswaan/
|
||||||
|
├── database/
|
||||||
|
├── files/
|
||||||
|
├── env/
|
||||||
|
└── manifests/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Retensi Default
|
||||||
|
|
||||||
|
Script menggunakan retensi default:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RETENTION_DAYS=14
|
||||||
|
```
|
||||||
|
|
||||||
|
Artinya backup lebih lama dari 14 hari akan dibersihkan otomatis.
|
||||||
|
|
||||||
|
Kalau ingin ubah retensi saat menjalankan script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RETENTION_DAYS=30 ./scripts/backup-full-kesiswaan.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Menjalankan Manual
|
||||||
|
|
||||||
|
### Backup penuh manual
|
||||||
|
```bash
|
||||||
|
cd /var/www/database-kesiswaan
|
||||||
|
chmod +x scripts/*.sh
|
||||||
|
./scripts/backup-full-kesiswaan.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup hanya database
|
||||||
|
```bash
|
||||||
|
cd /var/www/database-kesiswaan
|
||||||
|
./scripts/backup-database-kesiswaan.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup hanya dokumen
|
||||||
|
```bash
|
||||||
|
cd /var/www/database-kesiswaan
|
||||||
|
./scripts/backup-dokumen-kesiswaan.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contoh Cron Rutin
|
||||||
|
|
||||||
|
### Backup penuh setiap hari jam 01:00
|
||||||
|
```cron
|
||||||
|
0 1 * * * cd /var/www/database-kesiswaan && /bin/bash ./scripts/backup-full-kesiswaan.sh >> /var/log/database-kesiswaan-backup.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup database saja setiap 6 jam
|
||||||
|
```cron
|
||||||
|
0 */6 * * * cd /var/www/database-kesiswaan && /bin/bash ./scripts/backup-database-kesiswaan.sh >> /var/log/database-kesiswaan-db-backup.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup dokumen setiap hari jam 01:30
|
||||||
|
```cron
|
||||||
|
30 1 * * * cd /var/www/database-kesiswaan && /bin/bash ./scripts/backup-dokumen-kesiswaan.sh >> /var/log/database-kesiswaan-files-backup.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Restore Database
|
||||||
|
|
||||||
|
Contoh restore dump database:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gunzip -c /var/backups/database-kesiswaan/database/database_kesiswaan-YYYY-MM-DD-HHMMSS.sql.gz | mysql -u kesiswaan -p database_kesiswaan
|
||||||
|
```
|
||||||
|
|
||||||
|
> Pastikan database target sudah ada dan kredensial benar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Restore Dokumen
|
||||||
|
|
||||||
|
Contoh restore dokumen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p /var/www/database-kesiswaan/storage/app/public
|
||||||
|
tar -xzf /var/backups/database-kesiswaan/files/storage-public-YYYY-MM-DD-HHMMSS.tar.gz -C /var/www/database-kesiswaan/storage/app/public
|
||||||
|
```
|
||||||
|
|
||||||
|
Lalu pastikan storage link tetap ada:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /var/www/database-kesiswaan
|
||||||
|
php artisan storage:link
|
||||||
|
php artisan optimize:clear
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Restore `.env`
|
||||||
|
|
||||||
|
Kalau perlu mengembalikan `.env`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp /var/backups/database-kesiswaan/env/env-YYYY-MM-DD-HHMMSS.backup /var/www/database-kesiswaan/.env
|
||||||
|
chmod 600 /var/www/database-kesiswaan/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Checklist Setelah Restore
|
||||||
|
|
||||||
|
- [ ] database berhasil di-restore
|
||||||
|
- [ ] dokumen berhasil di-restore
|
||||||
|
- [ ] `.env` benar
|
||||||
|
- [ ] `php artisan optimize:clear` dijalankan
|
||||||
|
- [ ] `php artisan storage:link` valid
|
||||||
|
- [ ] halaman login bisa dibuka
|
||||||
|
- [ ] data siswa muncul
|
||||||
|
- [ ] preview/download dokumen berjalan
|
||||||
|
- [ ] portal publik berjalan normal
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rekomendasi Operasional
|
||||||
|
|
||||||
|
1. Gunakan **backup penuh harian**.
|
||||||
|
2. Simpan backup di disk/partisi yang cukup longgar.
|
||||||
|
3. Kalau memungkinkan, sinkronkan backup ke lokasi kedua (server lain / external storage).
|
||||||
|
4. Uji restore minimal sesekali, jangan hanya percaya backup berhasil dibuat.
|
||||||
|
5. Lindungi folder backup karena berisi data sensitif dan kemungkinan salinan `.env`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Catatan Keamanan
|
||||||
|
|
||||||
|
- Folder backup bisa mengandung data sensitif.
|
||||||
|
- Jangan expose `/var/backups/database-kesiswaan` ke web.
|
||||||
|
- Jangan commit backup ke GitHub.
|
||||||
|
- Jangan berikan izin baca sembarangan ke file backup `.env`.
|
||||||
Executable
+65
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ENV_FILE="${ENV_FILE:-$APP_DIR/.env}"
|
||||||
|
BACKUP_ROOT="${BACKUP_ROOT:-/var/backups/database-kesiswaan}"
|
||||||
|
TIMESTAMP="${TIMESTAMP:-$(date '+%Y-%m-%d-%H%M%S')}"
|
||||||
|
RETENTION_DAYS="${RETENTION_DAYS:-14}"
|
||||||
|
|
||||||
|
abort() {
|
||||||
|
printf '[ERROR] %s\n' "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_bin() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || abort "Binary '$1' tidak ditemukan."
|
||||||
|
}
|
||||||
|
|
||||||
|
read_env() {
|
||||||
|
local key="$1"
|
||||||
|
grep -E "^${key}=" "$ENV_FILE" | tail -n 1 | cut -d '=' -f2- | sed 's/^"//; s/"$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -f "$ENV_FILE" ]] || abort "File .env tidak ditemukan di $ENV_FILE"
|
||||||
|
require_bin mysqldump
|
||||||
|
require_bin gzip
|
||||||
|
|
||||||
|
DB_CONNECTION="$(read_env DB_CONNECTION)"
|
||||||
|
DB_HOST="$(read_env DB_HOST)"
|
||||||
|
DB_PORT="$(read_env DB_PORT)"
|
||||||
|
DB_DATABASE="$(read_env DB_DATABASE)"
|
||||||
|
DB_USERNAME="$(read_env DB_USERNAME)"
|
||||||
|
DB_PASSWORD="$(read_env DB_PASSWORD)"
|
||||||
|
|
||||||
|
[[ "$DB_CONNECTION" == "mysql" ]] || abort "Script ini saat ini hanya mendukung DB_CONNECTION=mysql"
|
||||||
|
[[ -n "$DB_DATABASE" ]] || abort "DB_DATABASE kosong"
|
||||||
|
[[ -n "$DB_USERNAME" ]] || abort "DB_USERNAME kosong"
|
||||||
|
|
||||||
|
DB_HOST="${DB_HOST:-127.0.0.1}"
|
||||||
|
DB_PORT="${DB_PORT:-3306}"
|
||||||
|
|
||||||
|
TARGET_DIR="$BACKUP_ROOT/database"
|
||||||
|
mkdir -p "$TARGET_DIR"
|
||||||
|
TARGET_FILE="$TARGET_DIR/${DB_DATABASE}-${TIMESTAMP}.sql.gz"
|
||||||
|
|
||||||
|
log "Memulai backup database '$DB_DATABASE'"
|
||||||
|
MYSQL_PWD="$DB_PASSWORD" mysqldump \
|
||||||
|
--host="$DB_HOST" \
|
||||||
|
--port="$DB_PORT" \
|
||||||
|
--user="$DB_USERNAME" \
|
||||||
|
--single-transaction \
|
||||||
|
--quick \
|
||||||
|
--skip-lock-tables \
|
||||||
|
--routines \
|
||||||
|
--triggers \
|
||||||
|
"$DB_DATABASE" | gzip -c > "$TARGET_FILE"
|
||||||
|
|
||||||
|
find "$TARGET_DIR" -type f -name '*.sql.gz' -mtime +"$RETENTION_DAYS" -delete || true
|
||||||
|
|
||||||
|
log "Backup database selesai: $TARGET_FILE"
|
||||||
|
printf '%s\n' "$TARGET_FILE"
|
||||||
Executable
+36
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
BACKUP_ROOT="${BACKUP_ROOT:-/var/backups/database-kesiswaan}"
|
||||||
|
TIMESTAMP="${TIMESTAMP:-$(date '+%Y-%m-%d-%H%M%S')}"
|
||||||
|
RETENTION_DAYS="${RETENTION_DAYS:-14}"
|
||||||
|
SOURCE_DIR="${SOURCE_DIR:-$APP_DIR/storage/app/public}"
|
||||||
|
|
||||||
|
abort() {
|
||||||
|
printf '[ERROR] %s\n' "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_bin() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || abort "Binary '$1' tidak ditemukan."
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -d "$SOURCE_DIR" ]] || abort "Folder sumber dokumen tidak ditemukan di $SOURCE_DIR"
|
||||||
|
require_bin tar
|
||||||
|
|
||||||
|
TARGET_DIR="$BACKUP_ROOT/files"
|
||||||
|
mkdir -p "$TARGET_DIR"
|
||||||
|
TARGET_FILE="$TARGET_DIR/storage-public-${TIMESTAMP}.tar.gz"
|
||||||
|
|
||||||
|
log "Memulai backup dokumen dari '$SOURCE_DIR'"
|
||||||
|
tar -czf "$TARGET_FILE" -C "$SOURCE_DIR" .
|
||||||
|
|
||||||
|
find "$TARGET_DIR" -type f -name '*.tar.gz' -mtime +"$RETENTION_DAYS" -delete || true
|
||||||
|
|
||||||
|
log "Backup dokumen selesai: $TARGET_FILE"
|
||||||
|
printf '%s\n' "$TARGET_FILE"
|
||||||
Executable
+53
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
BACKUP_ROOT="${BACKUP_ROOT:-/var/backups/database-kesiswaan}"
|
||||||
|
ENV_FILE="${ENV_FILE:-$APP_DIR/.env}"
|
||||||
|
TIMESTAMP="${TIMESTAMP:-$(date '+%Y-%m-%d-%H%M%S')}"
|
||||||
|
RETENTION_DAYS="${RETENTION_DAYS:-14}"
|
||||||
|
KEEP_ENV_BACKUP="${KEEP_ENV_BACKUP:-true}"
|
||||||
|
|
||||||
|
abort() {
|
||||||
|
printf '[ERROR] %s\n' "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -f "$ENV_FILE" ]] || abort "File .env tidak ditemukan di $ENV_FILE"
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_ROOT/manifests" "$BACKUP_ROOT/env"
|
||||||
|
|
||||||
|
DB_BACKUP="$(BACKUP_ROOT="$BACKUP_ROOT" ENV_FILE="$ENV_FILE" TIMESTAMP="$TIMESTAMP" RETENTION_DAYS="$RETENTION_DAYS" "$APP_DIR/scripts/backup-database-kesiswaan.sh")"
|
||||||
|
FILES_BACKUP="$(BACKUP_ROOT="$BACKUP_ROOT" TIMESTAMP="$TIMESTAMP" RETENTION_DAYS="$RETENTION_DAYS" "$APP_DIR/scripts/backup-dokumen-kesiswaan.sh")"
|
||||||
|
ENV_BACKUP=""
|
||||||
|
|
||||||
|
if [[ "$KEEP_ENV_BACKUP" == "true" ]]; then
|
||||||
|
ENV_BACKUP="$BACKUP_ROOT/env/env-${TIMESTAMP}.backup"
|
||||||
|
cp "$ENV_FILE" "$ENV_BACKUP"
|
||||||
|
chmod 600 "$ENV_BACKUP" || true
|
||||||
|
find "$BACKUP_ROOT/env" -type f -name '*.backup' -mtime +"$RETENTION_DAYS" -delete || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
MANIFEST_FILE="$BACKUP_ROOT/manifests/backup-${TIMESTAMP}.txt"
|
||||||
|
{
|
||||||
|
echo "timestamp=$TIMESTAMP"
|
||||||
|
echo "database_backup=$DB_BACKUP"
|
||||||
|
echo "files_backup=$FILES_BACKUP"
|
||||||
|
echo "env_backup=${ENV_BACKUP:-not_saved}"
|
||||||
|
echo "host=$(hostname)"
|
||||||
|
echo "app_dir=$APP_DIR"
|
||||||
|
} > "$MANIFEST_FILE"
|
||||||
|
|
||||||
|
find "$BACKUP_ROOT/manifests" -type f -name 'backup-*.txt' -mtime +"$RETENTION_DAYS" -delete || true
|
||||||
|
|
||||||
|
log "Backup penuh selesai"
|
||||||
|
printf 'Database: %s\n' "$DB_BACKUP"
|
||||||
|
printf 'Dokumen : %s\n' "$FILES_BACKUP"
|
||||||
|
if [[ -n "$ENV_BACKUP" ]]; then
|
||||||
|
printf '.env : %s\n' "$ENV_BACKUP"
|
||||||
|
fi
|
||||||
|
printf 'Manifest: %s\n' "$MANIFEST_FILE"
|
||||||
Reference in New Issue
Block a user