diff --git a/setup-npm-lxc.sh b/setup-npm-lxc.sh index 674b200..8dbc8ba 100644 --- a/setup-npm-lxc.sh +++ b/setup-npm-lxc.sh @@ -2,31 +2,18 @@ # ===================================================================== # Nginx Proxy Manager LXC Setup + Migration from HA Addon # ===================================================================== -# Migrates NPM from a Home Assistant add-on to a dedicated LXC -# container on Proxmox. Copies the SQLite database (all proxy hosts, -# users, settings) and Let's Encrypt certificates so you don't have -# to re-create anything. -# # Run this script on the Proxmox host (HAL-HOST / 10.0.0.240) as root. # # Network: # - Proxmox host: 10.0.0.240 # - HAOS VM: 10.0.0.55 -# - OPNsense: 10.0.0.254 # - AdGuard LXC: 10.0.0.224 (CT 120) # - Guacamole LXC: 10.0.0.225 (CT 121) # - NPM LXC: 10.0.0.226 (CT 122) -# -# HA Addon slug: a0d7b954_nginxproxymanager -# Addon data path on HAOS: /addon_data/a0d7b954_nginxproxymanager/ -# -# IMPORTANT: After migration, update your OPNsense port forwards -# (80/443) to point to 10.0.0.226 instead of 10.0.0.55. # ===================================================================== set -euo pipefail -# --- Configuration --- CT_ID="122" CT_NAME="npm" CT_IP="10.0.0.226/24" @@ -38,7 +25,6 @@ CT_SWAP=256 CT_CORES=2 CT_DISK="4" BRIDGE="vmbr0" - HAOS_IP="10.0.0.55" ADDON_SLUG="a0d7b954_nginxproxymanager" @@ -48,7 +34,7 @@ echo " Container ID: ${CT_ID}" echo " IP Address: ${CT_IP}" echo "============================================" -# --- Check if template exists --- +# --- Template --- if ! pveam list local | grep -q "debian-12-standard"; then echo "[1/9] Downloading Debian 12 template..." pveam download local debian-12-standard_12.12-1_amd64.tar.zst @@ -56,7 +42,7 @@ else echo "[1/9] Debian 12 template already available" fi -# --- Create the container (don't start yet - need AppArmor fix first) --- +# --- Create container --- echo "[2/9] Creating LXC container ${CT_ID}..." pct create "${CT_ID}" "${CT_TEMPLATE}" \ --hostname "${CT_NAME}" \ @@ -71,18 +57,17 @@ pct create "${CT_ID}" "${CT_TEMPLATE}" \ --features "nesting=1,keyctl=1" \ --startup "order=2,up=10" -# --- Apply AppArmor fix for Docker-in-LXC --- +# --- AppArmor fix --- echo "[3/9] Applying AppArmor fix for Docker compatibility..." CT_CONF="/etc/pve/lxc/${CT_ID}.conf" if ! grep -q "lxc.apparmor.profile" "${CT_CONF}" 2>/dev/null; then echo "lxc.apparmor.profile: unconfined" >> "${CT_CONF}" fi pct start "${CT_ID}" - echo "[4/9] Waiting for container to start..." sleep 5 -# --- Install Docker inside the container --- +# --- Install Docker --- echo "[5/9] Installing Docker..." pct exec "${CT_ID}" -- bash -c ' apt-get update -qq @@ -97,7 +82,7 @@ pct exec "${CT_ID}" -- bash -c ' systemctl start docker ' -# --- Create Docker Compose config --- +# --- Docker Compose --- echo "[6/9] Creating NPM Docker Compose configuration..." pct exec "${CT_ID}" -- bash -c " mkdir -p /opt/npm/data /opt/npm/letsencrypt @@ -124,11 +109,13 @@ services: DCEOF " -# --- Attempt data migration from HA addon --- -echo "[7/9] Attempting data migration from HA addon..." +# ================================================================= +# DATA MIGRATION +# ================================================================= +echo "[7/9] Data migration from HA addon..." MIGRATED=false -# --- Approach 1: Try SSH (ports 22222 and 22) --- +# --- Try SSH first --- for PORT in 22222 22; do if ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no -p ${PORT} \ root@${HAOS_IP} "test -d /addon_data/${ADDON_SLUG}" 2>/dev/null; then @@ -137,11 +124,9 @@ for PORT in 22222 22; do scp -P ${PORT} -r -o StrictHostKeyChecking=no \ root@${HAOS_IP}:/addon_data/${ADDON_SLUG}/ "${TMPDIR}/" 2>/dev/null ADDON_DATA="${TMPDIR}/${ADDON_SLUG}" - if [ -d "${ADDON_DATA}" ]; then DB_SRC=$(find "${ADDON_DATA}" -name "database.sqlite" -type f 2>/dev/null | head -1) [ -n "${DB_SRC}" ] && pct push "${CT_ID}" "${DB_SRC}" /opt/npm/data/database.sqlite && echo " DB migrated" - CERT_DIR=$(find "${ADDON_DATA}" -type d -name "letsencrypt" 2>/dev/null | head -1) if [ -n "${CERT_DIR}" ]; then tar -czf "${TMPDIR}/c.tar.gz" -C "${CERT_DIR}" . 2>/dev/null @@ -156,97 +141,59 @@ for PORT in 22222 22; do fi done -# --- Approach 2: HA Supervisor partial backup (prompt for token) --- +# --- If SSH failed, interactive migration from HA terminal --- if [ "$MIGRATED" = false ]; then echo "" echo " SSH to HAOS failed." echo "" - echo " To migrate your NPM data automatically, this script can" - echo " use the Home Assistant API to create a partial backup." - echo "" - echo " You need a Long-Lived Access Token from HA:" - echo " Profile > Security > Long-lived access tokens > Create" + echo " ┌─────────────────────────────────────────────────┐" + echo " │ To migrate your data, run this in the HA │" + echo " │ Terminal & SSH addon (or HA console): │" + echo " │ │" + echo " │ cd /addon_data/${ADDON_SLUG}" + echo " │ tar czf /tmp/npm-backup.tar.gz . │" + echo " │ scp /tmp/npm-backup.tar.gz \\ │" + echo " │ root@10.0.0.240:/tmp/npm-backup.tar.gz │" + echo " │ │" + echo " │ (Accept the host key if prompted, enter the │" + echo " │ Proxmox root password when asked) │" + echo " └─────────────────────────────────────────────────┘" echo "" - if [ -n "${HA_TOKEN:-}" ]; then - echo " Using HA_TOKEN from environment." - else - read -r -p " Paste your HA token (or press Enter to skip): " HA_TOKEN - fi + read -r -p " Press Enter once you've copied the file (or type 'skip'): " RESPONSE - if [ -n "${HA_TOKEN:-}" ]; then - HA_URL="http://${HAOS_IP}:8123" + if [ "${RESPONSE}" != "skip" ] && [ -f "/tmp/npm-backup.tar.gz" ]; then + echo " Found /tmp/npm-backup.tar.gz, extracting..." TMPDIR=$(mktemp -d) + tar xzf /tmp/npm-backup.tar.gz -C "${TMPDIR}/" 2>/dev/null || true - echo " Creating partial backup of NPM addon..." - BACKUP_SLUG=$(curl -s -X POST \ - -H "Authorization: Bearer ${HA_TOKEN}" \ - -H "Content-Type: application/json" \ - -d "{\"name\":\"npm-migration\",\"addons\":[\"${ADDON_SLUG}\"],\"folders\":[]}" \ - "${HA_URL}/api/hassio/backups/new/partial" 2>/dev/null \ - | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('slug',''))" 2>/dev/null) - - if [ -n "${BACKUP_SLUG}" ]; then - echo " Backup created (${BACKUP_SLUG}), downloading..." - curl -s -o "${TMPDIR}/backup.tar" \ - -H "Authorization: Bearer ${HA_TOKEN}" \ - "${HA_URL}/api/hassio/backups/${BACKUP_SLUG}/download" 2>/dev/null - - if [ -s "${TMPDIR}/backup.tar" ]; then - cd "${TMPDIR}" && tar xf backup.tar 2>/dev/null || true - ADDON_TAR=$(find "${TMPDIR}" -name "*nginxproxymanager*" -name "*.tar.gz" 2>/dev/null | head -1) - if [ -n "${ADDON_TAR}" ]; then - mkdir -p "${TMPDIR}/npm_data" - tar xzf "${ADDON_TAR}" -C "${TMPDIR}/npm_data/" 2>/dev/null || true - - DB_SRC=$(find "${TMPDIR}/npm_data" -name "database.sqlite" -type f 2>/dev/null | head -1) - [ -n "${DB_SRC}" ] && pct push "${CT_ID}" "${DB_SRC}" /opt/npm/data/database.sqlite && echo " DB migrated" - - CERT_DIR=$(find "${TMPDIR}/npm_data" -type d -name "letsencrypt" 2>/dev/null | head -1) - if [ -n "${CERT_DIR}" ]; then - tar -czf "${TMPDIR}/c.tar.gz" -C "${CERT_DIR}" . 2>/dev/null - pct push "${CT_ID}" "${TMPDIR}/c.tar.gz" /tmp/c.tar.gz - pct exec "${CT_ID}" -- bash -c 'tar xzf /tmp/c.tar.gz -C /opt/npm/letsencrypt/ && rm /tmp/c.tar.gz' - echo " Certs migrated" - fi - MIGRATED=true - else - echo " Could not find addon data in backup" - fi - else - echo " Backup download failed" - fi - - # Clean up the backup from HA - curl -s -X DELETE -H "Authorization: Bearer ${HA_TOKEN}" \ - "${HA_URL}/api/hassio/backups/${BACKUP_SLUG}" 2>/dev/null || true + DB_SRC=$(find "${TMPDIR}" -name "database.sqlite" -type f 2>/dev/null | head -1) + if [ -n "${DB_SRC}" ]; then + pct push "${CT_ID}" "${DB_SRC}" /opt/npm/data/database.sqlite + echo " DB migrated" else - echo " Backup creation failed (check token permissions)" + echo " WARNING: database.sqlite not found in archive" + echo " Archive contents:" + find "${TMPDIR}" -maxdepth 3 -type f | head -20 fi - rm -rf "${TMPDIR}" - else - echo " Skipping API migration." - fi -fi -if [ "$MIGRATED" = false ]; then - echo "" - echo " =========================================" - echo " DATA MIGRATION SKIPPED" - echo " =========================================" - echo " NPM will start fresh. To migrate later:" - echo " 1. HA > Settings > Backups > Create > Partial" - echo " Select ONLY 'Nginx Proxy Manager'" - echo " 2. Download the .tar backup" - echo " 3. Copy to Proxmox: scp backup.tar root@10.0.0.240:/tmp/" - echo " 4. Extract:" - echo " cd /tmp && tar xf *.tar" - echo " tar xzf *nginxproxymanager*.tar.gz -C /tmp/npm_extract/" - echo " find /tmp/npm_extract -name database.sqlite" - echo " 5. Push to NPM LXC:" - echo " pct exec ${CT_ID} -- bash -c 'cd /opt/npm && docker compose down'" - echo " pct push ${CT_ID} /database.sqlite /opt/npm/data/database.sqlite" - echo " pct exec ${CT_ID} -- bash -c 'cd /opt/npm && docker compose up -d'" + CERT_DIR=$(find "${TMPDIR}" -type d -name "letsencrypt" 2>/dev/null | head -1) + if [ -n "${CERT_DIR}" ]; then + tar -czf "${TMPDIR}/c.tar.gz" -C "${CERT_DIR}" . 2>/dev/null + pct push "${CT_ID}" "${TMPDIR}/c.tar.gz" /tmp/c.tar.gz + pct exec "${CT_ID}" -- bash -c 'tar xzf /tmp/c.tar.gz -C /opt/npm/letsencrypt/ && rm /tmp/c.tar.gz' + echo " Certs migrated" + fi + + MIGRATED=true + rm -rf "${TMPDIR}" + rm -f /tmp/npm-backup.tar.gz + elif [ "${RESPONSE}" != "skip" ]; then + echo " File not found at /tmp/npm-backup.tar.gz" + echo " You can migrate later — see instructions below." + else + echo " Skipping migration." + fi fi # --- Start NPM --- @@ -259,7 +206,7 @@ pct exec "${CT_ID}" -- bash -c ' docker compose ps ' -# --- Create systemd service --- +# --- Systemd service --- echo "[9/9] Creating systemd service for auto-start..." pct exec "${CT_ID}" -- bash -c ' cat > /etc/systemd/system/npm.service << "SVCEOF" @@ -303,6 +250,19 @@ else echo " Email: admin@example.com" echo " Password: changeme" echo " >>> CHANGE THIS IMMEDIATELY <<<" + echo "" + echo " TO MIGRATE DATA LATER:" + echo " From HA Terminal & SSH addon:" + echo " cd /addon_data/${ADDON_SLUG}" + echo " tar czf /tmp/npm-backup.tar.gz ." + echo " scp /tmp/npm-backup.tar.gz root@10.0.0.240:/tmp/" + echo "" + echo " Then on Proxmox:" + echo " pct exec ${CT_ID} -- bash -c 'cd /opt/npm && docker compose down'" + echo " mkdir /tmp/npm_ex && tar xzf /tmp/npm-backup.tar.gz -C /tmp/npm_ex/" + echo " DB=\$(find /tmp/npm_ex -name database.sqlite | head -1)" + echo " pct push ${CT_ID} \$DB /opt/npm/data/database.sqlite" + echo " pct exec ${CT_ID} -- bash -c 'cd /opt/npm && docker compose up -d'" fi echo "" echo " NEXT STEPS:"