Add setup.sh with nightly systemd timer; move key and excludes into /opt/backup
This commit is contained in:
parent
99c716d35b
commit
2db05c9bb6
6 changed files with 151 additions and 27 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
||||||
# Secrets — never commit the real env file
|
# Secrets — never commit
|
||||||
backup.env
|
backup.env
|
||||||
|
encryption-key.pem
|
||||||
|
|
|
||||||
|
|
@ -13,23 +13,35 @@ Everything lives in `/opt/backup/`. The connection details and credentials
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| `backup.env` | Shared config: server, datastore, namespace, token, key (sourced by both scripts) |
|
| `backup.env` | Shared config: server, datastore, namespace, token, key (sourced by both scripts) |
|
||||||
| `backup.env.sample` | Template — copy to `backup.env` and fill in real values |
|
| `backup.env.sample` | Template — copy to `backup.env` and fill in real values |
|
||||||
|
| `setup.sh` | Install the client and create the encryption key (run once as root) |
|
||||||
| `backup.sh` | Full backup of `/` with client-side encryption |
|
| `backup.sh` | Full backup of `/` with client-side encryption |
|
||||||
| `restore.sh` | FUSE-mount the encrypted backup to browse/restore files |
|
| `restore.sh` | FUSE-mount the encrypted backup to browse/restore files |
|
||||||
| `/etc/proxmox-backup/encryption-key.pem` | Client-side encryption key (store a copy off-host!) |
|
| `/opt/backup/encryption-key.pem` | Client-side encryption key (store a copy off-host!) |
|
||||||
| `/etc/proxmox-backup/defaults.exclude` | Paths excluded from the backup |
|
| `/opt/backup/exclude` | Paths excluded from the backup |
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
On a fresh host, as root:
|
||||||
|
|
||||||
|
```
|
||||||
|
./setup.sh
|
||||||
|
cp backup.env.sample backup.env
|
||||||
|
$EDITOR backup.env # fill in server, datastore, namespace, token
|
||||||
|
chmod 600 backup.env
|
||||||
|
```
|
||||||
|
|
||||||
## How `backup.sh` works
|
## How `backup.sh` works
|
||||||
|
|
||||||
1. Sources `backup.env`, which exports the connection/auth settings (server,
|
1. Sources `backup.env`, which exports the connection/auth settings (server,
|
||||||
datastore, port, API token) as separate `PBS_*` component variables. This
|
datastore, port, API token) as separate `PBS_*` component variables. This
|
||||||
matters: `PBS_AUTH_ID` is only honoured when `PBS_REPOSITORY` is *not* set.
|
matters: `PBS_AUTH_ID` is only honoured when `PBS_REPOSITORY` is *not* set.
|
||||||
2. Builds `--exclude` flags from `/etc/proxmox-backup/defaults.exclude`
|
2. Builds `--exclude` flags from `/opt/backup/exclude`
|
||||||
(`/proc`, `/sys`, `/dev`, `/run`, `/tmp`, …).
|
(`/proc`, `/sys`, `/dev`, `/run`, `/tmp`, …).
|
||||||
3. Runs:
|
3. Runs:
|
||||||
|
|
||||||
```
|
```
|
||||||
proxmox-backup-client backup "${HOSTNAME}-root.pxar:/" \
|
proxmox-backup-client backup "${HOSTNAME}-root.pxar:/" \
|
||||||
--keyfile /etc/proxmox-backup/encryption-key.pem \
|
--keyfile /opt/backup/encryption-key.pem \
|
||||||
--ns "$BACKUP_NS" \
|
--ns "$BACKUP_NS" \
|
||||||
--exclude /proc/* ...
|
--exclude /proc/* ...
|
||||||
```
|
```
|
||||||
|
|
@ -46,8 +58,8 @@ The **encryption key is the only thing that makes the backups readable**. If
|
||||||
this host and the key are both lost, the backup is unrecoverable — no one at
|
this host and the key are both lost, the backup is unrecoverable — no one at
|
||||||
the PBS provider can help.
|
the PBS provider can help.
|
||||||
|
|
||||||
- File: `/etc/proxmox-backup/encryption-key.pem`
|
- File: `/opt/backup/encryption-key.pem`
|
||||||
- Fingerprint: `proxmox-backup-client key show /etc/proxmox-backup/encryption-key.pem`
|
- Fingerprint: `proxmox-backup-client key show /opt/backup/encryption-key.pem`
|
||||||
|
|
||||||
Keep a copy somewhere safe that is **not this machine**:
|
Keep a copy somewhere safe that is **not this machine**:
|
||||||
- offline USB stick / printed paperkey
|
- offline USB stick / printed paperkey
|
||||||
|
|
@ -138,7 +150,7 @@ First source the shared config (`source /opt/backup/backup.env`), then:
|
||||||
```
|
```
|
||||||
proxmox-backup-client restore host/<hostname>/<time> <hostname>-root.pxar /restore/dir \
|
proxmox-backup-client restore host/<hostname>/<time> <hostname>-root.pxar /restore/dir \
|
||||||
--ns <namespace> \
|
--ns <namespace> \
|
||||||
--keyfile /etc/proxmox-backup/encryption-key.pem \
|
--keyfile /opt/backup/encryption-key.pem \
|
||||||
--pattern "etc/postfix/main.cf"
|
--pattern "etc/postfix/main.cf"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ export PBS_AUTH_ID="user@pbs!tokenname"
|
||||||
export PBS_PASSWORD="paste-token-secret-here"
|
export PBS_PASSWORD="paste-token-secret-here"
|
||||||
|
|
||||||
# --- Client-side encryption key (passed via --keyfile) ---
|
# --- Client-side encryption key (passed via --keyfile) ---
|
||||||
ENCRYPTION_KEY_FILE="/etc/proxmox-backup/encryption-key.pem"
|
ENCRYPTION_KEY_FILE="/opt/backup/encryption-key.pem"
|
||||||
|
|
||||||
# --- Local hostname (used as backup-id and archive-name prefix) ---
|
# --- Local hostname (used as backup-id and archive-name prefix) ---
|
||||||
HOSTNAME="$(hostname)"
|
HOSTNAME="$(hostname)"
|
||||||
|
|
|
||||||
24
backup.sh
24
backup.sh
|
|
@ -9,28 +9,16 @@ source "$SCRIPT_DIR/backup.env"
|
||||||
# BACKUP-SPECIFIC CONFIGURATION
|
# BACKUP-SPECIFIC CONFIGURATION
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
BACKUP_LABEL="${HOSTNAME}-root"
|
BACKUP_LABEL="${HOSTNAME}-root"
|
||||||
EXCLUDE_FILE="/etc/proxmox-backup/defaults.exclude"
|
EXCLUDE_FILE="/opt/backup/exclude"
|
||||||
|
|
||||||
# Create a default exclude file if it doesn't exist
|
|
||||||
if [ ! -f "$EXCLUDE_FILE" ]; then
|
|
||||||
mkdir -p "$(dirname "$EXCLUDE_FILE")"
|
|
||||||
cat << 'EOF' > "$EXCLUDE_FILE"
|
|
||||||
/proc/*
|
|
||||||
/sys/*
|
|
||||||
/dev/*
|
|
||||||
/run/*
|
|
||||||
/tmp/*
|
|
||||||
/mnt/*
|
|
||||||
/media/*
|
|
||||||
/lost+found
|
|
||||||
/var/tmp/*
|
|
||||||
/var/cache/*
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# EXECUTION
|
# EXECUTION
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
if [ ! -f "$EXCLUDE_FILE" ]; then
|
||||||
|
echo "error: exclude list not found at $EXCLUDE_FILE — run setup.sh first" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Starting Proxmox Backup for ${HOSTNAME}..."
|
echo "Starting Proxmox Backup for ${HOSTNAME}..."
|
||||||
|
|
||||||
EXCLUDE_ARGS=()
|
EXCLUDE_ARGS=()
|
||||||
|
|
|
||||||
10
exclude
Normal file
10
exclude
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
/proc/*
|
||||||
|
/sys/*
|
||||||
|
/dev/*
|
||||||
|
/run/*
|
||||||
|
/tmp/*
|
||||||
|
/mnt/*
|
||||||
|
/media/*
|
||||||
|
/lost+found
|
||||||
|
/var/tmp/*
|
||||||
|
/var/cache/*
|
||||||
113
setup.sh
Executable file
113
setup.sh
Executable file
|
|
@ -0,0 +1,113 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Set up Proxmox Backup Client on a Debian trixie host.
|
||||||
|
#
|
||||||
|
# Installs the client and creates the client-side encryption key. Everything
|
||||||
|
# lives in /opt/backup (see backup.env for the connection/auth config).
|
||||||
|
#
|
||||||
|
# Run as root. Safe to re-run: it will not overwrite an existing key.
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
KEYRING="/usr/share/keyrings/proxmox-archive-keyring.gpg"
|
||||||
|
KEYRING_URL="https://enterprise.proxmox.com/debian/proxmox-archive-keyring-trixie.gpg"
|
||||||
|
SOURCES_FILE="/etc/apt/sources.list.d/pbs-client.sources"
|
||||||
|
BACKUP_DIR="/opt/backup"
|
||||||
|
KEY_FILE="${BACKUP_DIR}/encryption-key.pem"
|
||||||
|
EXCLUDE_FILE="${BACKUP_DIR}/exclude"
|
||||||
|
ENV_FILE="${BACKUP_DIR}/backup.env"
|
||||||
|
ENV_SAMPLE="${BACKUP_DIR}/backup.env.sample"
|
||||||
|
SERVICE_UNIT="/etc/systemd/system/pbs-backup.service"
|
||||||
|
TIMER_UNIT="/etc/systemd/system/pbs-backup.timer"
|
||||||
|
BACKUP_TIME="02:00"
|
||||||
|
|
||||||
|
# 1. Proxmox archive signing key
|
||||||
|
wget "$KEYRING_URL" -O "$KEYRING"
|
||||||
|
|
||||||
|
# 2. APT source for the client-only repository
|
||||||
|
cat > "$SOURCES_FILE" <<'EOF'
|
||||||
|
Types: deb
|
||||||
|
URIs: http://download.proxmox.com/debian/pbs-client
|
||||||
|
Suites: trixie
|
||||||
|
Components: main
|
||||||
|
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 3. Install the client
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y proxmox-backup-client
|
||||||
|
|
||||||
|
# 4. Client-side encryption key (no password). Never overwrite an existing key.
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
if [ -e "$KEY_FILE" ]; then
|
||||||
|
echo "Encryption key already exists at $KEY_FILE — leaving it untouched." >&2
|
||||||
|
else
|
||||||
|
proxmox-backup-client key create "$KEY_FILE" --kdf none
|
||||||
|
chmod 600 "$KEY_FILE"
|
||||||
|
echo "Created encryption key: $KEY_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. Exclude list (created only if it doesn't exist yet)
|
||||||
|
if [ ! -f "$EXCLUDE_FILE" ]; then
|
||||||
|
cat > "$EXCLUDE_FILE" <<'EOF'
|
||||||
|
/proc/*
|
||||||
|
/sys/*
|
||||||
|
/dev/*
|
||||||
|
/run/*
|
||||||
|
/tmp/*
|
||||||
|
/mnt/*
|
||||||
|
/media/*
|
||||||
|
/lost+found
|
||||||
|
/var/tmp/*
|
||||||
|
/var/cache/*
|
||||||
|
EOF
|
||||||
|
echo "Created exclude list: $EXCLUDE_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 6. Config template -> backup.env (unless backup.env already exists)
|
||||||
|
if [ -f "$ENV_FILE" ]; then
|
||||||
|
echo "backup.env already exists — leaving it untouched." >&2
|
||||||
|
elif [ -f "$ENV_SAMPLE" ]; then
|
||||||
|
cp "$ENV_SAMPLE" "$ENV_FILE"
|
||||||
|
chmod 600 "$ENV_FILE"
|
||||||
|
echo "Created $ENV_FILE from $ENV_SAMPLE"
|
||||||
|
else
|
||||||
|
echo "warning: $ENV_SAMPLE not found — create $ENV_FILE manually" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 7. systemd timer — run the backup daily at night
|
||||||
|
cat > "$SERVICE_UNIT" <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Proxmox Backup Client host backup
|
||||||
|
Wants=network-online.target
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=${BACKUP_DIR}/backup.sh
|
||||||
|
Nice=19
|
||||||
|
IOSchedulingClass=idle
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$TIMER_UNIT" <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Daily Proxmox Backup
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=*-*-* ${BACKUP_TIME}
|
||||||
|
RandomizeDelaySec=1800
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now pbs-backup.timer
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Done. Fill in the credentials, then run ${BACKUP_DIR}/backup.sh (or wait for the timer):"
|
||||||
|
echo " ${EDITOR:-vi} ${ENV_FILE} # server/datastore/namespace/token"
|
||||||
|
echo " systemctl list-timers pbs-backup.timer"
|
||||||
|
echo " journalctl -u pbs-backup"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue