255 lines
11 KiB
Bash
255 lines
11 KiB
Bash
#!/bin/bash -eu
|
|
# =============================================================================
|
|
# 00-backup.sh — Run as ROOT via: sudo bash steps/00-backup.sh
|
|
# 1. Full backup (keys, peers, nginx, certs, ufw, env)
|
|
# NOTE: does NOT shut down legacy stack — that happens in 02-peers.sh
|
|
# only after the new WireGuard is verified and running.
|
|
# =============================================================================
|
|
if [ "$EUID" -ne 0 ]; then
|
|
echo "[X] Run as root: sudo bash steps/00-backup.sh"
|
|
exit 1
|
|
fi
|
|
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; RESET='\033[0m'
|
|
|
|
LINUX_USER="${SUDO_USER:-}"
|
|
if [ -z "$LINUX_USER" ] || [ "$LINUX_USER" = "root" ]; then
|
|
LINUX_USER=$(getent passwd | awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' | head -1 || true)
|
|
fi
|
|
[ -z "$LINUX_USER" ] && { echo -e "${RED}[X]${RESET} Could not detect Linux user."; exit 1; }
|
|
LINUX_HOME=$(getent passwd "$LINUX_USER" | cut -d: -f6)
|
|
|
|
BACKUP_DIR="$LINUX_HOME/.wg-migration"
|
|
LOG="$BACKUP_DIR/migration.log"
|
|
|
|
mkdir -p "$BACKUP_DIR"
|
|
chmod 700 "$BACKUP_DIR"
|
|
chown "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR"
|
|
: > "$LOG"
|
|
chown "$LINUX_USER":"$LINUX_USER" "$LOG"
|
|
|
|
ok() { echo -e "${GREEN}[OK]${RESET} $1"; echo "[OK] $1" >> "$LOG"; }
|
|
info() { echo -e "${CYAN}[i]${RESET} $1"; echo "[i] $1" >> "$LOG"; }
|
|
warn() { echo -e "${YELLOW}[!]${RESET} $1"; echo "[!] $1" >> "$LOG"; }
|
|
fail() { echo -e "${RED}[X]${RESET} $1"; echo "[X] $1" >> "$LOG"; exit 1; }
|
|
sep() { echo -e "\n${CYAN}------------------------------------${RESET}"; }
|
|
|
|
_save() {
|
|
if [ -e "$1" ]; then
|
|
cp -r "$1" "$BACKUP_DIR/$2" 2>/dev/null || true
|
|
chown -R "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/$2" 2>/dev/null || true
|
|
ok "Saved: $1 → $2"
|
|
else
|
|
warn "Not found (skipped): $1"
|
|
fi
|
|
}
|
|
|
|
echo ""
|
|
echo "========================================="
|
|
echo " 00 - Backup and preparation"
|
|
echo " $(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo " User : $LINUX_USER"
|
|
echo " Backup : $BACKUP_DIR"
|
|
echo "========================================="
|
|
echo "[START-00] $(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG"
|
|
|
|
# ─── DOCKER ───────────────────────────────────────────────────────────────────
|
|
sep
|
|
info "Checking Docker..."
|
|
command -v docker &>/dev/null || fail "Docker not installed."
|
|
ok "Docker: $(docker --version)"
|
|
|
|
# ─── DETECT LEGACY WIREGUARD ──────────────────────────────────────────────────
|
|
sep
|
|
info "Detecting legacy WireGuard container..."
|
|
LEGACY_WG=$(docker ps --format '{{.Names}} {{.Image}}' | \
|
|
grep -i "linuxserver/wireguard\|lscr.io/linuxserver/wireguard" | \
|
|
awk '{print $1}' | head -1 || true)
|
|
if [ -z "$LEGACY_WG" ]; then
|
|
LEGACY_WG=$(docker ps --format '{{.Names}}' | \
|
|
grep -iE "^wireguard$|^wg$|^sp-wireguard$" | head -1 || true)
|
|
fi
|
|
[ -z "$LEGACY_WG" ] && fail "No legacy WireGuard container found. Check: docker ps"
|
|
ok "Legacy WireGuard: $LEGACY_WG"
|
|
docker inspect --format '{{.Id}}' "$LEGACY_WG" > "$BACKUP_DIR/legacy_wg_id"
|
|
chown "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/legacy_wg_id"
|
|
ok "Legacy WireGuard ID saved."
|
|
|
|
# ─── DETECT LEGACY STACK ──────────────────────────────────────────────────────
|
|
sep
|
|
info "Detecting legacy stack location..."
|
|
LEGACY_COMPOSE_DIR=""
|
|
|
|
for DIR in "$LINUX_HOME/sp-env-wireguard" \
|
|
"$LINUX_HOME/sp-env-wireguard-ipv6" \
|
|
"$LINUX_HOME/wireguard" \
|
|
/root/sp-env-wireguard \
|
|
/root/sp-env-wireguard-ipv6 \
|
|
/opt/sp-env-wireguard \
|
|
/srv/wireguard; do
|
|
if [ -f "$DIR/docker-compose.yml" ] && grep -q "wireguard" "$DIR/docker-compose.yml" 2>/dev/null; then
|
|
LEGACY_COMPOSE_DIR="$DIR"
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ -z "$LEGACY_COMPOSE_DIR" ]; then
|
|
LEGACY_COMPOSE_DIR=$(find "$LINUX_HOME" /root -maxdepth 6 -name "docker-compose.yml" 2>/dev/null | \
|
|
while read -r f; do
|
|
grep -q "wireguard" "$f" 2>/dev/null && dirname "$f" && break
|
|
done | head -1)
|
|
fi
|
|
|
|
[ -z "$LEGACY_COMPOSE_DIR" ] && fail "Legacy docker-compose.yml not found."
|
|
ok "Legacy stack: $LEGACY_COMPOSE_DIR"
|
|
echo "$LEGACY_COMPOSE_DIR" > "$BACKUP_DIR/legacy_compose_dir"
|
|
chown "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/legacy_compose_dir"
|
|
|
|
# ─── BACKUP WIREGUARD KEYS AND PEERS ──────────────────────────────────────────
|
|
sep
|
|
info "Backing up WireGuard keys and peers..."
|
|
|
|
WG_CONF_CONTENT=$(docker exec "$LEGACY_WG" cat /config/wg_confs/wg0.conf 2>/dev/null || true)
|
|
[ -z "$WG_CONF_CONTENT" ] && fail "Could not read wg0.conf from container $LEGACY_WG"
|
|
|
|
LEGACY_PRIVATE_KEY=$(echo "$WG_CONF_CONTENT" | grep "^PrivateKey" | awk '{print $3}' | tr -d '[:space:]')
|
|
[ -z "$LEGACY_PRIVATE_KEY" ] && fail "PrivateKey not found in wg0.conf"
|
|
echo "$LEGACY_PRIVATE_KEY" > "$BACKUP_DIR/private_key"
|
|
chmod 600 "$BACKUP_DIR/private_key"
|
|
chown "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/private_key"
|
|
ok "Private key saved."
|
|
|
|
LEGACY_PUBLIC_KEY=$(docker exec "$LEGACY_WG" cat /config/server/publickey-server 2>/dev/null | tr -d '[:space:]' || true)
|
|
if [ -z "$LEGACY_PUBLIC_KEY" ]; then
|
|
warn "publickey-server not found — deriving from private key..."
|
|
LEGACY_PUBLIC_KEY=$(echo "$LEGACY_PRIVATE_KEY" | wg pubkey 2>/dev/null || true)
|
|
fi
|
|
[ -z "$LEGACY_PUBLIC_KEY" ] && fail "Could not obtain public key."
|
|
echo "$LEGACY_PUBLIC_KEY" > "$BACKUP_DIR/public_key"
|
|
chmod 600 "$BACKUP_DIR/public_key"
|
|
chown "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/public_key"
|
|
ok "Public key: $LEGACY_PUBLIC_KEY"
|
|
|
|
PEER_CONF=$(docker exec "$LEGACY_WG" wg showconf wg0 2>/dev/null || echo "$WG_CONF_CONTENT")
|
|
echo "$PEER_CONF" > "$BACKUP_DIR/wg0-legacy.conf"
|
|
cp "$BACKUP_DIR/wg0-legacy.conf" "$BACKUP_DIR/wg0-legacy.conf.original"
|
|
chmod 600 "$BACKUP_DIR/wg0-legacy.conf" "$BACKUP_DIR/wg0-legacy.conf.original"
|
|
chown "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/wg0-legacy.conf" "$BACKUP_DIR/wg0-legacy.conf.original"
|
|
PEER_COUNT=$(grep -c "^\[Peer\]" "$BACKUP_DIR/wg0-legacy.conf" || echo 0)
|
|
ok "$PEER_COUNT peers saved."
|
|
|
|
# ─── BACKUP NGINX ─────────────────────────────────────────────────────────────
|
|
sep
|
|
info "Backing up Nginx..."
|
|
mkdir -p "$BACKUP_DIR/nginx/sites-available" "$BACKUP_DIR/nginx/sites-enabled"
|
|
cp -r /etc/nginx/sites-available/. "$BACKUP_DIR/nginx/sites-available/" 2>/dev/null || true
|
|
cp -r /etc/nginx/sites-enabled/. "$BACKUP_DIR/nginx/sites-enabled/" 2>/dev/null || true
|
|
_save /etc/nginx/nginx.conf nginx/nginx.conf
|
|
chown -R "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/nginx/"
|
|
ok "Nginx configs backed up."
|
|
|
|
# ─── BACKUP SSL CERTIFICATES ──────────────────────────────────────────────────
|
|
sep
|
|
info "Backing up SSL certificates..."
|
|
mkdir -p "$BACKUP_DIR/letsencrypt"
|
|
if [ -d /etc/letsencrypt ]; then
|
|
cp -r /etc/letsencrypt/. "$BACKUP_DIR/letsencrypt/"
|
|
chown -R "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/letsencrypt/"
|
|
ok "Certificates saved."
|
|
else
|
|
warn "/etc/letsencrypt not found."
|
|
fi
|
|
|
|
# ─── BACKUP UFW ───────────────────────────────────────────────────────────────
|
|
sep
|
|
info "Backing up UFW rules..."
|
|
ufw status verbose > "$BACKUP_DIR/ufw-snapshot.txt" 2>/dev/null || true
|
|
chown "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/ufw-snapshot.txt"
|
|
ok "UFW snapshot saved."
|
|
|
|
# ─── BACKUP LEGACY ENV ────────────────────────────────────────────────────────
|
|
sep
|
|
info "Backing up legacy .env..."
|
|
LEGACY_API_TOKEN=""
|
|
|
|
if [ -f "$LEGACY_COMPOSE_DIR/.env" ]; then
|
|
_save "$LEGACY_COMPOSE_DIR/.env" legacy.env
|
|
LEGACY_API_TOKEN=$(grep -E '^API_TOKEN=' "$BACKUP_DIR/legacy.env" 2>/dev/null \
|
|
| cut -d= -f2 | tr -d '[:space:]' || true)
|
|
else
|
|
warn ".env not found in legacy stack — checking docker-compose.yml..."
|
|
LEGACY_API_TOKEN=$(grep -E 'API_TOKEN' "$LEGACY_COMPOSE_DIR/docker-compose.yml" 2>/dev/null \
|
|
| grep -oP '(?<==)[^\s"]+' | head -1 | tr -d '[:space:]' || true)
|
|
fi
|
|
|
|
# Always write legacy.env so env.sh never fails on missing file
|
|
{
|
|
echo "# Generated by 00-backup.sh — $(date '+%Y-%m-%d %H:%M:%S')"
|
|
if [ -n "$LEGACY_API_TOKEN" ]; then
|
|
echo "API_TOKEN=${LEGACY_API_TOKEN}"
|
|
ok "API_TOKEN extracted from legacy stack"
|
|
else
|
|
echo "API_TOKEN="
|
|
warn "API_TOKEN not found in legacy — a new one will be generated"
|
|
fi
|
|
} > "$BACKUP_DIR/legacy.env"
|
|
chown "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/legacy.env"
|
|
|
|
# ─── DETECT NETWORK ───────────────────────────────────────────────────────────
|
|
sep
|
|
IPV6_ADDRS=$(ip -6 addr show | grep -oP 'inet6 \K[0-9a-fA-F:]+' | grep -v '^::1$' || true)
|
|
if [ -n "$IPV6_ADDRS" ]; then
|
|
echo "ipv6=true" > "$BACKUP_DIR/network_info"
|
|
ok "IPv6 detected."
|
|
else
|
|
echo "ipv6=false" > "$BACKUP_DIR/network_info"
|
|
info "IPv4 only."
|
|
fi
|
|
chown "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/network_info"
|
|
|
|
# ─── SSH KEY ──────────────────────────────────────────────────────────────────
|
|
sep
|
|
info "Adding $LINUX_USER to docker group..."
|
|
usermod -aG docker "$LINUX_USER" 2>/dev/null || true
|
|
ok "$LINUX_USER added to docker group. Changes take effect on next login."
|
|
|
|
info "Checking SSH key for private repo..."
|
|
mkdir -p "$LINUX_HOME/.ssh"
|
|
chmod 700 "$LINUX_HOME/.ssh"
|
|
chown "$LINUX_USER":"$LINUX_USER" "$LINUX_HOME/.ssh"
|
|
if [ ! -f "$LINUX_HOME/.ssh/id_ed25519" ]; then
|
|
sudo -u "$LINUX_USER" ssh-keygen -t ed25519 -f "$LINUX_HOME/.ssh/id_ed25519" -N "" -q
|
|
ok "SSH key generated."
|
|
else
|
|
ok "SSH key already exists."
|
|
fi
|
|
SSH_PUBKEY=$(cat "$LINUX_HOME/.ssh/id_ed25519.pub")
|
|
echo "$SSH_PUBKEY" > "$BACKUP_DIR/ssh_pubkey"
|
|
chown "$LINUX_USER":"$LINUX_USER" "$BACKUP_DIR/ssh_pubkey"
|
|
|
|
# ─── NOTE: legacy stack NOT shut down here ────────────────────────────────────
|
|
# go-legacy continues running until 02-peers.sh confirms the new
|
|
# WireGuard is up and identity is preserved. This avoids any VPN downtime
|
|
# during the install phase.
|
|
|
|
echo "[END-00] $(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG"
|
|
|
|
echo ""
|
|
echo "========================================="
|
|
echo " Backup complete — legacy still running"
|
|
echo "========================================="
|
|
echo ""
|
|
echo " Backup dir : $BACKUP_DIR"
|
|
echo " Legacy stack : $LEGACY_COMPOSE_DIR"
|
|
echo " Public key : $LEGACY_PUBLIC_KEY"
|
|
echo " Peers saved : $PEER_COUNT"
|
|
echo ""
|
|
echo " SSH key for Simplified Privacy:"
|
|
echo " $SSH_PUBKEY"
|
|
echo ""
|
|
echo " go-legacy is still running."
|
|
echo " It will be stopped by 02-peers.sh"
|
|
echo " only after the new WireGuard is verified."
|
|
echo ""
|
|
echo " Log: cat $LOG"
|
|
echo "========================================="
|