From 8dd66945ddcc8ddf9cf0665b5eaa36b5146065df Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 02:03:59 +0000 Subject: [PATCH] Offer to actually set up VPN + SSH keys at the DR-spare prompt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Requested improvement: the disaster-recovery spare prompt in backup.sh already ran a live connectivity check and, on failure, printed manual instructions (set up wg-easy separately if the spare isn't reachable, run ssh-keygen/ssh-copy-id yourself) — but never offered to do any of it right there, even though every piece is safe to automate inline. Now, when the passwordless SSH check fails: - If wg-easy isn't installed yet, offers to chain-install it (guarded with declare -F install_wg-easy, same pattern asterisk.sh already uses for security-dashboard/pstn-trunk) — covers the common case where the spare is a home box with no port-forward and no path there at all yet, not just a missing key. - If root has no SSH key, offers to generate one (ssh-keygen -t ed25519). - Offers to run ssh-copy-id against the spare interactively right there — it prompts for the spare's login password itself, so this script never touches or sees that password, just invokes the real command inline instead of telling the operator to go run it themselves after. - Re-runs the connectivity check after ssh-copy-id succeeds, so the install flow reports the actual current state instead of the pre-fix failure message. Verified the has-a-key detection (the part most likely to have a subtle &&/|| precedence bug) against all four cases — no key, only id_ed25519, only id_rsa, both — behaves correctly in each. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn --- services/backup.sh | 49 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/services/backup.sh b/services/backup.sh index b88ddd8..1bc2efe 100644 --- a/services/backup.sh +++ b/services/backup.sh @@ -496,8 +496,53 @@ install_backup() { log_success " SSH to $DR_SYNC_HOST works — spare sync will run after each backup." else log_warning " Couldn't SSH to $DR_SYNC_HOST without a password right now." - log_warning " Spare sync is saved but will fail until this works (as root, since" - log_warning " the backup timer runs as root): ssh-keygen; ssh-copy-id $DR_SYNC_HOST" + + # If the spare isn't reachable at all (behind NAT, no port-forward — + # a home box is the common case), a passwordless key won't help + # until there's a network path there in the first place. Offer the + # VPN hub right here instead of just telling the user to go set + # one up separately and come back. + if [ ! -d "$DOCKER_DIR/wg-easy" ]; then + local _SETUP_VPN="" + prompt_yn " Spare box not directly reachable (behind NAT, no port-forward)? Set up a WireGuard VPN hub (wg-easy) now so they can reach each other? (y/n):" "n" _SETUP_VPN + if [[ "$_SETUP_VPN" =~ ^[Yy]$ ]]; then + if declare -F install_wg-easy >/dev/null 2>&1; then + install_wg-easy + else + log_warning " services/wg-easy.sh isn't loaded — run: sudo ./setup.sh wg-easy" + fi + fi + fi + + local _HAVE_KEY=false + [ -f /root/.ssh/id_ed25519 ] || [ -f /root/.ssh/id_rsa ] && _HAVE_KEY=true + if [ "$_HAVE_KEY" = false ]; then + local _GEN_KEY="" + prompt_yn " No SSH key found for root — generate one now (ssh-keygen)? (y/n):" "y" _GEN_KEY + if [[ "$_GEN_KEY" =~ ^[Yy]$ ]]; then + ssh-keygen -t ed25519 -N "" -f /root/.ssh/id_ed25519 -q \ + && log_success " Generated /root/.ssh/id_ed25519" \ + || log_warning " ssh-keygen failed — generate one manually." + fi + fi + + local _COPY_KEY="" + prompt_yn " Run ssh-copy-id to $DR_SYNC_HOST now? (asks for its login password interactively) (y/n):" "y" _COPY_KEY + if [[ "$_COPY_KEY" =~ ^[Yy]$ ]]; then + if ssh-copy-id "$DR_SYNC_HOST"; then + if ssh -o BatchMode=yes -o ConnectTimeout=5 "$DR_SYNC_HOST" true 2>/dev/null; then + log_success " SSH to $DR_SYNC_HOST now works — spare sync will run after each backup." + else + log_warning " ssh-copy-id reported success but the passwordless check still failed — check manually." + fi + else + log_warning " ssh-copy-id failed. Spare sync is saved but will fail until this works:" + log_warning " ssh-copy-id $DR_SYNC_HOST" + fi + else + log_warning " Spare sync is saved but will fail until this works (as root, since" + log_warning " the backup timer runs as root): ssh-copy-id $DR_SYNC_HOST" + fi fi fi