Appearance
Webspace Restore Guide
This guide documents the process for restoring a webspace (WordPress site) from a restic backup, including database and files.
Prerequisites
- Access to the Kubernetes cluster
- Restic backup containing the webspace data
- The webspace's database credentials secret must exist
- MariaDB operator installed in the cluster
- A MariaDB instance named
dbmust exist in thewebspacesnamespace
Restore Process
Replace $NAME with the webspace name (e.g., vefa) throughout this guide.
Step 1: Suspend Flux HelmRelease
bash
flux suspend -n webspaces helmrelease $NAMEStep 2: Scale Deployment to 0 Replicas
bash
kubectl scale --replicas=0 -n webspaces deploy/${NAME}-webserverStep 3: Create Alpine Restore Pod
Create and apply a pod manifest that mounts the PVC and provides database credentials:
bash
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: ${NAME}-restore
namespace: webspaces
spec:
containers:
- name: alpine
image: alpine:latest
command: ["/bin/sh"]
args: ["-c", "while true; do sleep 3600; done"]
volumeMounts:
- name: data
mountPath: /data
env:
- name: DB_HOST
value: "db.webspaces.svc.cluster.local"
- name: DB_USER
value: "${NAME}"
- name: DB_NAME
value: "${NAME}"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: ${NAME}-credentials
key: db-password
volumes:
- name: data
persistentVolumeClaim:
claimName: ${NAME}-files
restartPolicy: Never
EOF
kubectl wait --for=condition=Ready pod/${NAME}-restore -n webspaces --timeout=60sStep 4: Install Tools and Configure Restic
Exec into the pod:
bash
kubectl exec -it ${NAME}-restore -n webspaces -- /bin/shInstall required tools:
bash
apk add --no-cache restic mariadb-clientSet restic environment variables:
bash
export RESTIC_REPOSITORY='s3:https://YOUR_S3_ENDPOINT/YOUR_BUCKET'
export RESTIC_PASSWORD='YOUR_RESTIC_PASSWORD'
export AWS_ACCESS_KEY_ID='YOUR_ACCESS_KEY'
export AWS_SECRET_ACCESS_KEY='YOUR_SECRET_KEY'Step 5: Identify Restic Snapshot
List snapshots and find the one to restore:
bash
restic snapshotsInspect the snapshot to verify contents:
bash
restic ls SNAPSHOT_IDLook for:
- SQL dump file (e.g.,
${NAME}.sqlor${NAME}.sql.gz) - Website files directory (e.g.,
${NAME}-files/)
Step 6: Restore Files from Restic
First, inspect the snapshot to find the paths:
bash
restic ls SNAPSHOT_ID | head -20Restore only the SQL dump and WordPress files directory directly to /data:
bash
# Replace with actual paths from your snapshot
restic restore SNAPSHOT_ID --target /data --include "/path/to/${NAME}.sql*" --include "/path/to/${NAME}-files/**"Note: You may see SELinux xattr warnings - these can be safely ignored as long as the summary shows files were restored.
Step 7: Restore SQL Dump
Find the SQL dump file:
bash
find /data -name "*.sql" -o -name "*.sql.gz"Import the database:
bash
# For uncompressed SQL dump
mariadb -h db -u $DB_USER -p$DB_PASSWORD $DB_NAME < /path/to/dump.sql
# For compressed SQL dump
gunzip -c /path/to/dump.sql.gz | mariadb -h db -u $DB_USER -p$DB_PASSWORD $DB_NAMEVerify the import:
bash
mariadb -h db -u $DB_USER -p$DB_PASSWORD $DB_NAME -e "SHOW TABLES;"
mariadb -h db -u $DB_USER -p$DB_PASSWORD $DB_NAME -e "SELECT COUNT(*) FROM wp_posts;"Note: The Database may have another prefix than
wp_. In that case, see what tables show up when running the first command.
Step 8: Finalize PVC
Move website files to /data root and clean up:
bash
# Move website files to root (adjust path based on your backup structure)
mv /data/path/to/${NAME}-files/* /data/
mv /data/path/to/${NAME}-files/.* /data/ 2>/dev/null || true
# Remove backup directory structure and SQL dump
rm -rf /data/path/to
rm -f /data/*.sql /data/*.sql.gzVerify files are in the correct location:
bash
ls -la /data/ | head -20You should see WordPress files like:
index.phpwp-config.phpwp-content/wp-includes/
Step 9: Update wp-config.php
Important: WordPress configuration files often have hardcoded database credentials that may be outdated.
Check current configuration:
bash
grep "DB_HOST\|DB_PASSWORD" /data/wp-config.php | grep defineUpdate to use environment variables:
bash
sed -i "s/define([[:space:]]*'DB_HOST',[[:space:]]*'[^']*'[[:space:]]*);/define( 'DB_HOST', getenv('WORDPRESS_DB_HOST') );/" /data/wp-config.php
sed -i "s/define([[:space:]]*'DB_PASSWORD',[[:space:]]*'[^']*'[[:space:]]*);/define( 'DB_PASSWORD', getenv('WORDPRESS_DB_PASSWORD') );/" /data/wp-config.phpVerify changes:
bash
grep "DB_HOST\|DB_PASSWORD" /data/wp-config.php | grep defineNote on Hardcoded Secrets: Many restored WordPress installations have hardcoded database passwords in wp-config.php. This is a security concern because:
- Passwords are stored in plain text in the file
- They may not match the current Kubernetes secrets
- Changing secrets requires manual file updates
- Secrets are visible in backups and file system
Recommended Solution: Configure WordPress to read database credentials from environment variables (as shown above). The webspace helm chart already injects these variables into the PHP container:
WORDPRESS_DB_HOSTWORDPRESS_DB_NAMEWORDPRESS_DB_USERWORDPRESS_DB_PASSWORD
Using getenv() in wp-config.php allows centralized secret management through Kubernetes secrets.
Step 10: Exit and Delete Restore Pod
bash
exit # Exit the pod shell
kubectl delete pod ${NAME}-restore -n webspacesStep 11: Scale Deployment Back Up
bash
kubectl scale --replicas=1 -n webspaces deploy/${NAME}-webserverStep 12: Resume Flux HelmRelease
bash
flux resume -n webspaces helmrelease $NAMEStep 13: Verify Deployment
Check that pods are running:
bash
kubectl get pods -n webspaces | grep ${NAME}Test the website in a browser to ensure it loads correctly.