diff --git a/setup-npm-lxc.sh b/setup-npm-lxc.sh new file mode 100644 index 0000000..95bc4ff --- /dev/null +++ b/setup-npm-lxc.sh @@ -0,0 +1,324 @@ +#!/bin/bash +# ===================================================================== +# 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" +CT_GW="10.0.0.254" +CT_STORAGE="local-lvm" +CT_TEMPLATE="local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst" +CT_MEMORY=512 +CT_SWAP=256 +CT_CORES=2 +CT_DISK="4" +BRIDGE="vmbr0" + +HAOS_IP="10.0.0.55" +ADDON_SLUG="a0d7b954_nginxproxymanager" +NPM_DATA="/opt/npm/data" + +echo "============================================" +echo " Nginx Proxy Manager LXC Setup + Migration" +echo " Container ID: ${CT_ID}" +echo " IP Address: ${CT_IP}" +echo "============================================" + +# --- Check if template exists --- +if ! pveam list local | grep -q "debian-12-standard"; then + echo "[1/9] Downloading Debian 12 template..." + pveam download local debian-12-standard_12.7-1_amd64.tar.zst +else + echo "[1/9] Debian 12 template already available" +fi + +# --- Create the container --- +echo "[2/9] Creating LXC container ${CT_ID}..." +pct create "${CT_ID}" "${CT_TEMPLATE}" \ + --hostname "${CT_NAME}" \ + --memory "${CT_MEMORY}" \ + --swap "${CT_SWAP}" \ + --cores "${CT_CORES}" \ + --rootfs "${CT_STORAGE}:${CT_DISK}" \ + --net0 "name=eth0,bridge=${BRIDGE},ip=${CT_IP},gw=${CT_GW},firewall=0" \ + --nameserver "10.0.0.224" \ + --onboot 1 \ + --start 1 \ + --unprivileged 1 \ + --features "nesting=1,keyctl=1" \ + --startup "order=2,up=10" + +echo "[3/9] Waiting for container to start..." +sleep 5 + +# --- Install Docker inside the container --- +echo "[4/9] Installing Docker..." +pct exec "${CT_ID}" -- bash -c ' + apt-get update -qq + apt-get install -y -qq ca-certificates curl gnupg + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg + chmod a+r /etc/apt/keyrings/docker.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list + apt-get update -qq + apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-compose-plugin + systemctl enable docker + systemctl start docker +' + +# --- Create Docker Compose config --- +echo "[5/9] Creating NPM Docker Compose configuration..." +pct exec "${CT_ID}" -- bash -c " + mkdir -p /opt/npm/data /opt/npm/letsencrypt + cat > /opt/npm/docker-compose.yml << 'DCEOF' +services: + npm: + image: jc21/nginx-proxy-manager:latest + container_name: npm + restart: unless-stopped + ports: + - '80:80' + - '443:443' + - '81:81' + volumes: + - /opt/npm/data:/data + - /opt/npm/letsencrypt:/etc/letsencrypt + environment: + TZ: Australia/Melbourne + DB_SQLITE_FILE: /data/database.sqlite + healthcheck: + test: ['CMD', '/usr/bin/check-health'] + interval: 10s + timeout: 3s +DCEOF +" + +# --- Attempt data migration from HA addon --- +echo "[6/9] Attempting data migration from HA addon..." +MIGRATED=false + +if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@${HAOS_IP} "test -d /addon_data/${ADDON_SLUG}" 2>/dev/null; then + echo " Found NPM addon data. Copying..." + TMPDIR=$(mktemp -d) + + # Copy entire addon data directory from HAOS + scp -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 + echo " Addon data downloaded to ${TMPDIR}" + + # --- Migrate SQLite database --- + # HA addon NPM may store the DB in various locations + DB_SRC="" + for candidate in \ + "${ADDON_DATA}/database.sqlite" \ + "${ADDON_DATA}/data/database.sqlite" \ + "${ADDON_DATA}/nginx/database.sqlite"; do + if [ -f "$candidate" ]; then + DB_SRC="$candidate" + break + fi + done + + if [ -n "${DB_SRC}" ]; then + echo " Found database: ${DB_SRC}" + pct push "${CT_ID}" "${DB_SRC}" /opt/npm/data/database.sqlite + echo " Database migrated (proxy hosts, users, settings)" + else + echo " WARNING: database.sqlite not found in addon data" + # List what we did find for debugging + echo " Contents of addon data:" + find "${ADDON_DATA}" -maxdepth 3 -type f | head -30 + fi + + # --- Migrate Let's Encrypt certificates --- + CERTS_SRC="" + for candidate in \ + "${ADDON_DATA}/letsencrypt" \ + "${ADDON_DATA}/ssl" \ + "${ADDON_DATA}/data/letsencrypt"; do + if [ -d "$candidate" ]; then + CERTS_SRC="$candidate" + break + fi + done + + if [ -n "${CERTS_SRC}" ]; then + echo " Found certificates: ${CERTS_SRC}" + # Tar up certs, push to LXC, extract + tar -czf "${TMPDIR}/certs.tar.gz" -C "${CERTS_SRC}" . 2>/dev/null + pct push "${CT_ID}" "${TMPDIR}/certs.tar.gz" /tmp/certs.tar.gz + pct exec "${CT_ID}" -- bash -c ' + mkdir -p /opt/npm/letsencrypt + tar -xzf /tmp/certs.tar.gz -C /opt/npm/letsencrypt/ + rm /tmp/certs.tar.gz + ' + CERT_COUNT=$(find "${CERTS_SRC}" -name "*.pem" -o -name "*.crt" 2>/dev/null | wc -l) + echo " Certificates migrated (${CERT_COUNT} cert files)" + else + echo " No certificate directory found (will need re-issue)" + fi + + # --- Migrate custom Nginx configs --- + for custom_dir in \ + "${ADDON_DATA}/nginx/custom" \ + "${ADDON_DATA}/data/nginx/custom"; do + if [ -d "$custom_dir" ] && [ "$(ls -A "$custom_dir" 2>/dev/null)" ]; then + echo " Found custom Nginx configs: ${custom_dir}" + tar -czf "${TMPDIR}/custom.tar.gz" -C "${custom_dir}" . 2>/dev/null + pct push "${CT_ID}" "${TMPDIR}/custom.tar.gz" /tmp/custom.tar.gz + pct exec "${CT_ID}" -- bash -c ' + mkdir -p /opt/npm/data/nginx/custom + tar -xzf /tmp/custom.tar.gz -C /opt/npm/data/nginx/custom/ + rm /tmp/custom.tar.gz + ' + echo " Custom configs migrated" + break + fi + done + + MIGRATED=true + fi + + rm -rf "${TMPDIR}" +else + echo " Could not SSH to HAOS at ${HAOS_IP}." + echo " Make sure Terminal & SSH addon is installed." + echo "" + echo " MANUAL MIGRATION:" + echo " From HAOS SSH terminal, run:" + 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 (10.0.0.240):" + echo " pct push ${CT_ID} /tmp/npm-backup.tar.gz /tmp/npm-backup.tar.gz" + echo " pct exec ${CT_ID} -- bash -c '" + echo " tar -xzf /tmp/npm-backup.tar.gz -C /opt/npm/data/" + echo " rm /tmp/npm-backup.tar.gz'" +fi + +# --- Start NPM --- +echo "[7/9] Starting Nginx Proxy Manager..." +pct exec "${CT_ID}" -- bash -c ' + cd /opt/npm + docker compose up -d + echo "Waiting for NPM to initialise..." + sleep 15 + docker compose ps +' + +# --- Create systemd service --- +echo "[8/9] Creating systemd service for auto-start..." +pct exec "${CT_ID}" -- bash -c ' + cat > /etc/systemd/system/npm.service << "SVCEOF" +[Unit] +Description=Nginx Proxy Manager Docker +Requires=docker.service +After=docker.service + +[Service] +Type=oneshot +RemainAfterExit=yes +WorkingDirectory=/opt/npm +ExecStart=/usr/bin/docker compose up -d +ExecStop=/usr/bin/docker compose down +TimeoutStartSec=120 + +[Install] +WantedBy=multi-user.target +SVCEOF + + systemctl daemon-reload + systemctl enable npm.service +' + +# --- Verify --- +echo "[9/9] Verifying NPM is accessible..." +CT_IP_CLEAN=$(echo "${CT_IP}" | cut -d'/' -f1) +sleep 5 +HTTP_CODE=$(pct exec "${CT_ID}" -- curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:81/ 2>/dev/null || echo "000") +if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ]; then + echo " NPM admin panel responding (HTTP ${HTTP_CODE})" +else + echo " NPM may still be starting up (HTTP ${HTTP_CODE})" + echo " Give it another minute, then check http://${CT_IP_CLEAN}:81" +fi + +echo "" +echo "============================================" +echo " Nginx Proxy Manager LXC setup complete!" +echo "============================================" +echo "" +echo " Admin UI: http://${CT_IP_CLEAN}:81" +echo " HTTP: ${CT_IP_CLEAN}:80" +echo " HTTPS: ${CT_IP_CLEAN}:443" +echo "" +if [ "$MIGRATED" = true ]; then + echo " Data was migrated from HA addon!" + echo " Your proxy hosts and SSL certs should be intact." + echo "" + echo " Default login (if DB migration succeeded):" + echo " Use your existing NPM credentials." + echo "" + echo " If login fails (schema mismatch), use defaults:" + echo " Email: admin@example.com" + echo " Password: changeme" +else + echo " Default login (fresh install):" + echo " Email: admin@example.com" + echo " Password: changeme" + echo " >>> CHANGE THIS IMMEDIATELY <<<" +fi +echo "" +echo " CRITICAL NEXT STEPS:" +echo "" +echo " 1. Verify all proxy hosts work at http://${CT_IP_CLEAN}:81" +echo "" +echo " 2. Update OPNsense port forwards:" +echo " Firewall > NAT > Port Forward" +echo " Change destination for ports 80/443:" +echo " OLD: 10.0.0.55 (HAOS)" +echo " NEW: ${CT_IP_CLEAN} (NPM LXC)" +echo "" +echo " 3. Update any DNS records pointing to the old IP" +echo " (all *.hideawaygaming.com.au should resolve" +echo " to your WAN IP, which OPNsense forwards)" +echo "" +echo " 4. If certs didn't migrate, re-request them:" +echo " NPM Admin > SSL Certificates > Add" +echo " Use DNS challenge or HTTP challenge" +echo "" +echo " 5. After confirming everything works:" +echo " Stop HA NPM add-on" +echo "" +echo " Docker management:" +echo " pct exec ${CT_ID} -- docker compose -f /opt/npm/docker-compose.yml logs -f" +echo " pct exec ${CT_ID} -- docker compose -f /opt/npm/docker-compose.yml restart" +echo "============================================"