usb drive fix, docs
This commit is contained in:
54
README.md
54
README.md
@@ -18,4 +18,56 @@ Check the wiki here for more information: [wikimd/wiki/homepage.md](wikimd/wiki/
|
|||||||
|
|
||||||
## Backup Strategies
|
## Backup Strategies
|
||||||
|
|
||||||
TODO
|
Two scripts handle backups. Both must be run as **root** (`sudo`) because the backup destination is owned by root.
|
||||||
|
|
||||||
|
### File Backup — [`backup.sh`](backup.sh)
|
||||||
|
|
||||||
|
Incremental rsync snapshot backup of `/home/oster/server` to the extension drive.
|
||||||
|
|
||||||
|
- **Destination:** `/media/extension/backup/ubuntu/`
|
||||||
|
- **Method:** Hard-link incremental snapshots (`--link-dest`) — each daily run creates a new `YYYY-MM-DD/` directory; unchanged files are hard-linked from the previous snapshot, so each snapshot looks complete but only new/changed files consume extra space.
|
||||||
|
- **Retention:** Configurable at the top of the script:
|
||||||
|
```bash
|
||||||
|
readonly KEEP_DAILY=3 # keep this many daily snapshots
|
||||||
|
readonly KEEP_WEEKLY=2 # keep this many weekly (Sunday) snapshots
|
||||||
|
```
|
||||||
|
- **Exclusions:** `.cache`, `node_modules`, `*.tmp`, and DB-related directories (`postgresql`, `mysql`, `db`, `database`) — those are handled separately by `backup-db.sh`.
|
||||||
|
- **Locking:** A lockfile at `/media/extension/backup/ubuntu/.backup.lock` prevents concurrent runs. Stale locks (from crashed runs) are detected by PID check and removed automatically.
|
||||||
|
|
||||||
|
**Run manually:**
|
||||||
|
```bash
|
||||||
|
sudo ./backup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cron example** (daily at 04:00, in root's crontab via `sudo crontab -e`):
|
||||||
|
```
|
||||||
|
0 4 * * * /home/oster/git/homeserver/backup.sh >> /var/log/backup.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Database Backup — [`backup-db.sh`](backup-db.sh)
|
||||||
|
|
||||||
|
Dumps all PostgreSQL databases from running Docker containers using `pg_dumpall`.
|
||||||
|
|
||||||
|
- **Destination:** `/home/oster/server/backup/` (on the system disk, picked up by `backup.sh` on the next run)
|
||||||
|
- **Databases backed up:**
|
||||||
|
|
||||||
|
| Container | DB User | Label |
|
||||||
|
|---|---|---|
|
||||||
|
| `immich_postgres` | `postgres` | `immich` |
|
||||||
|
| `authentik-postgresql-1` | `authentik` | `authentik` |
|
||||||
|
| `paperless-db-1` | `paperless` | `paperless` |
|
||||||
|
|
||||||
|
- **Output format:** `YYYY-MM-DD_HH:MM:SS-<label>.sql.gz` (gzip-compressed SQL dump)
|
||||||
|
- **Retention:** Dumps older than 7 days are automatically deleted.
|
||||||
|
|
||||||
|
**Run manually:**
|
||||||
|
```bash
|
||||||
|
sudo ./backup-db.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cron example** (daily at 03:30, before the file backup):
|
||||||
|
```
|
||||||
|
30 3 * * * /home/oster/git/homeserver/backup-db.sh >> /var/log/backup-db.log 2>&1
|
||||||
|
```
|
||||||
|
|||||||
49
backup.sh
49
backup.sh
@@ -15,6 +15,11 @@ readonly LATEST="${BACKUP_BASE}/latest"
|
|||||||
readonly KEEP_DAILY=3 # keep this many daily snapshots
|
readonly KEEP_DAILY=3 # keep this many daily snapshots
|
||||||
readonly KEEP_WEEKLY=2 # keep this many weekly (Sunday) snapshots
|
readonly KEEP_WEEKLY=2 # keep this many weekly (Sunday) snapshots
|
||||||
|
|
||||||
|
# USB backup drive — ASMedia ASM1153E bridge (174c:55aa)
|
||||||
|
# Used to disable UAS (which causes resets under load) and spin-down
|
||||||
|
readonly USB_VENDOR_PRODUCT="174c:55aa"
|
||||||
|
readonly UAS_QUIRKS_FILE="/etc/modprobe.d/usb-backup-uas-quirk.conf"
|
||||||
|
|
||||||
# Directories (or files) to back up (without DB volumes)
|
# Directories (or files) to back up (without DB volumes)
|
||||||
declare -a SOURCE_ITEMS=(
|
declare -a SOURCE_ITEMS=(
|
||||||
"/home/oster/server"
|
"/home/oster/server"
|
||||||
@@ -59,6 +64,48 @@ check_mount() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Ensure the UAS quirk is configured for the backup drive.
|
||||||
|
# UAS causes device resets under sustained write load with the ASM1153E bridge.
|
||||||
|
# If the config is missing, write it and update initramfs (requires reboot to take effect).
|
||||||
|
ensure_uas_quirk() {
|
||||||
|
local vid="${USB_VENDOR_PRODUCT%%:*}"
|
||||||
|
local pid="${USB_VENDOR_PRODUCT##*:}"
|
||||||
|
local expected="options usb-storage quirks=${vid}:${pid}:u"
|
||||||
|
|
||||||
|
if grep -qsF "$expected" "$UAS_QUIRKS_FILE" 2>/dev/null; then
|
||||||
|
# Check if the drive is still bound to uas (quirk active only after reboot)
|
||||||
|
if ls /sys/bus/usb/drivers/uas/ 2>/dev/null | grep -q .; then
|
||||||
|
log "WARNING: UAS quirk is configured but drive is still using the uas driver."
|
||||||
|
log " A reboot is required for the quirk to take effect."
|
||||||
|
log " Backup will proceed but may encounter USB resets."
|
||||||
|
else
|
||||||
|
log "UAS quirk active — drive is using usb-storage driver."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "UAS quirk not found — writing $UAS_QUIRKS_FILE and updating initramfs."
|
||||||
|
echo "$expected" > "$UAS_QUIRKS_FILE"
|
||||||
|
update-initramfs -u
|
||||||
|
log "Initramfs updated. Please reboot for the UAS quirk to take effect."
|
||||||
|
log "Continuing backup with current (uas) driver — may encounter resets."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable drive spin-down and APM for the duration of the backup.
|
||||||
|
# The drive going to standby mid-write causes "Logical unit not ready" errors.
|
||||||
|
disable_spindown() {
|
||||||
|
local dev
|
||||||
|
# Resolve the underlying block device from the mount point (strip partition number)
|
||||||
|
dev=$(findmnt -n -o SOURCE "$MOUNT_POINT" | sed 's/[0-9]*$//')
|
||||||
|
if [[ -b "$dev" ]]; then
|
||||||
|
log "Disabling spin-down and APM on $dev for backup duration."
|
||||||
|
hdparm -B 255 -S 0 "$dev" > /dev/null \
|
||||||
|
&& log " hdparm: spin-down disabled on $dev." \
|
||||||
|
|| log "WARNING: hdparm failed on $dev — drive may still spin down."
|
||||||
|
else
|
||||||
|
log "WARNING: Could not determine block device for $MOUNT_POINT (got: $dev) — skipping hdparm."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Rotation: keep KEEP_DAILY daily and KEEP_WEEKLY weekly snapshots
|
# Rotation: keep KEEP_DAILY daily and KEEP_WEEKLY weekly snapshots
|
||||||
rotate_old() {
|
rotate_old() {
|
||||||
log "Applying retention policy (${KEEP_DAILY} daily, ${KEEP_WEEKLY} weekly)."
|
log "Applying retention policy (${KEEP_DAILY} daily, ${KEEP_WEEKLY} weekly)."
|
||||||
@@ -92,6 +139,8 @@ rotate_old() {
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
log "=== Starting backup run: $NOW ==="
|
log "=== Starting backup run: $NOW ==="
|
||||||
check_mount
|
check_mount
|
||||||
|
ensure_uas_quirk
|
||||||
|
disable_spindown
|
||||||
|
|
||||||
# Fail early if the backup base directory doesn't exist (drive not mounted / path wrong)
|
# Fail early if the backup base directory doesn't exist (drive not mounted / path wrong)
|
||||||
[ -d "$BACKUP_BASE" ] || die "Backup base directory $BACKUP_BASE does not exist."
|
[ -d "$BACKUP_BASE" ] || die "Backup base directory $BACKUP_BASE does not exist."
|
||||||
|
|||||||
Reference in New Issue
Block a user