fix: replace broken Supervisor API with interactive push-from-HA-terminal migration
This commit is contained in:
+58
-98
@@ -2,31 +2,18 @@
|
|||||||
# =====================================================================
|
# =====================================================================
|
||||||
# Nginx Proxy Manager LXC Setup + Migration from HA Addon
|
# 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.
|
# Run this script on the Proxmox host (HAL-HOST / 10.0.0.240) as root.
|
||||||
#
|
#
|
||||||
# Network:
|
# Network:
|
||||||
# - Proxmox host: 10.0.0.240
|
# - Proxmox host: 10.0.0.240
|
||||||
# - HAOS VM: 10.0.0.55
|
# - HAOS VM: 10.0.0.55
|
||||||
# - OPNsense: 10.0.0.254
|
|
||||||
# - AdGuard LXC: 10.0.0.224 (CT 120)
|
# - AdGuard LXC: 10.0.0.224 (CT 120)
|
||||||
# - Guacamole LXC: 10.0.0.225 (CT 121)
|
# - Guacamole LXC: 10.0.0.225 (CT 121)
|
||||||
# - NPM LXC: 10.0.0.226 (CT 122)
|
# - 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
|
set -euo pipefail
|
||||||
|
|
||||||
# --- Configuration ---
|
|
||||||
CT_ID="122"
|
CT_ID="122"
|
||||||
CT_NAME="npm"
|
CT_NAME="npm"
|
||||||
CT_IP="10.0.0.226/24"
|
CT_IP="10.0.0.226/24"
|
||||||
@@ -38,7 +25,6 @@ CT_SWAP=256
|
|||||||
CT_CORES=2
|
CT_CORES=2
|
||||||
CT_DISK="4"
|
CT_DISK="4"
|
||||||
BRIDGE="vmbr0"
|
BRIDGE="vmbr0"
|
||||||
|
|
||||||
HAOS_IP="10.0.0.55"
|
HAOS_IP="10.0.0.55"
|
||||||
ADDON_SLUG="a0d7b954_nginxproxymanager"
|
ADDON_SLUG="a0d7b954_nginxproxymanager"
|
||||||
|
|
||||||
@@ -48,7 +34,7 @@ echo " Container ID: ${CT_ID}"
|
|||||||
echo " IP Address: ${CT_IP}"
|
echo " IP Address: ${CT_IP}"
|
||||||
echo "============================================"
|
echo "============================================"
|
||||||
|
|
||||||
# --- Check if template exists ---
|
# --- Template ---
|
||||||
if ! pveam list local | grep -q "debian-12-standard"; then
|
if ! pveam list local | grep -q "debian-12-standard"; then
|
||||||
echo "[1/9] Downloading Debian 12 template..."
|
echo "[1/9] Downloading Debian 12 template..."
|
||||||
pveam download local debian-12-standard_12.12-1_amd64.tar.zst
|
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"
|
echo "[1/9] Debian 12 template already available"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Create the container (don't start yet - need AppArmor fix first) ---
|
# --- Create container ---
|
||||||
echo "[2/9] Creating LXC container ${CT_ID}..."
|
echo "[2/9] Creating LXC container ${CT_ID}..."
|
||||||
pct create "${CT_ID}" "${CT_TEMPLATE}" \
|
pct create "${CT_ID}" "${CT_TEMPLATE}" \
|
||||||
--hostname "${CT_NAME}" \
|
--hostname "${CT_NAME}" \
|
||||||
@@ -71,18 +57,17 @@ pct create "${CT_ID}" "${CT_TEMPLATE}" \
|
|||||||
--features "nesting=1,keyctl=1" \
|
--features "nesting=1,keyctl=1" \
|
||||||
--startup "order=2,up=10"
|
--startup "order=2,up=10"
|
||||||
|
|
||||||
# --- Apply AppArmor fix for Docker-in-LXC ---
|
# --- AppArmor fix ---
|
||||||
echo "[3/9] Applying AppArmor fix for Docker compatibility..."
|
echo "[3/9] Applying AppArmor fix for Docker compatibility..."
|
||||||
CT_CONF="/etc/pve/lxc/${CT_ID}.conf"
|
CT_CONF="/etc/pve/lxc/${CT_ID}.conf"
|
||||||
if ! grep -q "lxc.apparmor.profile" "${CT_CONF}" 2>/dev/null; then
|
if ! grep -q "lxc.apparmor.profile" "${CT_CONF}" 2>/dev/null; then
|
||||||
echo "lxc.apparmor.profile: unconfined" >> "${CT_CONF}"
|
echo "lxc.apparmor.profile: unconfined" >> "${CT_CONF}"
|
||||||
fi
|
fi
|
||||||
pct start "${CT_ID}"
|
pct start "${CT_ID}"
|
||||||
|
|
||||||
echo "[4/9] Waiting for container to start..."
|
echo "[4/9] Waiting for container to start..."
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
# --- Install Docker inside the container ---
|
# --- Install Docker ---
|
||||||
echo "[5/9] Installing Docker..."
|
echo "[5/9] Installing Docker..."
|
||||||
pct exec "${CT_ID}" -- bash -c '
|
pct exec "${CT_ID}" -- bash -c '
|
||||||
apt-get update -qq
|
apt-get update -qq
|
||||||
@@ -97,7 +82,7 @@ pct exec "${CT_ID}" -- bash -c '
|
|||||||
systemctl start docker
|
systemctl start docker
|
||||||
'
|
'
|
||||||
|
|
||||||
# --- Create Docker Compose config ---
|
# --- Docker Compose ---
|
||||||
echo "[6/9] Creating NPM Docker Compose configuration..."
|
echo "[6/9] Creating NPM Docker Compose configuration..."
|
||||||
pct exec "${CT_ID}" -- bash -c "
|
pct exec "${CT_ID}" -- bash -c "
|
||||||
mkdir -p /opt/npm/data /opt/npm/letsencrypt
|
mkdir -p /opt/npm/data /opt/npm/letsencrypt
|
||||||
@@ -124,11 +109,13 @@ services:
|
|||||||
DCEOF
|
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
|
MIGRATED=false
|
||||||
|
|
||||||
# --- Approach 1: Try SSH (ports 22222 and 22) ---
|
# --- Try SSH first ---
|
||||||
for PORT in 22222 22; do
|
for PORT in 22222 22; do
|
||||||
if ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no -p ${PORT} \
|
if ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no -p ${PORT} \
|
||||||
root@${HAOS_IP} "test -d /addon_data/${ADDON_SLUG}" 2>/dev/null; then
|
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 \
|
scp -P ${PORT} -r -o StrictHostKeyChecking=no \
|
||||||
root@${HAOS_IP}:/addon_data/${ADDON_SLUG}/ "${TMPDIR}/" 2>/dev/null
|
root@${HAOS_IP}:/addon_data/${ADDON_SLUG}/ "${TMPDIR}/" 2>/dev/null
|
||||||
ADDON_DATA="${TMPDIR}/${ADDON_SLUG}"
|
ADDON_DATA="${TMPDIR}/${ADDON_SLUG}"
|
||||||
|
|
||||||
if [ -d "${ADDON_DATA}" ]; then
|
if [ -d "${ADDON_DATA}" ]; then
|
||||||
DB_SRC=$(find "${ADDON_DATA}" -name "database.sqlite" -type f 2>/dev/null | head -1)
|
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"
|
[ -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)
|
CERT_DIR=$(find "${ADDON_DATA}" -type d -name "letsencrypt" 2>/dev/null | head -1)
|
||||||
if [ -n "${CERT_DIR}" ]; then
|
if [ -n "${CERT_DIR}" ]; then
|
||||||
tar -czf "${TMPDIR}/c.tar.gz" -C "${CERT_DIR}" . 2>/dev/null
|
tar -czf "${TMPDIR}/c.tar.gz" -C "${CERT_DIR}" . 2>/dev/null
|
||||||
@@ -156,99 +141,61 @@ for PORT in 22222 22; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# --- Approach 2: HA Supervisor partial backup (prompt for token) ---
|
# --- If SSH failed, interactive migration from HA terminal ---
|
||||||
if [ "$MIGRATED" = false ]; then
|
if [ "$MIGRATED" = false ]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo " SSH to HAOS failed."
|
echo " SSH to HAOS failed."
|
||||||
echo ""
|
echo ""
|
||||||
echo " To migrate your NPM data automatically, this script can"
|
echo " ┌─────────────────────────────────────────────────┐"
|
||||||
echo " use the Home Assistant API to create a partial backup."
|
echo " │ To migrate your data, run this in the HA │"
|
||||||
echo ""
|
echo " │ Terminal & SSH addon (or HA console): │"
|
||||||
echo " You need a Long-Lived Access Token from HA:"
|
echo " │ │"
|
||||||
echo " Profile > Security > Long-lived access tokens > Create"
|
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 ""
|
echo ""
|
||||||
|
|
||||||
if [ -n "${HA_TOKEN:-}" ]; then
|
read -r -p " Press Enter once you've copied the file (or type 'skip'): " RESPONSE
|
||||||
echo " Using HA_TOKEN from environment."
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
else
|
||||||
read -r -p " Paste your HA token (or press Enter to skip): " HA_TOKEN
|
echo " WARNING: database.sqlite not found in archive"
|
||||||
|
echo " Archive contents:"
|
||||||
|
find "${TMPDIR}" -maxdepth 3 -type f | head -20
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "${HA_TOKEN:-}" ]; then
|
CERT_DIR=$(find "${TMPDIR}" -type d -name "letsencrypt" 2>/dev/null | head -1)
|
||||||
HA_URL="http://${HAOS_IP}:8123"
|
|
||||||
TMPDIR=$(mktemp -d)
|
|
||||||
|
|
||||||
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
|
if [ -n "${CERT_DIR}" ]; then
|
||||||
tar -czf "${TMPDIR}/c.tar.gz" -C "${CERT_DIR}" . 2>/dev/null
|
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 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'
|
pct exec "${CT_ID}" -- bash -c 'tar xzf /tmp/c.tar.gz -C /opt/npm/letsencrypt/ && rm /tmp/c.tar.gz'
|
||||||
echo " Certs migrated"
|
echo " Certs migrated"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
MIGRATED=true
|
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
|
|
||||||
else
|
|
||||||
echo " Backup creation failed (check token permissions)"
|
|
||||||
fi
|
|
||||||
rm -rf "${TMPDIR}"
|
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
|
else
|
||||||
echo " Skipping API migration."
|
echo " Skipping migration."
|
||||||
fi
|
fi
|
||||||
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} <path>/database.sqlite /opt/npm/data/database.sqlite"
|
|
||||||
echo " pct exec ${CT_ID} -- bash -c 'cd /opt/npm && docker compose up -d'"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Start NPM ---
|
# --- Start NPM ---
|
||||||
echo "[8/9] Starting Nginx Proxy Manager..."
|
echo "[8/9] Starting Nginx Proxy Manager..."
|
||||||
pct exec "${CT_ID}" -- bash -c '
|
pct exec "${CT_ID}" -- bash -c '
|
||||||
@@ -259,7 +206,7 @@ pct exec "${CT_ID}" -- bash -c '
|
|||||||
docker compose ps
|
docker compose ps
|
||||||
'
|
'
|
||||||
|
|
||||||
# --- Create systemd service ---
|
# --- Systemd service ---
|
||||||
echo "[9/9] Creating systemd service for auto-start..."
|
echo "[9/9] Creating systemd service for auto-start..."
|
||||||
pct exec "${CT_ID}" -- bash -c '
|
pct exec "${CT_ID}" -- bash -c '
|
||||||
cat > /etc/systemd/system/npm.service << "SVCEOF"
|
cat > /etc/systemd/system/npm.service << "SVCEOF"
|
||||||
@@ -303,6 +250,19 @@ else
|
|||||||
echo " Email: admin@example.com"
|
echo " Email: admin@example.com"
|
||||||
echo " Password: changeme"
|
echo " Password: changeme"
|
||||||
echo " >>> CHANGE THIS IMMEDIATELY <<<"
|
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
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
echo " NEXT STEPS:"
|
echo " NEXT STEPS:"
|
||||||
|
|||||||
Reference in New Issue
Block a user