#!/bin/bash set -euo pipefail # Migrate from Nginx Proxy Manager to NPMplus # This script backs up current NPM, installs NPMplus, and migrates all configurations set -e PROXMOX_HOST="192.168.11.11" OLD_CONTAINER_ID="105" BACKUP_DIR="/tmp/npm-migration-$(date +%Y%m%d_%H%M%S)" ACME_EMAIL="nsatoshi2007@hotmail.com" TZ="America/New_York" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "🔄 NPM to NPMplus Migration" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" # Step 1: Backup current NPM echo "📦 Step 1: Backing up current NPM configuration..." mkdir -p "$BACKUP_DIR" echo " 📋 Exporting proxy hosts..." ssh root@"$PROXMOX_HOST" "pct exec $OLD_CONTAINER_ID -- bash -c ' cd /app if [ -f /data/database.sqlite ]; then sqlite3 /data/database.sqlite \".dump\" > /tmp/npm-database.sql 2>/dev/null || echo \"Database export may have issues\" echo \"Database exported\" else echo \"Database not found\" fi '" > "$BACKUP_DIR/backup.log" 2>&1 # Copy database backup ssh root@"$PROXMOX_HOST" "pct exec $OLD_CONTAINER_ID -- cat /tmp/npm-database.sql" > "$BACKUP_DIR/database.sql" 2>&1 || echo "Database backup may have failed" echo " ✅ Backup complete: $BACKUP_DIR" echo "" # Step 2: Install NPMplus echo "📦 Step 2: Installing NPMplus..." echo " ℹ️ This will create a new container and install NPMplus via Docker Compose" echo " ℹ️ Default: Alpine 3.22, 1 vCPU, 512 MB RAM, 3 GB disk" echo "" read -p " Continue with NPMplus installation? (y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "❌ Migration cancelled" exit 1 fi echo " 🚀 Installing NPMplus..." ssh root@"$PROXMOX_HOST" "bash -c \" bash <(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/npmplus.sh) \"" || { echo " ❌ Installation failed. Check the output above." exit 1 } # Get the new container ID echo "" echo " 📋 Please enter the new NPMplus container ID (VMID):" read -p " Container ID: " NEW_CONTAINER_ID if [ -z "$NEW_CONTAINER_ID" ]; then echo " ❌ Container ID is required" exit 1 fi # Wait for NPMplus to be ready echo "" echo " ⏳ Waiting for NPMplus to be ready (this may take 1-2 minutes)..." for i in {1..60}; do if ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- docker ps --filter 'name=npmplus' --format '{{.Status}}' 2>/dev/null" | grep -q "Up"; then echo " ✅ NPMplus is running" break fi echo " ⏳ Waiting... ($i/60)" sleep 2 done # Get the admin password echo "" echo " 🔑 Retrieving admin password..." ADMIN_PASSWORD=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- bash -c ' if [ -f /opt/.npm_pwd ]; then cat /opt/.npm_pwd else docker logs npmplus 2>/dev/null | grep -i \"Creating a new user\" | tail -1 | grep -oP \"password: \K[^\s]+\" || echo \"\" fi '") if [ -z "$ADMIN_PASSWORD" ]; then echo " ⚠️ Could not retrieve password automatically" echo " 📋 Check manually: ssh root@$PROXMOX_HOST \"pct exec $NEW_CONTAINER_ID -- docker logs npmplus | grep -i password\"" echo "" read -p " Enter admin password manually: " ADMIN_PASSWORD fi # Get container IP CONTAINER_IP=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- hostname -I | awk '{print \$1}'") echo " ✅ NPMplus container IP: $CONTAINER_IP" echo " ✅ Admin password: $ADMIN_PASSWORD" echo " 🌐 Access URL: https://$CONTAINER_IP:81" echo "" # Step 3: Export current configurations echo "📦 Step 3: Exporting current NPM configurations..." EXPORT_SCRIPT="/tmp/export-npm-configs.sh" cat > "$EXPORT_SCRIPT" << 'EXPORT_EOF' #!/bin/bash # Export NPM configurations via API NPM_URL="http://127.0.0.1:81" EMAIL="nsatoshi2007@hotmail.com" PASSWORD='L@ker$2010' # Authenticate TOKEN_RESPONSE=$(curl -s -X POST "$NPM_URL/api/tokens" \ -H "Content-Type: application/json" \ -d "{\"identity\":\"$EMAIL\",\"secret\":\"$PASSWORD\"}") TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || echo "") if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then echo "❌ Authentication failed" exit 1 fi # Export proxy hosts echo "Exporting proxy hosts..." curl -s -X GET "$NPM_URL/api/nginx/proxy-hosts" \ -H "Authorization: Bearer $TOKEN" | jq '.' > /tmp/npm-proxy-hosts.json # Export certificates echo "Exporting certificates..." curl -s -X GET "$NPM_URL/api/nginx/certificates" \ -H "Authorization: Bearer $TOKEN" | jq '.' > /tmp/npm-certificates.json echo "✅ Export complete" EXPORT_EOF chmod +x "$EXPORT_SCRIPT" scp "$EXPORT_SCRIPT" root@"$PROXMOX_HOST":/tmp/ ssh root@"$PROXMOX_HOST" "pct exec $OLD_CONTAINER_ID -- bash < /tmp/export-npm-configs.sh" || { echo " ⚠️ Export via API failed, will use manual configuration" } # Copy exported files ssh root@"$PROXMOX_HOST" "pct exec $OLD_CONTAINER_ID -- cat /tmp/npm-proxy-hosts.json" > "$BACKUP_DIR/proxy-hosts.json" 2>/dev/null || echo "{}" > "$BACKUP_DIR/proxy-hosts.json" ssh root@"$PROXMOX_HOST" "pct exec $OLD_CONTAINER_ID -- cat /tmp/npm-certificates.json" > "$BACKUP_DIR/certificates.json" 2>/dev/null || echo "[]" > "$BACKUP_DIR/certificates.json" echo " ✅ Configurations exported to $BACKUP_DIR" echo "" # Step 4: Import to NPMplus echo "📦 Step 4: Importing configurations to NPMplus..." echo " ℹ️ This will configure all 19 domains in NPMplus" echo "" # Create migration script for NPMplus MIGRATE_SCRIPT="/tmp/migrate-to-npmplus-api.sh" cat > "$MIGRATE_SCRIPT" << 'MIGRATE_EOF' #!/bin/bash # Migrate configurations to NPMplus set -e NPM_URL="https://127.0.0.1:81" EMAIL="admin@example.org" PASSWORD="${1}" echo "🔐 Authenticating to NPMplus..." TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \ -H "Content-Type: application/json" \ -d "{\"identity\":\"$EMAIL\",\"secret\":\"$PASSWORD\"}") TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || echo "") if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then ERROR_MSG=$(echo "$TOKEN_RESPONSE" | jq -r '.error.message // "Unknown error"' 2>/dev/null || echo "$TOKEN_RESPONSE") echo "❌ Authentication failed: $ERROR_MSG" exit 1 fi echo "✅ Authentication successful" echo "" # Function to create proxy host create_proxy_host() { local domain=$1 local scheme=$2 local hostname=$3 local port=$4 local websocket=$5 echo "📋 Processing $domain..." # Check if exists EXISTING=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \ -H "Authorization: Bearer $TOKEN" | jq -r ".result[] | select(.domain_names[] == \"$domain\") | .id" 2>/dev/null || echo "") local HOST_ID if [ -n "$EXISTING" ] && [ "$EXISTING" != "null" ]; then echo " ℹ️ Already exists (ID: $EXISTING)" HOST_ID=$EXISTING else # Create new echo " ➕ Creating proxy host..." RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/nginx/proxy-hosts" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"domain_names\": [\"$domain\"], \"forward_scheme\": \"$scheme\", \"forward_hostname\": \"$hostname\", \"forward_port\": $port, \"allow_websocket_upgrade\": $websocket, \"block_exploits\": true, \"cache_enabled\": false, \"ssl_forced\": true, \"http2_support\": true, \"hsts_enabled\": true, \"hsts_subdomains\": true, \"access_list_id\": 0, \"certificate_id\": 0 }") HOST_ID=$(echo "$RESPONSE" | jq -r '.id // empty' 2>/dev/null || echo "") if [ -z "$HOST_ID" ] || [ "$HOST_ID" = "null" ]; then ERROR=$(echo "$RESPONSE" | jq -r '.error.message // .error // "Unknown error"' 2>/dev/null || echo "$RESPONSE") echo " ❌ Failed: $ERROR" return 1 fi echo " ✅ Created (ID: $HOST_ID)" fi # Request SSL certificate echo " 🔒 Requesting SSL certificate..." CERT_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/nginx/certificates" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"domain_names\": [\"$domain\"], \"provider\": \"letsencrypt\", \"letsencrypt_email\": \"nsatoshi2007@hotmail.com\", \"letsencrypt_agree\": true }") CERT_ID=$(echo "$CERT_RESPONSE" | jq -r '.id // empty' 2>/dev/null || echo "") if [ -z "$CERT_ID" ] || [ "$CERT_ID" = "null" ]; then ERROR=$(echo "$CERT_RESPONSE" | jq -r '.error.message // .error // "Check manually\"' 2>/dev/null || echo "$CERT_RESPONSE") echo " ⚠️ Certificate request: $ERROR" echo " ℹ️ Certificate may be processing or domain may need DNS verification" else echo " ✅ Certificate requested (ID: $CERT_ID)" # Update proxy host with certificate if [ -n "$CERT_ID" ] && [ "$CERT_ID" != "null" ] && [ "$CERT_ID" != "0" ]; then UPDATE_RESPONSE=$(curl -s -k -X PUT "$NPM_URL/api/nginx/proxy-hosts/$HOST_ID" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"certificate_id\": $CERT_ID, \"ssl_forced\": true }") echo " ✅ SSL configured for $domain" fi fi return 0 } # Configure all 19 domains echo "🚀 Starting domain configuration (19 domains)..." echo "" SUCCESS=0 FAILED=0 # sankofa.nexus (5 domains) create_proxy_host "sankofa.nexus" "http" "192.168.11.140" "80" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "www.sankofa.nexus" "http" "192.168.11.140" "80" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "phoenix.sankofa.nexus" "http" "192.168.11.140" "80" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "www.phoenix.sankofa.nexus" "http" "192.168.11.140" "80" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "the-order.sankofa.nexus" "http" "192.168.11.140" "80" "false" && ((SUCCESS++)) || ((FAILED++)) # d-bis.org (9 domains) create_proxy_host "explorer.d-bis.org" "http" "192.168.11.140" "80" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "rpc-http-pub.d-bis.org" "https" "192.168.11.252" "443" "true" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "rpc-ws-pub.d-bis.org" "https" "192.168.11.252" "443" "true" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "rpc-http-prv.d-bis.org" "https" "192.168.11.251" "443" "true" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "rpc-ws-prv.d-bis.org" "https" "192.168.11.251" "443" "true" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "dbis-admin.d-bis.org" "http" "192.168.11.130" "80" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "dbis-api.d-bis.org" "http" "192.168.11.155" "3000" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "dbis-api-2.d-bis.org" "http" "192.168.11.156" "3000" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "secure.d-bis.org" "http" "192.168.11.130" "80" "false" && ((SUCCESS++)) || ((FAILED++)) # mim4u.org (4 domains) create_proxy_host "mim4u.org" "http" "192.168.11.36" "80" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "www.mim4u.org" "http" "192.168.11.36" "80" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "secure.mim4u.org" "http" "192.168.11.36" "80" "false" && ((SUCCESS++)) || ((FAILED++)) create_proxy_host "training.mim4u.org" "http" "192.168.11.36" "80" "false" && ((SUCCESS++)) || ((FAILED++)) # defi-oracle.io (1 domain) create_proxy_host "rpc.public-0138.defi-oracle.io" "https" "192.168.11.252" "443" "true" && ((SUCCESS++)) || ((FAILED++)) echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "📊 Configuration Summary" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "✅ Successful: $SUCCESS" echo "⚠️ Failed: $FAILED" echo "📋 Total: 19" echo "" echo "⏳ SSL certificates may take 1-2 minutes to be issued" MIGRATE_EOF chmod +x "$MIGRATE_SCRIPT" scp "$MIGRATE_SCRIPT" root@"$PROXMOX_HOST":/tmp/ echo " 🚀 Running migration script in NPMplus container..." ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- bash < /tmp/migrate-to-npmplus-api.sh '$ADMIN_PASSWORD'" || { echo " ⚠️ Migration script had issues. Check output above." } echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "✅ Migration Complete!" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "📋 Summary:" echo " • Old NPM Container: $OLD_CONTAINER_ID" echo " • New NPMplus Container: $NEW_CONTAINER_ID" echo " • NPMplus IP: $CONTAINER_IP" echo " • Access URL: https://$CONTAINER_IP:81" echo " • Admin Email: admin@example.org" echo " • Admin Password: $ADMIN_PASSWORD" echo " • Backup Location: $BACKUP_DIR" echo "" echo "⚠️ Next Steps:" echo " 1. Update UDM Pro port forwarding to point to new container IP" echo " 2. Test all domains and SSL certificates" echo " 3. Update all scripts to use new container ID" echo " 4. (Optional) Stop old NPM container after verification" echo ""