#!/usr/bin/env bash set -euo pipefail # sync-nextcloud-ecosystem-conf.sh # # Pull/push a fixed set of server files under /data to a local git-tracked tree, # preserving folder structure but stripping the leading "/data". # # Requires: rsync, ssh # # Examples: # ./sync-nextcloud-ecosystem-conf.sh pull # ./sync-nextcloud-ecosystem-conf.sh push --dry-run # ./sync-nextcloud-ecosystem-conf.sh pull --host henrov@nextcloud.data-pro.nu --port 22 # # Notes: # - Uses remote sudo via: --rsync-path="sudo rsync" # - Allocates a TTY for sudo prompting with ssh -tt # - Transfers ONLY the listed files (push and pull) DEFAULT_HOST="henrov@nextcloud.data-pro.nu" DEFAULT_PORT="22" DEFAULT_REMOTE_BASE="/data" DEFAULT_LOCAL_ROOT="$HOME/Repos/nextcloud_ecosystem/conf" usage() { cat <<'USAGE' Usage: sync-nextcloud-ecosystem-conf.sh [--host USER@HOST] [--port N] [--local-root PATH] [--dry-run] Options: --host USER@HOST SSH target (default: henrov@nextcloud.data-pro.nu) --port N SSH port (default: 22) --local-root PATH Local destination root (default: ~/Repos/nextcloud_ecosystem/conf) --dry-run Show what would change without writing (rsync -n + itemize) -h, --help Show this help Behavior: pull: server:/data/ -> local-root/ push: local-root/ -> server:/data/ Always overwrites destination files (as rsync updates them). Preserves timestamps. USAGE } MODE="${1:-}" shift || true HOST="$DEFAULT_HOST" PORT="$DEFAULT_PORT" REMOTE_BASE="$DEFAULT_REMOTE_BASE" LOCAL_ROOT="$DEFAULT_LOCAL_ROOT" DRY_RUN=0 while [[ $# -gt 0 ]]; do case "$1" in --host) HOST="${2:?missing value for --host}"; shift 2 ;; --port) PORT="${2:?missing value for --port}"; shift 2 ;; --local-root) LOCAL_ROOT="${2:?missing value for --local-root}"; shift 2 ;; --dry-run) DRY_RUN=1; shift ;; -h|--help) usage; exit 0 ;; *) echo "Unknown argument: $1" >&2; usage; exit 2 ;; esac done if [[ "$MODE" != "pull" && "$MODE" != "push" ]]; then echo "Error: first argument must be 'pull' or 'push'." >&2 usage exit 2 fi mkdir -p "$LOCAL_ROOT" # File list is RELATIVE to /data, so /data is effectively "stripped" on local. # Only these files are transferred in either direction. read -r -d '' FILES_FROM <<'EOF' || true caddy/Caddyfile nextcloud/config/config.php nextcloud/php/conf.d/opcache.ini signaling/config/server.conf janus/janus.transport.http.jcfg janus/janus.transport.websockets.jcfg gitlab/config/gitlab.rb EOF tmp_files_from="$(mktemp)" cleanup() { rm -f "$tmp_files_from"; } trap cleanup EXIT printf "%s\n" "$FILES_FROM" > "$tmp_files_from" # rsync options: # -a : archive (recursive, preserve perms, etc.) # -t : preserve times (also included in -a, but explicit for clarity) # -v : verbose # --itemize-changes: useful output, especially with --dry-run # --files-from: copy only specified files # --relative not needed because paths are already relative to REMOTE_BASE/LOCAL_ROOT # # Excludes (mostly relevant if you ever extend this to directories): # *~ , *.swp / *.sw? , *.tmp RSYNC_OPTS=( -avt --itemize-changes --files-from="$tmp_files_from" --exclude='*~' --exclude='*.swp' --exclude='*.sw?' --exclude='*.tmp' ) if [[ "$DRY_RUN" -eq 1 ]]; then RSYNC_OPTS+=( --dry-run ) fi # Use ssh with a TTY so sudo can prompt on the remote end if needed. SSH_CMD=(ssh -T -p "$PORT") # Remote sudo for rsync (read/write privileged files) # Preflight: ensure sudo won't prompt during rsync if ! ssh -p "$PORT" "$HOST" 'sudo -n true' >/dev/null 2>&1; then echo "[warn] Remote sudo needs authentication. Running 'sudo -v' interactively once..." ssh -t -p "$PORT" "$HOST" 'sudo -v' fi REMOTE_RSYNC_PATH='sudo -n rsync' REMOTE_SRC="${HOST}:${REMOTE_BASE}/" REMOTE_DST="${HOST}:${REMOTE_BASE}/" LOCAL_SRC="${LOCAL_ROOT}/" LOCAL_DST="${LOCAL_ROOT}/" echo "[info] mode=$MODE host=$HOST port=$PORT" echo "[info] remote_base=$REMOTE_BASE" echo "[info] local_root=$LOCAL_ROOT" [[ "$DRY_RUN" -eq 1 ]] && echo "[info] dry-run enabled" if [[ "$MODE" == "pull" ]]; then # server -> local rsync "${RSYNC_OPTS[@]}" \ -e "${SSH_CMD[*]}" \ --rsync-path="$REMOTE_RSYNC_PATH" \ "$REMOTE_SRC" "$LOCAL_DST" else # local -> server rsync "${RSYNC_OPTS[@]}" \ -e "${SSH_CMD[*]}" \ --rsync-path="$REMOTE_RSYNC_PATH" \ "$LOCAL_SRC" "$REMOTE_DST" fi echo "[ok] done"