Restore Repo
Odtwarzanie serwera z repozytorium
Skrypt realizuje
Odtworzenie konfiguracji Docker Compose
- nadpisuje pliki konfiguracyjne (
.yml) z repozytorium, - nie usuwa ani nie nadpisuje lokalnych plików
.env, - nie ingeruje w wolumeny danych, logi ani dane runtime.
Odtworzenie i nadpisanie konfiguracji systemowej
- wybrane pliki w
/etc(m.in.ssh,fail2ban,ufw,docker), - konfigurację
systemd(journald.conf), - jednostki
systemd(*.service,*.timer).
Przywracanie plików z repozytorium do systemu
- repozytorium jest traktowane jako źródło prawdy,
- pliki obecne w repo nadpisują pliki systemowe.
Nadawanie właściwych uprawnień
- konfiguracje systemowe:
root:root+ odpowiednie prawa (644,640), - spójne i deterministyczne prawa po restore.
Plik konfiguracyjny
Do działania skryptu oddtwarzania niezbędny jest plik konfiguracyjny sync.env opisany w dokumentacji skryptu synchronizacji.
Tworzymy plik konfiguracyjny dla skryptu synchronizacji:
Skrypt odtwarzania serwra z repozytorium
Tworzymy jeden zbiorczy skrypt odpowiedzialny za odtwarzanie:
sudo micro /srv/config/scripts/restore-repo.sh
Treść pliku:
#!/usr/bin/env bash
set -euo pipefail
# ANSI Colors
GREEN='\033[0;32m'
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
RED='\033[31m'
NC='\033[0m' # No Color
log() { echo -e "${GREEN}[restore]${NC} $1"; }
header() { echo -e "\n${CYAN}=== $1 ===${NC}"; }
warn() { echo -e "${YELLOW}Warning: $1${NC}"; }
error() { echo -e "${RED}Error: $1${NC}" >&2; }
critical() { echo -e "${RED}CRITICAL ERROR: $1${NC}" >&2; }
umask 022
# Ensure root execution
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
critical "Run as root (use sudo)."
exit 1
fi
# ============================================================
# LOCK MECHANISM
# ============================================================
LOCK_FILE="/tmp/restore-repo.lock"
exec 200>"$LOCK_FILE"
flock -n 200 || { error "Script is already running."; exit 1; }
# ============================================================
# CONFIGURATION & VALIDATION
# ============================================================
CONFIG_FILE="/srv/config/git/sync.env"
if [[ ! -f "$CONFIG_FILE" ]]; then
critical "Config file missing at $CONFIG_FILE"
exit 1
fi
# Verify config file owner and permissions before loading
if [[ "$(stat -c '%U:%G %a' "$CONFIG_FILE")" != "root:root 600" ]]; then
critical "Unsafe perms/owner for $CONFIG_FILE (expected root:root 600)"
exit 1
fi
source "$CONFIG_FILE"
if [[ -z "${REPO_ROOT:-}" ]] || [[ -z "${REPO_USER:-}" ]] || [[ -z "${REPO_GROUP:-}" ]]; then
critical "REPO_ROOT, REPO_USER or REPO_GROUP variables are not set in sync.env"
exit 1
fi
if [[ ! -d "$REPO_ROOT" ]]; then
critical "Repository directory $REPO_ROOT does not exist."
exit 1
fi
# ============================================================
# SAFETY PROMPT (always manual)
# ============================================================
confirm_execution() {
echo -e "${RED}WARNING: You are about to OVERWRITE system files from the repository.${NC}"
echo -e "Source: $REPO_ROOT"
read -p "Are you sure you want to proceed? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted by user."
exit 1
fi
}
# ============================================================
# HELPER FUNCTIONS
# ============================================================
restore_file() {
local repo_path="$REPO_ROOT/$1"
local sys_path="$2"
local owner="$3"
local perms="$4"
if [[ -f "$repo_path" ]]; then
mkdir -p "$(dirname "$sys_path")"
cp -a -- "$repo_path" "$sys_path"
chown "$owner" "$sys_path"
chmod "$perms" "$sys_path"
echo " + Restored: $sys_path ($owner, $perms)"
else
echo -e " ${YELLOW}! Skipped (missing in repo): $1${NC}"
fi
}
# ============================================================
# WRAPPERS (mirror sync structure)
# ============================================================
etc_restore() {
local rel_dir="$1"
shift
local repo_base="host/etc"
local sys_base="/etc"
if [[ "$rel_dir" != "." ]]; then
repo_base="host/etc/$rel_dir"
sys_base="/etc/$rel_dir"
fi
for f in "$@"; do
restore_file "$repo_base/$f" "$sys_base/$f" "root:root" "644"
done
}
systemd_restore() {
local rel_dir="$1"
shift
local repo_base="host/etc/systemd"
local sys_base="/etc/systemd"
if [[ "$rel_dir" != "." ]]; then
repo_base="host/etc/systemd/$rel_dir"
sys_base="/etc/systemd/$rel_dir"
fi
for f in "$@"; do
restore_file "$repo_base/$f" "$sys_base/$f" "root:root" "644"
done
}
units_restore() {
local rel_dir="$1"
shift
local repo_base="host/etc/systemd/system"
local sys_base="/etc/systemd/system"
if [[ "$rel_dir" != "." ]]; then
repo_base="host/etc/systemd/system/$rel_dir"
sys_base="/etc/systemd/system/$rel_dir"
fi
for f in "$@"; do
restore_file "$repo_base/$f" "$sys_base/$f" "root:root" "644"
done
}
# ============================================================
# RESTORE MODULES
# ============================================================
restore_compose() {
header "Restore: Docker Compose"
local src="$REPO_ROOT/compose/"
local dst="${SOURCE_COMPOSE:-}"
if [[ ! -d "$src" ]]; then
warn "Repo compose directory missing. Skipping."
return
fi
if [[ -z "$dst" ]] || [[ ! -d "$dst" ]]; then
warn "SOURCE_COMPOSE not found or unset. Skipping."
return
fi
rsync -av \
--exclude ".git/" \
"$src" "$dst/"
chown -R "$REPO_USER:$REPO_GROUP" "$dst"
log "Compose files updated."
}
restore_etc() {
header "Restore: Host /etc"
etc_restore "ssh" sshd_config ssh_config
etc_restore "fail2ban" jail.local
etc_restore "ufw" ufw.conf user.rules
etc_restore "docker" daemon.json
}
restore_systemd() {
header "Restore: Host /etc/systemd"
systemd_restore "." journald.conf
}
restore_units() {
header "Restore: Host /etc/systemd/system"
units_restore "." restic-backup.service restic-backup.timer
}
restore_host() {
header "Restore: Host (etc + systemd + units)"
restore_etc
restore_systemd
restore_units
}
# ============================================================
# EXECUTION
# ============================================================
TARGET=${1:-host}
confirm_execution
case "$TARGET" in
compose) restore_compose ;;
etc) restore_etc ;;
systemd) restore_systemd ;;
units) restore_units ;;
host) restore_host ;;
all) restore_compose; restore_host ;;
*) error "Usage: $0 {compose|etc|systemd|units|host|all}"; exit 1 ;;
esac
echo ""
log "Completed successfully."
Po zapisaniu nadajemy prawa do uruchamiania:
sudo chmod +x /srv/config/scripts/restore-repo.sh
Uruchamianie odtwarzania
Oddtwarzanie wykonujemy z katalogu skryptów:
cd /srv/config/scripts
sudo ./restore-repo.sh all
Tryby przywracania
Skrypt restore-repo.sh obsługuje następujące tryby pracy:
Tryb compose
Odtwarza wyłącznie definicje Docker Compose z repozytorium (do katalogu roboczego Dockera).
- nadpisywane są pliki konfiguracyjne stacków (
.yml), - lokalne pliki
.envoraz dane runtime nie są usuwane.
sudo ./restore-repo.sh compose
Tryb etc
Odtwarza wybrane pliki konfiguracyjne systemu z katalogu /etc
(np. ssh, fail2ban, ufw, docker).
sudo ./restore-repo.sh etc
Tryb systemd
Odtwarza konfigurację systemd
(np. journald.conf).
sudo ./restore-repo.sh systemd
Tryb units
Odtwarza jednostki systemd
(np. pliki *.service, *.timer).
sudo ./restore-repo.sh units
Tryb host
Odtwarza pełną konfigurację hosta:
/etc/etc/systemd/etc/systemd/system
Jest to tryb domyślny.
sudo ./restore-repo.sh host
Tryb all
Wykonuje pełne odtworzenie konfiguracji:
- Docker Compose
- konfigurację hosta (
host)
sudo ./restore-repo.sh all