feat(migration): Extend migration tools v2.1.0 with 19 modules

Add comprehensive data migration covering all SecuBox services:

Export modules (migration-export.sh):
- dns: BIND zones, Vortex RPZ blocklists, Unbound, AdGuard, Pi-hole
- databases: SQLite, MySQL/MariaDB, PostgreSQL, Redis dumps
- scripts: Custom scripts, systemd units, rc.local, cron jobs
- services: All /srv/* directories including:
  - Streamlit instances
  - Metablogizer/Metabolizer apps
  - Gitea/Git repositories with full history
  - Docker compose configurations
  - LXC container configs
  - mitmproxy, config-vault, saas-relay

Import modules (migration-import.sh):
- Corresponding restore functions for all new modules
- Service detection and systemd integration
- Database restore with owner/permission handling

Enhanced HAProxy export:
- conf.d modular architecture
- Certificate management
- Lua scripts and maps
- mitmproxy route integration

Total modules: 19 (network, firewall, wireguard, crowdsec, dhcp,
haproxy, nginx, certs, content, vhosts, users, state, git, media,
mail, accounts, dns, databases, scripts, services)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-04-29 14:17:30 +02:00
parent a8b80ff9c4
commit 6edd343019
2 changed files with 632 additions and 11 deletions

View File

@ -15,7 +15,7 @@ set -euo pipefail
readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
readonly REPO="$(cd "$SCRIPT_DIR/.." && pwd)"
readonly VERSION="2.0.0"
readonly VERSION="2.1.0"
readonly TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
# ── Colors ──
@ -59,7 +59,7 @@ Options:
-m, --modules LIST Comma-separated module list (default: all)
Available: network,firewall,wireguard,crowdsec,dhcp,
haproxy,nginx,certs,content,vhosts,users,
git,media,mail,accounts
git,media,mail,accounts,dns,databases,scripts
--help Show this help
Examples:
@ -243,17 +243,66 @@ export_dhcp() {
}
export_haproxy() {
section "Exporting: HAProxy Configuration"
section "Exporting: HAProxy Configuration (Full)"
local dst="$WORKDIR/configs/haproxy"
mkdir -p "$dst"
local secrets_dst="$WORKDIR/secrets/haproxy"
mkdir -p "$dst" "$secrets_dst"
# Main config
ssh_run "cat /etc/haproxy/haproxy.cfg 2>/dev/null" > "$dst/haproxy.cfg" || warn "No HAProxy config"
# Additional configs
ssh_run "tar -czf - /etc/haproxy/conf.d 2>/dev/null" | tar -xzf - -C "$dst" --strip-components=2 || true
# conf.d directory (backend definitions, ACLs, routing)
if ssh_run "[ -d '/etc/haproxy/conf.d' ]" 2>/dev/null; then
log " Exporting HAProxy conf.d..."
mkdir -p "$dst/conf.d"
ssh_run "tar -czf - /etc/haproxy/conf.d 2>/dev/null" | tar -xzf - -C "$dst/conf.d" --strip-components=3 || true
local conf_count=$(ls "$dst/conf.d"/*.cfg 2>/dev/null | wc -l || echo "0")
log " Found $conf_count config snippets"
fi
ok "HAProxy exported"
# HAProxy certificates (secrets)
if ssh_run "[ -d '/etc/haproxy/certs' ]" 2>/dev/null; then
log " Exporting HAProxy certificates..."
mkdir -p "$secrets_dst/certs"
ssh_run "tar -czf - /etc/haproxy/certs 2>/dev/null" | tar -xzf - -C "$secrets_dst/certs" --strip-components=3 || true
local cert_count=$(ssh_run "ls /etc/haproxy/certs/*.pem 2>/dev/null | wc -l" || echo "0")
log " Found $cert_count certificate files"
fi
# HAProxy maps (domain → backend mappings)
if ssh_run "[ -d '/etc/haproxy/maps' ]" 2>/dev/null; then
log " Exporting HAProxy maps..."
mkdir -p "$dst/maps"
ssh_run "tar -czf - /etc/haproxy/maps 2>/dev/null" | tar -xzf - -C "$dst/maps" --strip-components=3 || true
fi
# HAProxy errors directory (custom error pages)
if ssh_run "[ -d '/etc/haproxy/errors' ]" 2>/dev/null; then
log " Exporting HAProxy error pages..."
mkdir -p "$dst/errors"
ssh_run "tar -czf - /etc/haproxy/errors 2>/dev/null" | tar -xzf - -C "$dst/errors" --strip-components=3 || true
fi
# ACME/Let's Encrypt HAProxy integration
if ssh_run "[ -f '/etc/haproxy/acme.cfg' ]" 2>/dev/null; then
ssh_run "cat /etc/haproxy/acme.cfg 2>/dev/null" > "$dst/acme.cfg" || true
fi
# HAProxy Lua scripts
if ssh_run "[ -d '/etc/haproxy/lua' ]" 2>/dev/null; then
log " Exporting HAProxy Lua scripts..."
mkdir -p "$dst/lua"
ssh_run "tar -czf - /etc/haproxy/lua 2>/dev/null" | tar -xzf - -C "$dst/lua" --strip-components=3 || true
fi
# mitmproxy routes mapping (SecuBox specific)
if ssh_run "[ -f '/srv/mitmproxy/haproxy-routes.json' ]" 2>/dev/null; then
log " Exporting mitmproxy routes..."
ssh_run "cat /srv/mitmproxy/haproxy-routes.json 2>/dev/null" > "$dst/mitmproxy-routes.json" || true
fi
local size=$(du -sh "$dst" 2>/dev/null | cut -f1 || echo "0")
ok "HAProxy exported ($size)"
}
export_nginx() {
@ -563,6 +612,285 @@ export_accounts() {
ok "User accounts exported ($user_count users, $size)"
}
export_dns() {
section "Exporting: DNS Services (BIND, Vortex, AdGuard)"
local dst="$WORKDIR/configs/dns"
local secrets_dst="$WORKDIR/secrets/dns"
mkdir -p "$dst" "$secrets_dst"
# BIND/named configuration
if ssh_run "[ -d '/etc/bind' ]" 2>/dev/null; then
log " Exporting BIND configuration..."
mkdir -p "$dst/bind"
ssh_run "tar -czf - /etc/bind 2>/dev/null" | tar -xzf - -C "$dst/bind" --strip-components=2 || true
# Zones directory separately (may be large)
if ssh_run "[ -d '/etc/bind/zones' ]" 2>/dev/null; then
log " Exporting DNS zones..."
mkdir -p "$dst/bind/zones"
ssh_run "tar -czf - /etc/bind/zones 2>/dev/null" | tar -xzf - -C "$dst/bind/zones" --strip-components=3 || true
local zone_count=$(ls "$dst/bind/zones"/*.zone 2>/dev/null | wc -l || echo "0")
log " Found $zone_count zone files"
fi
# RNDC key (secret)
ssh_run "cat /etc/bind/rndc.key 2>/dev/null" > "$secrets_dst/rndc.key" || true
fi
# Unbound configuration
if ssh_run "[ -d '/etc/unbound' ]" 2>/dev/null; then
log " Exporting Unbound configuration..."
mkdir -p "$dst/unbound"
ssh_run "tar -czf - /etc/unbound 2>/dev/null" | tar -xzf - -C "$dst/unbound" --strip-components=2 || true
fi
# Vortex DNS (dnsmasq-based blocklists)
if ssh_run "[ -d '/etc/dnsmasq.d/vortex' ]" 2>/dev/null; then
log " Exporting Vortex DNS blocklists..."
mkdir -p "$dst/vortex"
ssh_run "tar -czf - /etc/dnsmasq.d/vortex 2>/dev/null" | tar -xzf - -C "$dst/vortex" --strip-components=3 || true
ssh_run "cat /etc/dnsmasq.d/vortex*.conf 2>/dev/null" > "$dst/vortex/vortex-main.conf" || true
fi
# Vortex RPZ zone (Response Policy Zone for blocking)
if ssh_run "[ -f '/etc/bind/zones/rpz.vortex.zone' ]" 2>/dev/null; then
log " Exporting Vortex RPZ zone (blocklist)..."
ssh_run "cat /etc/bind/zones/rpz.vortex.zone 2>/dev/null" > "$dst/bind/zones/rpz.vortex.zone" || true
local rpz_size=$(ssh_run "du -h /etc/bind/zones/rpz.vortex.zone 2>/dev/null | cut -f1" || echo "0")
log " RPZ zone size: $rpz_size"
fi
# AdGuard Home
if ssh_run "[ -f '/etc/adguardhome/AdGuardHome.yaml' ]" 2>/dev/null; then
log " Exporting AdGuard Home configuration..."
mkdir -p "$dst/adguardhome"
ssh_run "cat /etc/adguardhome/AdGuardHome.yaml 2>/dev/null" > "$dst/adguardhome/AdGuardHome.yaml" || true
# AdGuard Home data (filters, stats)
if ssh_run "[ -d '/var/lib/adguardhome/data' ]" 2>/dev/null; then
mkdir -p "$dst/adguardhome/data"
ssh_run "tar -czf - /var/lib/adguardhome/data 2>/dev/null" | tar -xzf - -C "$dst/adguardhome/data" --strip-components=4 || true
fi
fi
# Pi-hole (if present)
if ssh_run "[ -d '/etc/pihole' ]" 2>/dev/null; then
log " Exporting Pi-hole configuration..."
mkdir -p "$dst/pihole"
ssh_run "tar -czf - /etc/pihole 2>/dev/null" | tar -xzf - -C "$dst/pihole" --strip-components=2 || true
fi
# Additional dnsmasq configs
ssh_run "cat /etc/dnsmasq.d/*.conf 2>/dev/null" > "$dst/dnsmasq.d.conf" || true
local size=$(du -sh "$dst" 2>/dev/null | cut -f1 || echo "0")
ok "DNS services exported ($size)"
}
export_databases() {
section "Exporting: Databases (SQLite, MySQL dumps)"
local dst="$WORKDIR/state/databases"
mkdir -p "$dst"
# SQLite databases from common locations
local db_paths="/var/lib/*.db /srv/*.db /var/lib/*/data/*.db /var/lib/*/*/*.db"
local db_count=0
for db_pattern in $db_paths; do
ssh_run "ls $db_pattern 2>/dev/null" | while read -r db_file; do
[[ -z "$db_file" ]] && continue
local db_name=$(basename "$db_file")
local db_dir=$(dirname "$db_file" | tr '/' '_' | sed 's/^_//')
mkdir -p "$dst/$db_dir"
log " Exporting: $db_file"
ssh_run "cat '$db_file' 2>/dev/null" > "$dst/$db_dir/$db_name" || true
((db_count++))
done || true
done
# MySQL/MariaDB dump (if mysqldump available)
if ssh_run "which mysqldump >/dev/null 2>&1"; then
log " Creating MySQL dump..."
mkdir -p "$dst/mysql"
ssh_run "mysqldump --all-databases --single-transaction 2>/dev/null" > "$dst/mysql/all-databases.sql" || warn "MySQL dump failed"
fi
# PostgreSQL dump (if pg_dumpall available)
if ssh_run "which pg_dumpall >/dev/null 2>&1"; then
log " Creating PostgreSQL dump..."
mkdir -p "$dst/postgresql"
ssh_run "su - postgres -c 'pg_dumpall' 2>/dev/null" > "$dst/postgresql/all-databases.sql" || warn "PostgreSQL dump failed"
fi
# Redis dump
if ssh_run "[ -f '/var/lib/redis/dump.rdb' ]" 2>/dev/null; then
log " Exporting Redis dump..."
mkdir -p "$dst/redis"
ssh_run "cat /var/lib/redis/dump.rdb 2>/dev/null" > "$dst/redis/dump.rdb" || true
fi
local size=$(du -sh "$dst" 2>/dev/null | cut -f1 || echo "0")
ok "Databases exported ($size)"
}
export_scripts() {
section "Exporting: Custom Scripts and Systemd Units"
local dst="$WORKDIR/configs/scripts"
mkdir -p "$dst"
# Custom scripts from common locations
local script_dirs="/usr/local/bin /usr/local/sbin /root/scripts /root/bin /opt/scripts"
for script_dir in $script_dirs; do
if ssh_run "[ -d '$script_dir' ]" 2>/dev/null; then
log " Exporting: $script_dir"
local dir_name=$(echo "$script_dir" | tr '/' '_' | sed 's/^_//')
mkdir -p "$dst/$dir_name"
ssh_run "tar -czf - '$script_dir' 2>/dev/null" | tar -xzf - -C "$dst/$dir_name" --strip-components=3 || true
fi
done
# Systemd unit overrides
if ssh_run "[ -d '/etc/systemd/system' ]" 2>/dev/null; then
log " Exporting systemd unit overrides..."
mkdir -p "$dst/systemd"
ssh_run "find /etc/systemd/system -name '*.service' -o -name '*.d' -type d 2>/dev/null" | while read -r unit; do
[[ -z "$unit" ]] && continue
local unit_name=$(basename "$unit")
if [[ -d "$unit" ]]; then
ssh_run "tar -czf - '$unit' 2>/dev/null" | tar -xzf - -C "$dst/systemd" --strip-components=3 || true
else
ssh_run "cat '$unit' 2>/dev/null" > "$dst/systemd/$unit_name" || true
fi
done || true
fi
# Init.d scripts (OpenWrt style)
if ssh_run "[ -d '/etc/init.d' ]" 2>/dev/null; then
log " Exporting init.d scripts..."
mkdir -p "$dst/init.d"
ssh_run "tar -czf - /etc/init.d 2>/dev/null" | tar -xzf - -C "$dst/init.d" --strip-components=2 || true
fi
# RC.local
ssh_run "cat /etc/rc.local 2>/dev/null" > "$dst/rc.local" || true
# Environment files
mkdir -p "$dst/environment"
ssh_run "cat /etc/environment 2>/dev/null" > "$dst/environment/environment" || true
ssh_run "cat /etc/default/* 2>/dev/null" > "$dst/environment/defaults" || true
local size=$(du -sh "$dst" 2>/dev/null | cut -f1 || echo "0")
ok "Scripts and units exported ($size)"
}
export_services() {
section "Exporting: Application Services (/srv/*)"
local dst="$WORKDIR/content/services"
mkdir -p "$dst"
# List of service directories to export from /srv/
local services="
streamlit
gitea
metablogizer
metabolizer
metacatalog
mitmproxy
mitmproxy-in
mitmproxy-out
secubox
config-vault
saas-relay
hexojs
gotosocial
nextcloud
peertube
matrix
simplex
voip
webradio
zigbee2mqtt
domoticz
photoprism
rezapp
haproxy
crowdsec
dns
dns-master
lxc
jabber
jitsi
localai
sherlock
maltego
"
for svc in $services; do
svc=$(echo "$svc" | tr -d ' ')
[[ -z "$svc" ]] && continue
if ssh_run "[ -d '/srv/$svc' ]" 2>/dev/null; then
log " Exporting: /srv/$svc"
mkdir -p "$dst/$svc"
# Export service directory (excluding large binary/cache dirs)
ssh_run "tar -czf - \
--exclude='*.log' \
--exclude='node_modules' \
--exclude='__pycache__' \
--exclude='.cache' \
--exclude='cache' \
--exclude='*.pyc' \
--exclude='.venv' \
--exclude='venv' \
/srv/$svc 2>/dev/null" | tar -xzf - -C "$dst/$svc" --strip-components=2 || warn "Partial export: $svc"
fi
done
# Export Streamlit apps specifically
if ssh_run "[ -d '/srv/streamlit/apps' ]" 2>/dev/null; then
log " Exporting Streamlit apps..."
mkdir -p "$dst/streamlit-apps"
ssh_run "tar -czf - /srv/streamlit/apps 2>/dev/null" | tar -xzf - -C "$dst/streamlit-apps" --strip-components=3 || true
local app_count=$(ssh_run "ls -d /srv/streamlit/apps/*/ 2>/dev/null | wc -l" || echo "0")
log " Found $app_count Streamlit apps"
fi
# Export Git repositories (full repos with history)
log " Discovering Git repositories..."
ssh_run "find /srv -maxdepth 4 -name '.git' -type d 2>/dev/null" | while read -r git_dir; do
[[ -z "$git_dir" ]] && continue
local repo_path=$(dirname "$git_dir")
local repo_name=$(echo "$repo_path" | sed 's|/srv/||' | tr '/' '_')
log " Exporting repo: $repo_name"
mkdir -p "$dst/git-repos"
ssh_run "tar -czf - '$repo_path' 2>/dev/null" > "$dst/git-repos/${repo_name}.tar.gz" || true
done || true
# Export Docker/Podman compose files
log " Exporting Docker compose files..."
mkdir -p "$dst/docker-compose"
ssh_run "find /srv -name 'docker-compose*.yml' -o -name 'docker-compose*.yaml' 2>/dev/null" | while read -r compose_file; do
[[ -z "$compose_file" ]] && continue
local compose_name=$(echo "$compose_file" | tr '/' '_' | sed 's/^_srv_//')
ssh_run "cat '$compose_file' 2>/dev/null" > "$dst/docker-compose/$compose_name" || true
done || true
# Export LXC container configs
if ssh_run "[ -d '/srv/lxc' ]" 2>/dev/null; then
log " Exporting LXC container configs..."
mkdir -p "$dst/lxc"
ssh_run "ls /srv/lxc 2>/dev/null" | while read -r container; do
[[ -z "$container" ]] && continue
ssh_run "cat /srv/lxc/$container/config 2>/dev/null" > "$dst/lxc/${container}.config" || true
done || true
fi
local size=$(du -sh "$dst" 2>/dev/null | cut -f1 || echo "0")
local svc_count=$(ls -d "$dst"/*/ 2>/dev/null | wc -l || echo "0")
ok "Services exported ($svc_count services, $size)"
}
# ── Module selection ──
declare -A MODULE_FUNCS=(
[network]=export_network
@ -581,9 +909,13 @@ declare -A MODULE_FUNCS=(
[media]=export_media
[mail]=export_mail
[accounts]=export_accounts
[dns]=export_dns
[databases]=export_databases
[scripts]=export_scripts
[services]=export_services
)
ALL_MODULES="network,firewall,wireguard,crowdsec,dhcp,haproxy,nginx,certs,content,vhosts,users,state,git,media,mail,accounts"
ALL_MODULES="network,firewall,wireguard,crowdsec,dhcp,haproxy,nginx,certs,content,vhosts,users,state,git,media,mail,accounts,dns,databases,scripts,services"
if [[ "$MODULES" == "all" ]]; then
MODULES="$ALL_MODULES"

View File

@ -15,7 +15,7 @@ set -euo pipefail
readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
readonly REPO="$(cd "$SCRIPT_DIR/.." && pwd)"
readonly VERSION="2.0.0"
readonly VERSION="2.1.0"
readonly TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
# ── Colors ──
@ -55,6 +55,9 @@ MEDIA_DIR="/srv/media"
MAIL_DIR="/var/vmail"
POSTFIX_DIR="/etc/postfix"
DOVECOT_DIR="/etc/dovecot"
BIND_DIR="/etc/bind"
UNBOUND_DIR="/etc/unbound"
ADGUARD_DIR="/etc/adguardhome"
usage() {
cat <<EOF
@ -76,7 +79,7 @@ Options:
-m, --modules LIST Comma-separated module list (default: all)
Available: network,firewall,wireguard,crowdsec,dhcp,
haproxy,nginx,certs,content,vhosts,users,state,
git,media,mail,accounts
git,media,mail,accounts,dns,databases,scripts
--help Show this help
Examples:
@ -879,6 +882,288 @@ import_accounts() {
fi
}
import_dns() {
section "Importing: DNS Services"
local src="$WORKDIR/configs/dns"
local secrets_src="$WORKDIR/secrets/dns"
if [[ -d "$src" && -n "$(ls -A "$src" 2>/dev/null)" ]]; then
# BIND/named
if [[ -d "$src/bind" ]]; then
log " Importing BIND configuration..."
run "mkdir -p '$BIND_DIR'"
run "cp -r '$src/bind/'* '$BIND_DIR/' 2>/dev/null || true"
# Import zones
if [[ -d "$src/bind/zones" ]]; then
run "mkdir -p '$BIND_DIR/zones'"
run "cp -r '$src/bind/zones/'* '$BIND_DIR/zones/' 2>/dev/null || true"
local zone_count=$(ls "$src/bind/zones"/*.zone 2>/dev/null | wc -l || echo "0")
log " Imported $zone_count zone files"
fi
# Import RNDC key from secrets
if [[ -f "$secrets_src/rndc.key" ]]; then
run "cp '$secrets_src/rndc.key' '$BIND_DIR/'"
run "chmod 600 '$BIND_DIR/rndc.key'"
fi
if [[ $DRY_RUN -eq 0 ]]; then
chown -R bind:bind "$BIND_DIR" 2>/dev/null || true
systemctl restart named 2>/dev/null || systemctl restart bind9 2>/dev/null || warn "BIND restart failed"
fi
fi
# Unbound
if [[ -d "$src/unbound" ]]; then
log " Importing Unbound configuration..."
run "mkdir -p '$UNBOUND_DIR'"
run "cp -r '$src/unbound/'* '$UNBOUND_DIR/' 2>/dev/null || true"
if [[ $DRY_RUN -eq 0 ]]; then
systemctl restart unbound 2>/dev/null || warn "Unbound restart failed"
fi
fi
# Vortex DNS (dnsmasq blocklists)
if [[ -d "$src/vortex" ]]; then
log " Importing Vortex DNS blocklists..."
run "mkdir -p '/etc/dnsmasq.d/vortex'"
run "cp -r '$src/vortex/'* '/etc/dnsmasq.d/vortex/' 2>/dev/null || true"
fi
# AdGuard Home
if [[ -d "$src/adguardhome" ]]; then
log " Importing AdGuard Home configuration..."
run "mkdir -p '$ADGUARD_DIR'"
run "cp '$src/adguardhome/AdGuardHome.yaml' '$ADGUARD_DIR/' 2>/dev/null || true"
if [[ -d "$src/adguardhome/data" ]]; then
run "mkdir -p '/var/lib/adguardhome/data'"
run "cp -r '$src/adguardhome/data/'* '/var/lib/adguardhome/data/' 2>/dev/null || true"
fi
if [[ $DRY_RUN -eq 0 ]]; then
systemctl restart AdGuardHome 2>/dev/null || warn "AdGuard Home restart failed"
fi
fi
# Pi-hole
if [[ -d "$src/pihole" ]]; then
log " Importing Pi-hole configuration..."
run "mkdir -p '/etc/pihole'"
run "cp -r '$src/pihole/'* '/etc/pihole/' 2>/dev/null || true"
if [[ $DRY_RUN -eq 0 ]]; then
pihole restartdns 2>/dev/null || warn "Pi-hole restart failed"
fi
fi
local size=$(du -sh "$src" 2>/dev/null | cut -f1 || echo "0")
ok "DNS services imported ($size)"
else
warn "No DNS configuration to import"
fi
}
import_databases() {
section "Importing: Databases"
local src="$WORKDIR/state/databases"
if [[ -d "$src" && -n "$(ls -A "$src" 2>/dev/null)" ]]; then
# SQLite databases - restore to original locations
for db_dir in "$src"/var_lib_*; do
[[ -d "$db_dir" ]] || continue
local original_path=$(echo "$db_dir" | sed 's/_/\//g' | sed 's/.*var/\/var/')
log " Restoring databases to: $original_path"
run "mkdir -p '$original_path'"
run "cp -r '$db_dir/'* '$original_path/' 2>/dev/null || true"
done
# MySQL restore
if [[ -f "$src/mysql/all-databases.sql" ]]; then
log " Restoring MySQL databases..."
if [[ $DRY_RUN -eq 0 ]]; then
mysql < "$src/mysql/all-databases.sql" 2>/dev/null || warn "MySQL restore failed"
else
log " Would restore MySQL from all-databases.sql"
fi
fi
# PostgreSQL restore
if [[ -f "$src/postgresql/all-databases.sql" ]]; then
log " Restoring PostgreSQL databases..."
if [[ $DRY_RUN -eq 0 ]]; then
su - postgres -c "psql < $src/postgresql/all-databases.sql" 2>/dev/null || warn "PostgreSQL restore failed"
else
log " Would restore PostgreSQL from all-databases.sql"
fi
fi
# Redis restore
if [[ -f "$src/redis/dump.rdb" ]]; then
log " Restoring Redis dump..."
run "mkdir -p '/var/lib/redis'"
run "cp '$src/redis/dump.rdb' '/var/lib/redis/'"
if [[ $DRY_RUN -eq 0 ]]; then
chown redis:redis /var/lib/redis/dump.rdb 2>/dev/null || true
systemctl restart redis 2>/dev/null || warn "Redis restart failed"
fi
fi
local size=$(du -sh "$src" 2>/dev/null | cut -f1 || echo "0")
ok "Databases imported ($size)"
else
warn "No databases to import"
fi
}
import_scripts() {
section "Importing: Custom Scripts and Units"
local src="$WORKDIR/configs/scripts"
if [[ -d "$src" && -n "$(ls -A "$src" 2>/dev/null)" ]]; then
# Custom scripts
for script_dir in "$src"/usr_local_*; do
[[ -d "$script_dir" ]] || continue
local target="/usr/local/bin"
log " Importing scripts to: $target"
run "mkdir -p '$target'"
run "cp -r '$script_dir/'* '$target/' 2>/dev/null || true"
run "chmod +x '$target/'* 2>/dev/null || true"
done
for script_dir in "$src"/root_*; do
[[ -d "$script_dir" ]] || continue
local target="/root/scripts"
log " Importing scripts to: $target"
run "mkdir -p '$target'"
run "cp -r '$script_dir/'* '$target/' 2>/dev/null || true"
run "chmod +x '$target/'* 2>/dev/null || true"
done
# Systemd unit overrides
if [[ -d "$src/systemd" ]]; then
log " Importing systemd unit overrides..."
for unit in "$src/systemd"/*; do
[[ -e "$unit" ]] || continue
local unit_name=$(basename "$unit")
if [[ -d "$unit" ]]; then
run "mkdir -p '/etc/systemd/system/$unit_name'"
run "cp -r '$unit/'* '/etc/systemd/system/$unit_name/' 2>/dev/null || true"
else
run "cp '$unit' '/etc/systemd/system/$unit_name'"
fi
log " Imported: $unit_name"
done
if [[ $DRY_RUN -eq 0 ]]; then
systemctl daemon-reload 2>/dev/null || true
fi
fi
# RC.local
if [[ -f "$src/rc.local" && -s "$src/rc.local" ]]; then
log " Importing rc.local..."
run "cp '$src/rc.local' '/etc/rc.local'"
run "chmod +x '/etc/rc.local'"
fi
# Environment files
if [[ -d "$src/environment" ]]; then
if [[ -f "$src/environment/environment" && -s "$src/environment/environment" ]]; then
log " Importing /etc/environment..."
run "cp '$src/environment/environment' '/etc/environment'"
fi
fi
local size=$(du -sh "$src" 2>/dev/null | cut -f1 || echo "0")
ok "Scripts and units imported ($size)"
else
warn "No scripts to import"
fi
}
import_services() {
section "Importing: Application Services"
local src="$WORKDIR/content/services"
if [[ -d "$src" && -n "$(ls -A "$src" 2>/dev/null)" ]]; then
# Import service directories to /srv/
for svc_dir in "$src"/*/; do
[[ -d "$svc_dir" ]] || continue
local svc_name=$(basename "$svc_dir")
# Skip special directories
[[ "$svc_name" == "git-repos" || "$svc_name" == "docker-compose" || "$svc_name" == "lxc" || "$svc_name" == "streamlit-apps" ]] && continue
log " Importing service: $svc_name"
run "mkdir -p '/srv/$svc_name'"
run "cp -r '$svc_dir'* '/srv/$svc_name/' 2>/dev/null || true"
done
# Import Streamlit apps
if [[ -d "$src/streamlit-apps" ]]; then
log " Importing Streamlit apps..."
run "mkdir -p '/srv/streamlit/apps'"
run "cp -r '$src/streamlit-apps/'* '/srv/streamlit/apps/' 2>/dev/null || true"
fi
# Import Git repositories
if [[ -d "$src/git-repos" ]]; then
log " Importing Git repositories..."
run "mkdir -p '/srv/repos'"
for repo_tar in "$src/git-repos"/*.tar.gz; do
[[ -f "$repo_tar" ]] || continue
local repo_name=$(basename "$repo_tar" .tar.gz)
log " Importing repo: $repo_name"
run "mkdir -p '/srv/repos/$repo_name'"
run "tar -xzf '$repo_tar' -C '/srv/repos/$repo_name' --strip-components=2 2>/dev/null || true"
done
fi
# Import Docker compose files
if [[ -d "$src/docker-compose" ]]; then
log " Importing Docker compose files..."
for compose in "$src/docker-compose"/*; do
[[ -f "$compose" ]] || continue
local compose_name=$(basename "$compose")
local target_path=$(echo "$compose_name" | sed 's/_/\//g' | sed 's/^srv/\/srv/')
local target_dir=$(dirname "$target_path")
run "mkdir -p '$target_dir'"
run "cp '$compose' '$target_path'"
log " Imported: $compose_name"
done
fi
# Import LXC configs
if [[ -d "$src/lxc" ]]; then
log " Importing LXC container configs..."
run "mkdir -p '/srv/lxc'"
for lxc_config in "$src/lxc"/*.config; do
[[ -f "$lxc_config" ]] || continue
local container=$(basename "$lxc_config" .config)
run "mkdir -p '/srv/lxc/$container'"
run "cp '$lxc_config' '/srv/lxc/$container/config'"
log " Imported: $container"
done
fi
# Fix ownership
if [[ $DRY_RUN -eq 0 ]]; then
chown -R root:root /srv/* 2>/dev/null || true
# Fix specific service ownership
chown -R www-data:www-data /srv/nextcloud 2>/dev/null || true
chown -R gitea:gitea /srv/gitea 2>/dev/null || true
fi
local size=$(du -sh "$src" 2>/dev/null | cut -f1 || echo "0")
local svc_count=$(ls -d "$src"/*/ 2>/dev/null | wc -l || echo "0")
ok "Services imported ($svc_count services, $size)"
else
warn "No services to import"
fi
}
# ── Module selection ──
declare -A MODULE_FUNCS=(
[network]=import_network
@ -897,9 +1182,13 @@ declare -A MODULE_FUNCS=(
[media]=import_media
[mail]=import_mail
[accounts]=import_accounts
[dns]=import_dns
[databases]=import_databases
[scripts]=import_scripts
[services]=import_services
)
ALL_MODULES="network,firewall,wireguard,crowdsec,dhcp,haproxy,nginx,certs,content,vhosts,users,state,git,media,mail,accounts"
ALL_MODULES="network,firewall,wireguard,crowdsec,dhcp,haproxy,nginx,certs,content,vhosts,users,state,git,media,mail,accounts,dns,databases,scripts,services"
if [[ "$MODULES" == "all" ]]; then
MODULES="$ALL_MODULES"