docs: Ledger Live integration, contract deploy learnings, NEXT_STEPS updates
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands - CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround - CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check - NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere - MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates - LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
79
scripts/nginx-proxy-manager/add-rpc-core-2-npmplus-proxy.sh
Executable file
79
scripts/nginx-proxy-manager/add-rpc-core-2-npmplus-proxy.sh
Executable file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create NPMplus proxy host for rpc-core-2.d-bis.org → RPC Core-2 (VMID 2102, 192.168.11.212:8545).
|
||||
# Targets the THIRD NPMplus (192.168.11.169, VMID 10235 — same as Alltra/HYBX). Use after SFValley2 tunnel is set up.
|
||||
# Requires NPM_PASSWORD for that instance (in .env or NPM_URL). Run from repo root.
|
||||
# See: docs/04-configuration/NPMPLUS_FOUR_INSTANCES_MASTER.md, docs/04-configuration/cloudflare/SFVALLEY2_TUNNEL_MANUAL_RUNBOOK.md
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
[ -f "$PROJECT_ROOT/.env" ] && { set +u; source "$PROJECT_ROOT/.env"; set -u; }
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
|
||||
[ -f "$PROJECT_ROOT/config/ip-addresses.conf" ] && source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
# Third NPMplus (Alltra/HYBX + Nathan core-2) — 76.53.10.38 → 192.168.11.169
|
||||
NPMPLUS_THIRD="${IP_NPMPLUS_ALLTRA_HYBX:-192.168.11.169}"
|
||||
NPM_URL="${NPM_URL:-https://${NPMPLUS_THIRD}:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL_ALLTRA_HYBX:-${NPM_EMAIL:-admin@example.org}}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD_ALLTRA_HYBX:-${NPM_PASSWORD:-}}"
|
||||
RPC_CORE_2="${RPC_CORE_2:-192.168.11.212}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "❌ NPM_PASSWORD is required. Set it in .env or export NPM_PASSWORD=..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔐 Authenticating to NPMplus..."
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON")
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || true)
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
echo "❌ NPMplus authentication failed."
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Authenticated"
|
||||
echo ""
|
||||
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN")
|
||||
DOMAIN="rpc-core-2.d-bis.org"
|
||||
HOST_ID=$(echo "$PROXY_HOSTS_JSON" | jq -r ".[] | select(.domain_names | type == \"array\") | select(.domain_names[] == \"$DOMAIN\") | .id" 2>/dev/null | head -n1 || true)
|
||||
|
||||
if [ -n "$HOST_ID" ] && [ "$HOST_ID" != "null" ]; then
|
||||
echo "✓ $DOMAIN already exists (ID: $HOST_ID). Run update-npmplus-proxy-hosts-api.sh to sync target if needed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "➕ Creating proxy host: $DOMAIN → http://${RPC_CORE_2}:8545 (WebSocket on, block_exploits off for RPC)"
|
||||
CREATE_PAYLOAD=$(jq -n \
|
||||
--arg domain "$DOMAIN" \
|
||||
--arg forward_host "$RPC_CORE_2" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: "http",
|
||||
forward_host: $forward_host,
|
||||
forward_port: 8545,
|
||||
allow_websocket_upgrade: true,
|
||||
block_exploits: false
|
||||
}')
|
||||
RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$CREATE_PAYLOAD")
|
||||
|
||||
NEW_ID=$(echo "$RESPONSE" | jq -r '.id // empty' 2>/dev/null || true)
|
||||
if [ -n "$NEW_ID" ] && [ "$NEW_ID" != "null" ]; then
|
||||
echo "✅ Created $DOMAIN (ID: $NEW_ID). Add the route in Cloudflare sfvalley02 Published application routes and DNS CNAME."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ERROR=$(echo "$RESPONSE" | jq -r '.message // .error // "Unknown error"' 2>/dev/null || echo "$RESPONSE")
|
||||
echo "❌ Failed to create $DOMAIN: $ERROR"
|
||||
exit 1
|
||||
177
scripts/nginx-proxy-manager/complete-migration.sh
Executable file
177
scripts/nginx-proxy-manager/complete-migration.sh
Executable file
@@ -0,0 +1,177 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
# Complete NPMplus migration - handles all automated steps
|
||||
# Manual steps are clearly marked
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="${PROXMOX_HOST_R630_01}"
|
||||
OLD_CONTAINER_ID="105"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔄 Complete NPMplus Migration"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Step 1: Backup current NPM
|
||||
echo "📦 Step 1: Backing up current NPM..."
|
||||
BACKUP_DIR="/tmp/npm-migration-$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
echo " 📋 Exporting current configurations..."
|
||||
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\"
|
||||
fi
|
||||
'" > "$BACKUP_DIR/backup.log" 2>&1 || echo " ⚠️ Backup may have issues, continuing..."
|
||||
|
||||
ssh root@"$PROXMOX_HOST" "pct exec $OLD_CONTAINER_ID -- cat /tmp/npm-database.sql" > "$BACKUP_DIR/database.sql" 2>&1 || echo "" > "$BACKUP_DIR/database.sql"
|
||||
|
||||
echo " ✅ Backup saved to: $BACKUP_DIR"
|
||||
echo ""
|
||||
|
||||
# Step 2: Check for existing NPMplus
|
||||
echo "📦 Step 2: Checking for existing NPMplus installation..."
|
||||
EXISTING_CT=$(ssh root@"$PROXMOX_HOST" "pct list | grep -i npmplus | awk '{print \$1}' | head -1" || echo "")
|
||||
|
||||
if [ -n "$EXISTING_CT" ]; then
|
||||
echo " ✅ Found existing NPMplus container: $EXISTING_CT"
|
||||
NEW_CONTAINER_ID="$EXISTING_CT"
|
||||
else
|
||||
echo " ⚠️ No existing NPMplus container found"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📋 MANUAL STEP REQUIRED: Install NPMplus"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Please run this command on the Proxmox host:"
|
||||
echo ""
|
||||
echo " ssh root@$PROXMOX_HOST"
|
||||
echo " bash -c \"\$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/npmplus.sh)\""
|
||||
echo ""
|
||||
echo "When prompted:"
|
||||
echo " • Timezone: America/New_York"
|
||||
echo " • ACME Email: nsatoshi2007@hotmail.com"
|
||||
echo ""
|
||||
echo "After installation completes, note:"
|
||||
echo " • The container ID (VMID)"
|
||||
echo " • The container IP address"
|
||||
echo ""
|
||||
read -p "Press Enter after NPMplus is installed..."
|
||||
echo ""
|
||||
read -p "Enter the new NPMplus container ID (VMID): " NEW_CONTAINER_ID
|
||||
if [ -z "$NEW_CONTAINER_ID" ]; then
|
||||
echo " ❌ Container ID is required"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Step 3: Get container information
|
||||
echo ""
|
||||
echo "📦 Step 3: Getting container information..."
|
||||
CONTAINER_IP=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- hostname -I | awk '{print \$1}'" || echo "")
|
||||
if [ -z "$CONTAINER_IP" ]; then
|
||||
echo " ❌ Could not get container IP. Is the container running?"
|
||||
read -p " Enter container IP manually: " CONTAINER_IP
|
||||
if [ -z "$CONTAINER_IP" ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo " ✅ Container IP: $CONTAINER_IP"
|
||||
|
||||
# Get admin password
|
||||
echo " 🔑 Retrieving admin password..."
|
||||
ADMIN_PASSWORD=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- bash -c '
|
||||
if [ -f /opt/.npm_pwd ]; then
|
||||
grep -i password /opt/.npm_pwd | cut -d: -f2 | tr -d \" \"
|
||||
else
|
||||
docker logs npmplus 2>/dev/null | grep -i \"Creating a new user\" | tail -1 | grep -oP \"password: \K[^\s]+\" || echo \"\"
|
||||
fi
|
||||
'" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
echo " ⚠️ Could not retrieve password automatically"
|
||||
read -sp " Enter NPMplus admin password: " ADMIN_PASSWORD
|
||||
echo ""
|
||||
else
|
||||
echo " ✅ Admin password retrieved"
|
||||
fi
|
||||
|
||||
# Wait for NPMplus to be ready
|
||||
echo ""
|
||||
echo " ⏳ Waiting for NPMplus to be ready..."
|
||||
for i in {1..30}; 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/30)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Step 4: Migrate configurations
|
||||
echo ""
|
||||
echo "📦 Step 4: Migrating configurations..."
|
||||
echo "$ADMIN_PASSWORD" | bash scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh \
|
||||
"$PROXMOX_HOST" \
|
||||
"$NEW_CONTAINER_ID" \
|
||||
"https://$CONTAINER_IP:81" || {
|
||||
echo " ⚠️ Migration script had issues. Check output above."
|
||||
echo " 💡 You can run it manually:"
|
||||
echo " bash scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh $PROXMOX_HOST $NEW_CONTAINER_ID https://$CONTAINER_IP:81"
|
||||
}
|
||||
|
||||
# Step 5: Network configuration reminder
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📋 Step 5: Network Configuration Update Required"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "⚠️ MANUAL STEP: Update UDM Pro Port Forwarding"
|
||||
echo ""
|
||||
echo "1. Log into UDM Pro"
|
||||
echo "2. Go to: Settings → Networks → Port Forwarding"
|
||||
echo "3. Update both rules:"
|
||||
echo " • HTTP (Port 80): 76.53.10.36:80 → $CONTAINER_IP:80"
|
||||
echo " • HTTPS (Port 443): 76.53.10.36:443 → $CONTAINER_IP:443"
|
||||
echo ""
|
||||
read -p "Press Enter after updating port forwarding..."
|
||||
|
||||
# Step 6: Test migration
|
||||
echo ""
|
||||
echo "📦 Step 6: Testing migration..."
|
||||
echo " ⏳ Waiting 30 seconds for SSL certificates to process..."
|
||||
sleep 30
|
||||
|
||||
echo " 🔍 Testing SSL certificates..."
|
||||
bash scripts/check-east-west-ssl-status.sh || echo " ⚠️ Some tests may have failed. Check manually."
|
||||
|
||||
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 " • Backup Location: $BACKUP_DIR"
|
||||
echo ""
|
||||
echo "🔍 Next Steps:"
|
||||
echo " 1. Verify all domains are accessible"
|
||||
echo " 2. Test SSL certificates: bash scripts/check-east-west-ssl-status.sh"
|
||||
echo " 3. Monitor for 24-48 hours"
|
||||
echo " 4. (Optional) Stop old NPM container after verification:"
|
||||
echo " ssh root@$PROXMOX_HOST \"pct stop $OLD_CONTAINER_ID\""
|
||||
echo ""
|
||||
171
scripts/nginx-proxy-manager/complete-migration.sh.bak
Executable file
171
scripts/nginx-proxy-manager/complete-migration.sh.bak
Executable file
@@ -0,0 +1,171 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Complete NPMplus migration - handles all automated steps
|
||||
# Manual steps are clearly marked
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="192.168.11.11"
|
||||
OLD_CONTAINER_ID="105"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔄 Complete NPMplus Migration"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Step 1: Backup current NPM
|
||||
echo "📦 Step 1: Backing up current NPM..."
|
||||
BACKUP_DIR="/tmp/npm-migration-$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
echo " 📋 Exporting current configurations..."
|
||||
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\"
|
||||
fi
|
||||
'" > "$BACKUP_DIR/backup.log" 2>&1 || echo " ⚠️ Backup may have issues, continuing..."
|
||||
|
||||
ssh root@"$PROXMOX_HOST" "pct exec $OLD_CONTAINER_ID -- cat /tmp/npm-database.sql" > "$BACKUP_DIR/database.sql" 2>&1 || echo "" > "$BACKUP_DIR/database.sql"
|
||||
|
||||
echo " ✅ Backup saved to: $BACKUP_DIR"
|
||||
echo ""
|
||||
|
||||
# Step 2: Check for existing NPMplus
|
||||
echo "📦 Step 2: Checking for existing NPMplus installation..."
|
||||
EXISTING_CT=$(ssh root@"$PROXMOX_HOST" "pct list | grep -i npmplus | awk '{print \$1}' | head -1" || echo "")
|
||||
|
||||
if [ -n "$EXISTING_CT" ]; then
|
||||
echo " ✅ Found existing NPMplus container: $EXISTING_CT"
|
||||
NEW_CONTAINER_ID="$EXISTING_CT"
|
||||
else
|
||||
echo " ⚠️ No existing NPMplus container found"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📋 MANUAL STEP REQUIRED: Install NPMplus"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Please run this command on the Proxmox host:"
|
||||
echo ""
|
||||
echo " ssh root@$PROXMOX_HOST"
|
||||
echo " bash -c \"\$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/npmplus.sh)\""
|
||||
echo ""
|
||||
echo "When prompted:"
|
||||
echo " • Timezone: America/New_York"
|
||||
echo " • ACME Email: nsatoshi2007@hotmail.com"
|
||||
echo ""
|
||||
echo "After installation completes, note:"
|
||||
echo " • The container ID (VMID)"
|
||||
echo " • The container IP address"
|
||||
echo ""
|
||||
read -p "Press Enter after NPMplus is installed..."
|
||||
echo ""
|
||||
read -p "Enter the new NPMplus container ID (VMID): " NEW_CONTAINER_ID
|
||||
if [ -z "$NEW_CONTAINER_ID" ]; then
|
||||
echo " ❌ Container ID is required"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Step 3: Get container information
|
||||
echo ""
|
||||
echo "📦 Step 3: Getting container information..."
|
||||
CONTAINER_IP=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- hostname -I | awk '{print \$1}'" || echo "")
|
||||
if [ -z "$CONTAINER_IP" ]; then
|
||||
echo " ❌ Could not get container IP. Is the container running?"
|
||||
read -p " Enter container IP manually: " CONTAINER_IP
|
||||
if [ -z "$CONTAINER_IP" ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo " ✅ Container IP: $CONTAINER_IP"
|
||||
|
||||
# Get admin password
|
||||
echo " 🔑 Retrieving admin password..."
|
||||
ADMIN_PASSWORD=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- bash -c '
|
||||
if [ -f /opt/.npm_pwd ]; then
|
||||
grep -i password /opt/.npm_pwd | cut -d: -f2 | tr -d \" \"
|
||||
else
|
||||
docker logs npmplus 2>/dev/null | grep -i \"Creating a new user\" | tail -1 | grep -oP \"password: \K[^\s]+\" || echo \"\"
|
||||
fi
|
||||
'" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
echo " ⚠️ Could not retrieve password automatically"
|
||||
read -sp " Enter NPMplus admin password: " ADMIN_PASSWORD
|
||||
echo ""
|
||||
else
|
||||
echo " ✅ Admin password retrieved"
|
||||
fi
|
||||
|
||||
# Wait for NPMplus to be ready
|
||||
echo ""
|
||||
echo " ⏳ Waiting for NPMplus to be ready..."
|
||||
for i in {1..30}; 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/30)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Step 4: Migrate configurations
|
||||
echo ""
|
||||
echo "📦 Step 4: Migrating configurations..."
|
||||
echo "$ADMIN_PASSWORD" | bash scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh \
|
||||
"$PROXMOX_HOST" \
|
||||
"$NEW_CONTAINER_ID" \
|
||||
"https://$CONTAINER_IP:81" || {
|
||||
echo " ⚠️ Migration script had issues. Check output above."
|
||||
echo " 💡 You can run it manually:"
|
||||
echo " bash scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh $PROXMOX_HOST $NEW_CONTAINER_ID https://$CONTAINER_IP:81"
|
||||
}
|
||||
|
||||
# Step 5: Network configuration reminder
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📋 Step 5: Network Configuration Update Required"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "⚠️ MANUAL STEP: Update UDM Pro Port Forwarding"
|
||||
echo ""
|
||||
echo "1. Log into UDM Pro"
|
||||
echo "2. Go to: Settings → Networks → Port Forwarding"
|
||||
echo "3. Update both rules:"
|
||||
echo " • HTTP (Port 80): 76.53.10.36:80 → $CONTAINER_IP:80"
|
||||
echo " • HTTPS (Port 443): 76.53.10.36:443 → $CONTAINER_IP:443"
|
||||
echo ""
|
||||
read -p "Press Enter after updating port forwarding..."
|
||||
|
||||
# Step 6: Test migration
|
||||
echo ""
|
||||
echo "📦 Step 6: Testing migration..."
|
||||
echo " ⏳ Waiting 30 seconds for SSL certificates to process..."
|
||||
sleep 30
|
||||
|
||||
echo " 🔍 Testing SSL certificates..."
|
||||
bash scripts/check-east-west-ssl-status.sh || echo " ⚠️ Some tests may have failed. Check manually."
|
||||
|
||||
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 " • Backup Location: $BACKUP_DIR"
|
||||
echo ""
|
||||
echo "🔍 Next Steps:"
|
||||
echo " 1. Verify all domains are accessible"
|
||||
echo " 2. Test SSL certificates: bash scripts/check-east-west-ssl-status.sh"
|
||||
echo " 3. Monitor for 24-48 hours"
|
||||
echo " 4. (Optional) Stop old NPM container after verification:"
|
||||
echo " ssh root@$PROXMOX_HOST \"pct stop $OLD_CONTAINER_ID\""
|
||||
echo ""
|
||||
457
scripts/nginx-proxy-manager/configure-npmplus-domains.js
Executable file
457
scripts/nginx-proxy-manager/configure-npmplus-domains.js
Executable file
@@ -0,0 +1,457 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Configure all 19 domains in NPMplus using browser automation
|
||||
* This script uses Playwright to interact with the NPMplus web UI
|
||||
*/
|
||||
|
||||
import { chromium } from 'playwright';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import { config } from 'dotenv';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
config({ path: join(PROJECT_ROOT, '.env') });
|
||||
|
||||
// Configuration
|
||||
const NPM_URL = process.env.NPM_URL || 'https://192.168.11.167:81';
|
||||
const NPM_EMAIL = process.env.NPM_EMAIL || 'nsatoshi2007@hotmail.com';
|
||||
const NPM_PASSWORD = process.env.NPM_PASSWORD;
|
||||
const HEADLESS = process.env.HEADLESS !== 'false';
|
||||
|
||||
if (!NPM_PASSWORD) {
|
||||
console.error('❌ NPM_PASSWORD is required. Set it in .env or export NPM_PASSWORD=...');
|
||||
process.exit(1);
|
||||
}
|
||||
const PAUSE_MODE = process.env.PAUSE_MODE === 'true';
|
||||
|
||||
// All domains to configure (proxy hosts)
|
||||
// UPDATED: 2026-01-18 - Correct VMIDs and IP addresses verified
|
||||
// Reference: docs/04-configuration/RPC_ENDPOINTS_MASTER.md and ALL_VMIDS_ENDPOINTS.md
|
||||
const DOMAINS = [
|
||||
// sankofa.nexus zone - REMOVED: Services not deployed, were incorrectly routing to Blockscout
|
||||
// { domain: 'sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
||||
// { domain: 'phoenix.sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
||||
// { domain: 'the-order.sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
||||
|
||||
// d-bis.org zone - Blockchain Explorer
|
||||
// Web UI via nginx: NPMplus → Blockscout:80 (nginx serves UI and proxies /api/* to 4000)
|
||||
{ domain: 'explorer.d-bis.org', target: 'http://192.168.11.140:80', websocket: false }, // VMID 5000
|
||||
|
||||
// d-bis.org zone - Public RPC endpoints (VMID 2201: besu-rpc-public-1)
|
||||
{ domain: 'rpc-http-pub.d-bis.org', target: 'http://192.168.11.221:8545', websocket: true }, // VMID 2201
|
||||
{ domain: 'rpc-ws-pub.d-bis.org', target: 'http://192.168.11.221:8546', websocket: true }, // VMID 2201
|
||||
|
||||
// d-bis.org zone - Private RPC endpoints (VMID 2101: besu-rpc-core-1)
|
||||
{ domain: 'rpc-http-prv.d-bis.org', target: 'http://192.168.11.211:8545', websocket: true }, // VMID 2101
|
||||
{ domain: 'rpc-ws-prv.d-bis.org', target: 'http://192.168.11.211:8546', websocket: true }, // VMID 2101
|
||||
|
||||
// d-bis.org zone - DBIS Core Services
|
||||
{ domain: 'dbis-admin.d-bis.org', target: 'http://192.168.11.130:80', websocket: false }, // VMID 10130: dbis-frontend
|
||||
{ domain: 'dbis-api.d-bis.org', target: 'http://192.168.11.155:3000', websocket: false }, // VMID 10150: dbis-api-primary
|
||||
{ domain: 'dbis-api-2.d-bis.org', target: 'http://192.168.11.156:3000', websocket: false }, // VMID 10151: dbis-api-secondary
|
||||
{ domain: 'secure.d-bis.org', target: 'http://192.168.11.130:80', websocket: false }, // VMID 10130: dbis-frontend (path-based routing)
|
||||
|
||||
// mim4u.org zone - Miracles In Motion Services
|
||||
// VMID 7810: mim-web-1 (Web Frontend) @ 192.168.11.37 - serves static files and proxies /api/* to backend
|
||||
// VMID 7811: mim-api-1 (API Backend) @ 192.168.11.36 - handles API requests
|
||||
{ domain: 'mim4u.org', target: 'http://192.168.11.37:80', websocket: false }, // VMID 7810: mim-web-1
|
||||
{ domain: 'secure.mim4u.org', target: 'http://192.168.11.37:80', websocket: false }, // VMID 7810: mim-web-1
|
||||
{ domain: 'training.mim4u.org', target: 'http://192.168.11.37:80', websocket: false }, // VMID 7810: mim-web-1
|
||||
|
||||
// defi-oracle.io zone - ThirdWeb RPC (VMID 2400: thirdweb-rpc-1)
|
||||
// Note: Uses HTTPS and port 443 (Nginx with RPC Translator)
|
||||
{ domain: 'rpc.public-0138.defi-oracle.io', target: 'https://192.168.11.240:443', websocket: true }, // VMID 2400
|
||||
{ domain: 'rpc.defi-oracle.io', target: 'https://192.168.11.240:443', websocket: true }, // VMID 2400 - HTTP RPC
|
||||
{ domain: 'wss.defi-oracle.io', target: 'https://192.168.11.240:443', websocket: true }, // VMID 2400 - WebSocket RPC
|
||||
];
|
||||
|
||||
// www.* domains that redirect to parent domains
|
||||
const REDIRECT_DOMAINS = [
|
||||
// REMOVED: Sankofa redirects - services not deployed
|
||||
// { domain: 'www.sankofa.nexus', redirectTo: 'sankofa.nexus' },
|
||||
// { domain: 'www.phoenix.sankofa.nexus', redirectTo: 'phoenix.sankofa.nexus' },
|
||||
{ domain: 'www.mim4u.org', redirectTo: 'mim4u.org' },
|
||||
];
|
||||
|
||||
function log(message, type = 'info') {
|
||||
const icons = { success: '✅', error: '❌', warning: '⚠️', info: '📋' };
|
||||
const icon = icons[type] || '📋';
|
||||
console.log(`${icon} ${message}`);
|
||||
}
|
||||
|
||||
async function pause(page, message) {
|
||||
if (PAUSE_MODE) {
|
||||
log(`Paused: ${message}`, 'info');
|
||||
await page.pause();
|
||||
}
|
||||
}
|
||||
|
||||
async function login(page) {
|
||||
log('Logging in to NPMplus...');
|
||||
await page.goto(NPM_URL, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||
await pause(page, 'At login page');
|
||||
|
||||
// Wait for login form
|
||||
await page.waitForSelector('input[type="email"], input[name="email"], input[placeholder*="email" i]', { timeout: 10000 });
|
||||
|
||||
// Fill email
|
||||
const emailInput = await page.$('input[type="email"]') || await page.$('input[name="email"]') || await page.$('input[placeholder*="email" i]');
|
||||
if (emailInput) {
|
||||
await emailInput.fill(NPM_EMAIL);
|
||||
log(`Filled email: ${NPM_EMAIL}`);
|
||||
}
|
||||
|
||||
// Fill password
|
||||
const passwordInput = await page.$('input[type="password"]');
|
||||
if (passwordInput) {
|
||||
await passwordInput.fill(NPM_PASSWORD);
|
||||
log('Filled password');
|
||||
}
|
||||
|
||||
// Click login button
|
||||
const loginButton = await page.$('button[type="submit"]') || await page.$('button:has-text("Sign In")') || await page.$('button:has-text("Login")');
|
||||
if (loginButton) {
|
||||
await loginButton.click();
|
||||
log('Clicked login button');
|
||||
} else {
|
||||
await page.keyboard.press('Enter');
|
||||
}
|
||||
|
||||
// Wait for dashboard - NPMplus might use different URL patterns
|
||||
try {
|
||||
await page.waitForTimeout(3000);
|
||||
const currentURL = page.url();
|
||||
log(`Current URL after login: ${currentURL}`);
|
||||
|
||||
// Check if we're logged in by looking for dashboard elements
|
||||
const dashboardElements = await page.$('text=/dashboard|hosts|proxy|Proxy Hosts/i').catch(() => null);
|
||||
if (dashboardElements || currentURL.includes('dashboard') || currentURL.includes('hosts') || currentURL.includes('proxy')) {
|
||||
log('Logged in successfully', 'success');
|
||||
await pause(page, 'After login');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try waiting for URL change
|
||||
await page.waitForURL(/dashboard|hosts|proxy|#/, { timeout: 15000 });
|
||||
log('Logged in successfully', 'success');
|
||||
await pause(page, 'After login');
|
||||
return true;
|
||||
} catch (e) {
|
||||
// Check if we're actually logged in despite the timeout
|
||||
const currentURL = page.url();
|
||||
const pageContent = await page.textContent('body').catch(() => '');
|
||||
|
||||
if (currentURL.includes('dashboard') || currentURL.includes('hosts') || pageContent.includes('Proxy Hosts')) {
|
||||
log('Logged in (detected via page content)', 'success');
|
||||
return true;
|
||||
}
|
||||
|
||||
log(`Login check failed: ${e.message}`, 'error');
|
||||
log(`Current URL: ${currentURL}`, 'info');
|
||||
await page.screenshot({ path: '/tmp/npmplus-login-error.png' });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function configureProxyHost(page, domainConfig) {
|
||||
const { domain, target, websocket } = domainConfig;
|
||||
const url = new URL(target);
|
||||
const scheme = url.protocol.replace(':', '');
|
||||
const hostname = url.hostname;
|
||||
const port = url.port || (scheme === 'https' ? '443' : '80');
|
||||
|
||||
log(`Configuring ${domain}...`);
|
||||
|
||||
try {
|
||||
// Navigate to proxy hosts
|
||||
await page.goto(`${NPM_URL}/#/proxy-hosts`, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Click "Add Proxy Host" button
|
||||
const addButton = await page.$('button:has-text("Add Proxy Host"), button:has-text("Add"), a:has-text("Add Proxy Host")');
|
||||
if (addButton) {
|
||||
await addButton.click();
|
||||
log(` Clicked Add Proxy Host for ${domain}`);
|
||||
} else {
|
||||
// Try alternative selectors
|
||||
await page.click('button.btn-primary, .btn-add, [data-action="add"]');
|
||||
}
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Fill domain name
|
||||
const domainInput = await page.$('input[name="domain_names"], input[placeholder*="domain" i], #domain_names');
|
||||
if (domainInput) {
|
||||
await domainInput.fill(domain);
|
||||
log(` Filled domain: ${domain}`);
|
||||
}
|
||||
|
||||
// Fill forward scheme
|
||||
const schemeSelect = await page.$('select[name="forward_scheme"], select#forward_scheme');
|
||||
if (schemeSelect) {
|
||||
await schemeSelect.selectOption(scheme);
|
||||
log(` Set scheme: ${scheme}`);
|
||||
}
|
||||
|
||||
// Fill forward host
|
||||
const hostInput = await page.$('input[name="forward_host"], input[name="forward_hostname"], input#forward_host');
|
||||
if (hostInput) {
|
||||
await hostInput.fill(hostname);
|
||||
log(` Filled host: ${hostname}`);
|
||||
}
|
||||
|
||||
// Fill forward port
|
||||
const portInput = await page.$('input[name="forward_port"], input#forward_port');
|
||||
if (portInput) {
|
||||
await portInput.fill(port);
|
||||
log(` Filled port: ${port}`);
|
||||
}
|
||||
|
||||
// Enable websocket if needed
|
||||
if (websocket) {
|
||||
const websocketCheckbox = await page.$('input[type="checkbox"][name*="websocket" i], input[type="checkbox"][id*="websocket" i]');
|
||||
if (websocketCheckbox && !(await websocketCheckbox.isChecked())) {
|
||||
await websocketCheckbox.check();
|
||||
log(` Enabled WebSocket for ${domain}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable block exploits
|
||||
const blockExploitsCheckbox = await page.$('input[type="checkbox"][name*="block" i], input[type="checkbox"][id*="block" i]');
|
||||
if (blockExploitsCheckbox && !(await blockExploitsCheckbox.isChecked())) {
|
||||
await blockExploitsCheckbox.check();
|
||||
}
|
||||
|
||||
// Navigate to SSL tab
|
||||
const sslTab = await page.$('a[href*="ssl" i], button:has-text("SSL"), .tab:has-text("SSL")');
|
||||
if (sslTab) {
|
||||
await sslTab.click();
|
||||
await page.waitForTimeout(1000);
|
||||
}
|
||||
|
||||
// Request SSL certificate
|
||||
const requestCertButton = await page.$('button:has-text("Request"), button:has-text("SSL Certificate"), a:has-text("Request")');
|
||||
if (requestCertButton) {
|
||||
await requestCertButton.click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Fill email for Let's Encrypt
|
||||
const emailInput = await page.$('input[name="letsencrypt_email"], input[name="email"], input[type="email"]');
|
||||
if (emailInput) {
|
||||
await emailInput.fill('nsatoshi2007@hotmail.com');
|
||||
}
|
||||
|
||||
// Agree to terms
|
||||
const agreeCheckbox = await page.$('input[type="checkbox"][name*="agree" i]');
|
||||
if (agreeCheckbox) {
|
||||
await agreeCheckbox.check();
|
||||
}
|
||||
|
||||
// Enable Force SSL
|
||||
const forceSSLCheckbox = await page.$('input[type="checkbox"][name*="ssl_forced" i], input[type="checkbox"][name*="force" i]');
|
||||
if (forceSSLCheckbox && !(await forceSSLCheckbox.isChecked())) {
|
||||
await forceSSLCheckbox.check();
|
||||
}
|
||||
|
||||
// Enable HTTP/2
|
||||
const http2Checkbox = await page.$('input[type="checkbox"][name*="http2" i]');
|
||||
if (http2Checkbox && !(await http2Checkbox.isChecked())) {
|
||||
await http2Checkbox.check();
|
||||
}
|
||||
|
||||
// Enable HSTS
|
||||
const hstsCheckbox = await page.$('input[type="checkbox"][name*="hsts" i]');
|
||||
if (hstsCheckbox && !(await hstsCheckbox.isChecked())) {
|
||||
await hstsCheckbox.check();
|
||||
}
|
||||
}
|
||||
|
||||
// Save
|
||||
const saveButton = await page.$('button:has-text("Save"), button.btn-primary:has-text("Save"), button[type="submit"]');
|
||||
if (saveButton) {
|
||||
await saveButton.click();
|
||||
log(` Saved ${domain}`, 'success');
|
||||
await page.waitForTimeout(2000);
|
||||
return true;
|
||||
} else {
|
||||
log(` Could not find save button for ${domain}`, 'warning');
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
log(` Error configuring ${domain}: ${error.message}`, 'error');
|
||||
await page.screenshot({ path: `/tmp/npmplus-error-${domain.replace(/\./g, '-')}.png` });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function configureRedirectHost(page, redirectConfig) {
|
||||
const { domain, redirectTo } = redirectConfig;
|
||||
|
||||
log(`Configuring redirect ${domain} → ${redirectTo}...`);
|
||||
|
||||
try {
|
||||
// Navigate to proxy hosts
|
||||
await page.goto(`${NPM_URL}/#/proxy-hosts`, { waitUntil: 'domcontentloaded' });
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Click "Add Proxy Host" button
|
||||
const addButton = await page.$('button:has-text("Add Proxy Host"), button:has-text("Add"), a:has-text("Add Proxy Host")');
|
||||
if (addButton) {
|
||||
await addButton.click();
|
||||
log(` Clicked Add Proxy Host for ${domain}`);
|
||||
} else {
|
||||
await page.click('button.btn-primary, .btn-add, [data-action="add"]');
|
||||
}
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Switch to "Redirect" type (if available)
|
||||
const redirectType = await page.$('input[type="radio"][value="redirect"], input[type="radio"][name*="redirect" i]');
|
||||
if (redirectType) {
|
||||
await redirectType.click();
|
||||
log(` Selected Redirect type for ${domain}`);
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
|
||||
// Fill domain name
|
||||
const domainInput = await page.$('input[name="domain_names"], input[placeholder*="domain" i], #domain_names');
|
||||
if (domainInput) {
|
||||
await domainInput.fill(domain);
|
||||
log(` Filled domain: ${domain}`);
|
||||
}
|
||||
|
||||
// Fill redirect target
|
||||
const redirectInput = await page.$('input[name="forward_host"], input[name="redirect"], input[placeholder*="redirect" i]');
|
||||
if (redirectInput) {
|
||||
await redirectInput.fill(redirectTo);
|
||||
log(` Set redirect to: ${redirectTo}`);
|
||||
}
|
||||
|
||||
// Navigate to SSL tab if exists
|
||||
const sslTab = await page.$('a[href*="ssl" i], button:has-text("SSL"), .tab:has-text("SSL")');
|
||||
if (sslTab) {
|
||||
await sslTab.click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Request SSL certificate for redirect
|
||||
const requestCertButton = await page.$('button:has-text("Request"), button:has-text("SSL Certificate"), a:has-text("Request")');
|
||||
if (requestCertButton) {
|
||||
await requestCertButton.click();
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Fill email for Let's Encrypt
|
||||
const emailInput = await page.$('input[name="letsencrypt_email"], input[name="email"], input[type="email"]');
|
||||
if (emailInput) {
|
||||
await emailInput.fill('nsatoshi2007@hotmail.com');
|
||||
}
|
||||
|
||||
// Agree to terms
|
||||
const agreeCheckbox = await page.$('input[type="checkbox"][name*="agree" i]');
|
||||
if (agreeCheckbox) {
|
||||
await agreeCheckbox.check();
|
||||
}
|
||||
|
||||
// Enable Force SSL
|
||||
const forceSSLCheckbox = await page.$('input[type="checkbox"][name*="ssl_forced" i], input[type="checkbox"][name*="force" i]');
|
||||
if (forceSSLCheckbox && !(await forceSSLCheckbox.isChecked())) {
|
||||
await forceSSLCheckbox.check();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save
|
||||
const saveButton = await page.$('button:has-text("Save"), button.btn-primary:has-text("Save"), button[type="submit"]');
|
||||
if (saveButton) {
|
||||
await saveButton.click();
|
||||
log(` Saved redirect ${domain} → ${redirectTo}`, 'success');
|
||||
await page.waitForTimeout(2000);
|
||||
return true;
|
||||
} else {
|
||||
log(` Could not find save button for ${domain}`, 'warning');
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
log(` Error configuring redirect ${domain}: ${error.message}`, 'error');
|
||||
await page.screenshot({ path: `/tmp/npmplus-redirect-error-${domain.replace(/\./g, '-')}.png` });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
log('Starting NPMplus domain configuration...', 'info');
|
||||
log(`Target: ${NPM_URL}`, 'info');
|
||||
log(`Proxy hosts to configure: ${DOMAINS.length}`, 'info');
|
||||
log(`Redirects to configure: ${REDIRECT_DOMAINS.length}`, 'info');
|
||||
console.log('');
|
||||
|
||||
const browser = await chromium.launch({
|
||||
headless: HEADLESS,
|
||||
ignoreHTTPSErrors: true
|
||||
});
|
||||
|
||||
const context = await browser.newContext({
|
||||
ignoreHTTPSErrors: true,
|
||||
viewport: { width: 1920, height: 1080 }
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
try {
|
||||
// Login
|
||||
const loggedIn = await login(page);
|
||||
if (!loggedIn) {
|
||||
log('Failed to login. Exiting.', 'error');
|
||||
await browser.close();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Configure proxy hosts
|
||||
let proxySuccess = 0;
|
||||
let proxyFailed = 0;
|
||||
|
||||
for (const domainConfig of DOMAINS) {
|
||||
const result = await configureProxyHost(page, domainConfig);
|
||||
if (result) {
|
||||
proxySuccess++;
|
||||
} else {
|
||||
proxyFailed++;
|
||||
}
|
||||
await page.waitForTimeout(1000); // Small delay between domains
|
||||
}
|
||||
|
||||
// Configure redirects
|
||||
let redirectSuccess = 0;
|
||||
let redirectFailed = 0;
|
||||
|
||||
for (const redirectConfig of REDIRECT_DOMAINS) {
|
||||
const result = await configureRedirectHost(page, redirectConfig);
|
||||
if (result) {
|
||||
redirectSuccess++;
|
||||
} else {
|
||||
redirectFailed++;
|
||||
}
|
||||
await page.waitForTimeout(1000); // Small delay between redirects
|
||||
}
|
||||
|
||||
console.log('');
|
||||
log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'info');
|
||||
log('Configuration Summary', 'info');
|
||||
log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'info');
|
||||
log(`✅ Proxy Hosts - Successful: ${proxySuccess}, Failed: ${proxyFailed}`, proxyFailed > 0 ? 'warning' : 'success');
|
||||
log(`✅ Redirects - Successful: ${redirectSuccess}, Failed: ${redirectFailed}`, redirectFailed > 0 ? 'warning' : 'success');
|
||||
log(`📋 Total Proxy Hosts: ${DOMAINS.length}`, 'info');
|
||||
log(`📋 Total Redirects: ${REDIRECT_DOMAINS.length}`, 'info');
|
||||
console.log('');
|
||||
log('⏳ SSL certificates may take 1-2 minutes to be issued', 'info');
|
||||
|
||||
} catch (error) {
|
||||
log(`Fatal error: ${error.message}`, 'error');
|
||||
await page.screenshot({ path: '/tmp/npmplus-fatal-error.png' });
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
415
scripts/nginx-proxy-manager/configure-ssl-all-domains.js
Executable file
415
scripts/nginx-proxy-manager/configure-ssl-all-domains.js
Executable file
@@ -0,0 +1,415 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Configure SSL certificates for all domains in Nginx Proxy Manager
|
||||
* Uses browser automation to configure proxy hosts and Let's Encrypt certificates
|
||||
*/
|
||||
|
||||
import { chromium } from 'playwright';
|
||||
import { readFileSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import { config } from 'dotenv';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
|
||||
// Load environment variables
|
||||
config({ path: join(PROJECT_ROOT, '.env') });
|
||||
|
||||
// Configuration
|
||||
const NPM_URL = process.env.NPM_URL || 'http://192.168.11.26:81';
|
||||
const NPM_EMAIL = process.env.NPM_EMAIL || process.env.NGINX_EMAIL || 'nsatoshi2007@hotmail.com';
|
||||
const NPM_USERNAME = process.env.NPM_USERNAME || 'nsatoshi2007';
|
||||
const NPM_PASSWORD = process.env.NPM_PASSWORD || process.env.NGINX_PASSWORD || 'L@ker$2010';
|
||||
const HEADLESS = process.env.HEADLESS !== 'false';
|
||||
const PAUSE_MODE = process.env.PAUSE_MODE === 'true';
|
||||
|
||||
// All domains to configure
|
||||
const DOMAINS = [
|
||||
// sankofa.nexus zone
|
||||
{ domain: 'sankofa.nexus', target: 'http://192.168.11.140:80', description: 'Sankofa Nexus' },
|
||||
{ domain: 'www.sankofa.nexus', target: 'http://192.168.11.140:80', description: 'Sankofa Nexus WWW' },
|
||||
{ domain: 'phoenix.sankofa.nexus', target: 'http://192.168.11.140:80', description: 'Phoenix Sankofa' },
|
||||
{ domain: 'www.phoenix.sankofa.nexus', target: 'http://192.168.11.140:80', description: 'Phoenix Sankofa WWW' },
|
||||
{ domain: 'the-order.sankofa.nexus', target: 'http://192.168.11.140:80', description: 'The Order' },
|
||||
|
||||
// d-bis.org zone
|
||||
{ domain: 'explorer.d-bis.org', target: 'http://192.168.11.140:4000', description: 'Blockscout Explorer (Direct Route)' },
|
||||
{ domain: 'rpc-http-pub.d-bis.org', target: 'https://192.168.11.252:443', description: 'RPC HTTP Public' },
|
||||
{ domain: 'rpc-ws-pub.d-bis.org', target: 'https://192.168.11.252:443', description: 'RPC WebSocket Public' },
|
||||
{ domain: 'rpc-http-prv.d-bis.org', target: 'https://192.168.11.251:443', description: 'RPC HTTP Private' },
|
||||
{ domain: 'rpc-ws-prv.d-bis.org', target: 'https://192.168.11.251:443', description: 'RPC WebSocket Private' },
|
||||
{ domain: 'dbis-admin.d-bis.org', target: 'http://192.168.11.130:80', description: 'DBIS Admin' },
|
||||
{ domain: 'dbis-api.d-bis.org', target: 'http://192.168.11.155:3000', description: 'DBIS API' },
|
||||
{ domain: 'dbis-api-2.d-bis.org', target: 'http://192.168.11.156:3000', description: 'DBIS API 2' },
|
||||
{ domain: 'secure.d-bis.org', target: 'http://192.168.11.130:80', description: 'DBIS Secure' },
|
||||
|
||||
// mim4u.org zone
|
||||
// MIM4U - VMID 7810 (mim-web-1) @ 192.168.11.37 - Web Frontend serves main site and proxies /api/* to 7811
|
||||
{ domain: 'mim4u.org', target: 'http://192.168.11.37:80', description: 'MIM4U' },
|
||||
{ domain: 'www.mim4u.org', target: 'http://192.168.11.37:80', description: 'MIM4U WWW' },
|
||||
{ domain: 'secure.mim4u.org', target: 'http://192.168.11.37:80', description: 'MIM4U Secure' },
|
||||
{ domain: 'training.mim4u.org', target: 'http://192.168.11.37:80', description: 'MIM4U Training' },
|
||||
|
||||
// defi-oracle.io zone
|
||||
{ domain: 'rpc.public-0138.defi-oracle.io', target: 'https://192.168.11.252:443', description: 'ThirdWeb RPC' },
|
||||
];
|
||||
|
||||
// Helper functions
|
||||
const log = {
|
||||
info: (msg) => console.log(`[INFO] ${msg}`),
|
||||
success: (msg) => console.log(`[✓] ${msg}`),
|
||||
warn: (msg) => console.log(`[⚠] ${msg}`),
|
||||
error: (msg) => console.log(`[✗] ${msg}`),
|
||||
};
|
||||
|
||||
const pause = async (page, message) => {
|
||||
if (PAUSE_MODE) {
|
||||
log.info(`⏸ PAUSE: ${message}`);
|
||||
log.info('Press Enter to continue...');
|
||||
await new Promise(resolve => {
|
||||
process.stdin.once('data', () => resolve());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
async function login(page) {
|
||||
log.info('Logging in to Nginx Proxy Manager...');
|
||||
|
||||
try {
|
||||
// Try with more lenient wait strategy
|
||||
await page.goto(NPM_URL, { waitUntil: 'domcontentloaded', timeout: 60000 });
|
||||
await page.waitForTimeout(2000); // Give page time to fully load
|
||||
await pause(page, 'At login page');
|
||||
|
||||
// Take screenshot for debugging
|
||||
await page.screenshot({ path: '/tmp/npm-login-page.png' }).catch(() => {});
|
||||
log.info('Screenshot saved to /tmp/npm-login-page.png');
|
||||
|
||||
// Wait for login form - try multiple selectors
|
||||
try {
|
||||
await page.waitForSelector('input[type="email"], input[name="email"], input[type="text"], input[placeholder*="email" i]', { timeout: 15000 });
|
||||
} catch (e) {
|
||||
log.warn('Login form not found with standard selectors, trying alternative...');
|
||||
await page.waitForSelector('input', { timeout: 10000 });
|
||||
}
|
||||
|
||||
// Find email input - try multiple strategies
|
||||
let emailInput = await page.$('input[type="email"]');
|
||||
if (!emailInput) emailInput = await page.$('input[name="email"]');
|
||||
if (!emailInput) emailInput = await page.$('input[placeholder*="email" i]');
|
||||
if (!emailInput) emailInput = await page.$('input[type="text"]');
|
||||
if (!emailInput) {
|
||||
// Get all inputs and try the first one
|
||||
const inputs = await page.$$('input');
|
||||
if (inputs.length > 0) emailInput = inputs[0];
|
||||
}
|
||||
|
||||
if (emailInput) {
|
||||
await emailInput.click();
|
||||
await emailInput.fill(NPM_EMAIL);
|
||||
log.info(`Filled email: ${NPM_EMAIL}`);
|
||||
} else {
|
||||
log.error('Could not find email input field');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find password input
|
||||
const passwordInput = await page.$('input[type="password"]');
|
||||
if (passwordInput) {
|
||||
await passwordInput.click();
|
||||
await passwordInput.fill(''); // Clear first
|
||||
await page.waitForTimeout(300);
|
||||
await passwordInput.fill(NPM_PASSWORD);
|
||||
await page.waitForTimeout(300);
|
||||
// Trigger events to ensure validation
|
||||
await passwordInput.evaluate(el => {
|
||||
el.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
el.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
el.dispatchEvent(new Event('blur', { bubbles: true }));
|
||||
});
|
||||
log.info('Filled password');
|
||||
} else {
|
||||
log.error('Could not find password input field');
|
||||
return false;
|
||||
}
|
||||
|
||||
await pause(page, 'Credentials filled, ready to submit');
|
||||
|
||||
// Find and click login button - try multiple strategies
|
||||
let loginButton = await page.$('button[type="submit"]');
|
||||
if (!loginButton) loginButton = await page.$('button:has-text("Sign In")');
|
||||
if (!loginButton) loginButton = await page.$('button:has-text("Login")');
|
||||
if (!loginButton) loginButton = await page.$('button:has-text("Log in")');
|
||||
if (!loginButton) {
|
||||
// Try to find any button and click it
|
||||
const buttons = await page.$$('button');
|
||||
if (buttons.length > 0) loginButton = buttons[buttons.length - 1]; // Usually submit is last
|
||||
}
|
||||
|
||||
if (loginButton) {
|
||||
await loginButton.click();
|
||||
log.info('Clicked login button');
|
||||
} else {
|
||||
// Try pressing Enter
|
||||
log.info('Login button not found, pressing Enter');
|
||||
await page.keyboard.press('Enter');
|
||||
}
|
||||
|
||||
// Wait a moment for any error messages to appear
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Check for error messages before waiting for navigation
|
||||
const errorSelectors = [
|
||||
'.error',
|
||||
'.alert-danger',
|
||||
'.alert-error',
|
||||
'[role="alert"]',
|
||||
'.text-danger',
|
||||
'.invalid-feedback',
|
||||
'[class*="error"]',
|
||||
'[class*="invalid"]'
|
||||
];
|
||||
|
||||
for (const selector of errorSelectors) {
|
||||
const errorElement = await page.$(selector);
|
||||
if (errorElement) {
|
||||
const errorText = await errorElement.textContent();
|
||||
if (errorText && errorText.trim().length > 0) {
|
||||
log.error(`Login error detected: ${errorText.trim()}`);
|
||||
await page.screenshot({ path: '/tmp/npm-login-error.png' }).catch(() => {});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for navigation or dashboard - with better error handling
|
||||
try {
|
||||
await page.waitForURL(/dashboard|hosts|proxy|login/, { timeout: 20000 });
|
||||
const currentUrl = page.url();
|
||||
|
||||
if (currentUrl.includes('login')) {
|
||||
// Check for error message again after navigation attempt
|
||||
let errorFound = false;
|
||||
for (const selector of errorSelectors) {
|
||||
const errorElement = await page.$(selector);
|
||||
if (errorElement) {
|
||||
const errorText = await errorElement.textContent();
|
||||
if (errorText && errorText.trim().length > 0) {
|
||||
log.error(`Login failed: ${errorText.trim()}`);
|
||||
errorFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!errorFound) {
|
||||
// Check page content for error messages
|
||||
const pageText = await page.textContent('body');
|
||||
if (pageText && (pageText.includes('Invalid') || pageText.includes('incorrect') || pageText.includes('error'))) {
|
||||
log.error('Login failed - error message detected in page content');
|
||||
errorFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!errorFound) {
|
||||
log.error('Login failed - still on login page (no error message found)');
|
||||
}
|
||||
await page.screenshot({ path: '/tmp/npm-login-error.png' }).catch(() => {});
|
||||
return false;
|
||||
}
|
||||
|
||||
log.success('Logged in successfully');
|
||||
await pause(page, 'After login');
|
||||
return true;
|
||||
} catch (e) {
|
||||
log.error(`Login timeout: ${e.message}`);
|
||||
// Check for errors one more time
|
||||
const pageText = await page.textContent('body').catch(() => '');
|
||||
if (pageText && (pageText.includes('Invalid') || pageText.includes('incorrect'))) {
|
||||
log.error('Login failed - invalid credentials detected');
|
||||
}
|
||||
await page.screenshot({ path: '/tmp/npm-login-timeout.png' }).catch(() => {});
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(`Login error: ${error.message}`);
|
||||
await page.screenshot({ path: '/tmp/npm-login-error.png' }).catch(() => {});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function configureProxyHost(page, domainConfig) {
|
||||
const { domain, target, description } = domainConfig;
|
||||
|
||||
log.info(`Configuring proxy host for ${domain}...`);
|
||||
|
||||
try {
|
||||
// Navigate to Proxy Hosts
|
||||
await page.goto(`${NPM_URL}/#/proxy-hosts`, { waitUntil: 'networkidle' });
|
||||
await pause(page, `At proxy hosts page for ${domain}`);
|
||||
|
||||
// Click Add Proxy Host button
|
||||
const addButton = await page.$('button:has-text("Add Proxy Host")') ||
|
||||
await page.$('a:has-text("Add Proxy Host")') ||
|
||||
await page.$('button.btn-primary');
|
||||
|
||||
if (!addButton) {
|
||||
log.warn(`Could not find Add Proxy Host button for ${domain}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
await addButton.click();
|
||||
await page.waitForTimeout(1000);
|
||||
await pause(page, `Add Proxy Host form opened for ${domain}`);
|
||||
|
||||
// Fill in domain name
|
||||
const domainInput = await page.$('input[name="domain_names"]') ||
|
||||
await page.$('input[placeholder*="domain"]') ||
|
||||
await page.$('input[type="text"]');
|
||||
|
||||
if (domainInput) {
|
||||
await domainInput.fill(domain);
|
||||
}
|
||||
|
||||
// Configure forwarding
|
||||
const schemeSelect = await page.$('select[name="forward_scheme"]') ||
|
||||
await page.$('select');
|
||||
if (schemeSelect) {
|
||||
const scheme = target.startsWith('https') ? 'https' : 'http';
|
||||
await schemeSelect.selectOption(scheme);
|
||||
}
|
||||
|
||||
const hostInput = await page.$('input[name="forward_hostname"]') ||
|
||||
await page.$('input[name="forward_host"]');
|
||||
if (hostInput) {
|
||||
const host = new URL(target).hostname;
|
||||
await hostInput.fill(host);
|
||||
}
|
||||
|
||||
const portInput = await page.$('input[name="forward_port"]');
|
||||
if (portInput) {
|
||||
const port = new URL(target).port || (target.startsWith('https') ? '443' : '80');
|
||||
await portInput.fill(port);
|
||||
}
|
||||
|
||||
await pause(page, `Form filled for ${domain}`);
|
||||
|
||||
// Configure SSL
|
||||
const sslTab = await page.$('a:has-text("SSL")') ||
|
||||
await page.$('button:has-text("SSL")');
|
||||
if (sslTab) {
|
||||
await sslTab.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Request Let's Encrypt certificate
|
||||
const requestCertButton = await page.$('button:has-text("Request a new SSL Certificate")') ||
|
||||
await page.$('button:has-text("Request SSL")');
|
||||
|
||||
if (requestCertButton) {
|
||||
await requestCertButton.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Enable Force SSL
|
||||
const forceSSL = await page.$('input[type="checkbox"][name*="force"]') ||
|
||||
await page.$('input[type="checkbox"]');
|
||||
if (forceSSL) {
|
||||
await forceSSL.check();
|
||||
}
|
||||
|
||||
// Enable HTTP/2
|
||||
const http2 = await page.$('input[type="checkbox"][name*="http2"]');
|
||||
if (http2) {
|
||||
await http2.check();
|
||||
}
|
||||
|
||||
// Enable HSTS
|
||||
const hsts = await page.$('input[type="checkbox"][name*="hsts"]');
|
||||
if (hsts) {
|
||||
await hsts.check();
|
||||
}
|
||||
|
||||
await pause(page, `SSL configured for ${domain}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Save
|
||||
const saveButton = await page.$('button:has-text("Save")') ||
|
||||
await page.$('button.btn-primary:has-text("Save")');
|
||||
if (saveButton) {
|
||||
await saveButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
log.success(`Proxy host configured for ${domain}`);
|
||||
return true;
|
||||
} else {
|
||||
log.warn(`Could not find Save button for ${domain}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
log.error(`Error configuring ${domain}: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('🔒 Nginx Proxy Manager SSL Configuration');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('');
|
||||
log.info(`NPM URL: ${NPM_URL}`);
|
||||
log.info(`Email: ${NPM_EMAIL}`);
|
||||
log.info(`Domains to configure: ${DOMAINS.length}`);
|
||||
console.log('');
|
||||
|
||||
const browser = await chromium.launch({
|
||||
headless: HEADLESS,
|
||||
ignoreHTTPSErrors: true,
|
||||
});
|
||||
|
||||
const context = await browser.newContext({
|
||||
ignoreHTTPSErrors: true,
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
try {
|
||||
// Login
|
||||
const loggedIn = await login(page);
|
||||
if (!loggedIn) {
|
||||
log.error('Failed to login. Please check credentials.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Configure each domain
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
for (const domainConfig of DOMAINS) {
|
||||
const success = await configureProxyHost(page, domainConfig);
|
||||
if (success) {
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
|
||||
// Small delay between domains
|
||||
await page.waitForTimeout(1000);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
log.info(`Configuration complete: ${successCount} succeeded, ${failCount} failed`);
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
|
||||
} catch (error) {
|
||||
log.error(`Fatal error: ${error.message}`);
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
311
scripts/nginx-proxy-manager/configure-ssl-api.js
Executable file
311
scripts/nginx-proxy-manager/configure-ssl-api.js
Executable file
@@ -0,0 +1,311 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Configure SSL certificates for all domains in Nginx Proxy Manager via API
|
||||
* This script uses the NPM API directly instead of browser automation
|
||||
*/
|
||||
|
||||
import { readFileSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import { config } from 'dotenv';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
|
||||
// Load environment variables
|
||||
config({ path: join(PROJECT_ROOT, '.env') });
|
||||
|
||||
// Configuration
|
||||
const NPM_URL = process.env.NPM_URL || 'http://192.168.11.26:81';
|
||||
const NPM_EMAIL = process.env.NPM_EMAIL || process.env.NGINX_EMAIL || 'nsatoshi2007@hotmail.com';
|
||||
const NPM_PASSWORD = process.env.NPM_PASSWORD || process.env.NGINX_PASSWORD || 'L@ker$2010';
|
||||
|
||||
// All domains to configure
|
||||
const DOMAINS = [
|
||||
// sankofa.nexus zone
|
||||
{ domain: 'sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
||||
{ domain: 'www.sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
||||
{ domain: 'phoenix.sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
||||
{ domain: 'www.phoenix.sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
||||
{ domain: 'the-order.sankofa.nexus', target: 'http://192.168.11.140:80', websocket: false },
|
||||
|
||||
// d-bis.org zone
|
||||
{ domain: 'explorer.d-bis.org', target: 'http://192.168.11.140:4000', websocket: false },
|
||||
{ domain: 'rpc-http-pub.d-bis.org', target: 'https://192.168.11.252:443', websocket: true },
|
||||
{ domain: 'rpc-ws-pub.d-bis.org', target: 'https://192.168.11.252:443', websocket: true },
|
||||
{ domain: 'rpc-http-prv.d-bis.org', target: 'https://192.168.11.251:443', websocket: true },
|
||||
{ domain: 'rpc-ws-prv.d-bis.org', target: 'https://192.168.11.251:443', websocket: true },
|
||||
{ domain: 'dbis-admin.d-bis.org', target: 'http://192.168.11.130:80', websocket: false },
|
||||
{ domain: 'dbis-api.d-bis.org', target: 'http://192.168.11.155:3000', websocket: false },
|
||||
{ domain: 'dbis-api-2.d-bis.org', target: 'http://192.168.11.156:3000', websocket: false },
|
||||
{ domain: 'secure.d-bis.org', target: 'http://192.168.11.130:80', websocket: false },
|
||||
|
||||
// mim4u.org zone
|
||||
// MIM4U - VMID 7810 (mim-web-1) @ 192.168.11.37 - Web Frontend serves main site and proxies /api/* to 7811
|
||||
{ domain: 'mim4u.org', target: 'http://192.168.11.37:80', websocket: false },
|
||||
{ domain: 'www.mim4u.org', target: 'http://192.168.11.37:80', websocket: false },
|
||||
{ domain: 'secure.mim4u.org', target: 'http://192.168.11.37:80', websocket: false },
|
||||
{ domain: 'training.mim4u.org', target: 'http://192.168.11.37:80', websocket: false },
|
||||
|
||||
// defi-oracle.io zone
|
||||
{ domain: 'rpc.public-0138.defi-oracle.io', target: 'https://192.168.11.252:443', websocket: true },
|
||||
];
|
||||
|
||||
// Helper functions
|
||||
function log(message, type = 'info') {
|
||||
const prefix = type === 'error' ? '[✗]' : type === 'success' ? '[✓]' : '[INFO]';
|
||||
console.log(`${prefix} ${message}`);
|
||||
}
|
||||
|
||||
async function getAuthToken() {
|
||||
try {
|
||||
const response = await fetch(`${NPM_URL}/api/tokens`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
identity: NPM_EMAIL,
|
||||
secret: NPM_PASSWORD
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.token) {
|
||||
log('Authentication successful', 'success');
|
||||
return data.token;
|
||||
} else {
|
||||
log(`Authentication failed: ${data.error?.message || 'Unknown error'}`, 'error');
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
log(`Authentication error: ${error.message}`, 'error');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function checkExistingProxyHost(token, domain) {
|
||||
try {
|
||||
const response = await fetch(`${NPM_URL}/api/nginx/proxy-hosts`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.result) {
|
||||
const existing = data.result.find(host =>
|
||||
host.domain_names && host.domain_names.includes(domain)
|
||||
);
|
||||
return existing;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
log(`Error checking existing host for ${domain}: ${error.message}`, 'error');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function createProxyHost(token, domainConfig) {
|
||||
const { domain, target, websocket } = domainConfig;
|
||||
const url = new URL(target);
|
||||
const scheme = url.protocol.replace(':', '');
|
||||
const hostname = url.hostname;
|
||||
const port = url.port || (scheme === 'https' ? '443' : '80');
|
||||
|
||||
const payload = {
|
||||
domain_names: [domain],
|
||||
forward_scheme: scheme,
|
||||
forward_hostname: hostname,
|
||||
forward_port: parseInt(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,
|
||||
meta: {
|
||||
letsencrypt_agree: true,
|
||||
letsencrypt_email: NPM_EMAIL
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(`${NPM_URL}/api/nginx/proxy-hosts`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.id) {
|
||||
log(`Created proxy host for ${domain} (ID: ${data.id})`, 'success');
|
||||
return data;
|
||||
} else {
|
||||
log(`Failed to create proxy host for ${domain}: ${data.error?.message || 'Unknown error'}`, 'error');
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
log(`Error creating proxy host for ${domain}: ${error.message}`, 'error');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function requestSSLCertificate(token, proxyHostId, domain) {
|
||||
try {
|
||||
// First, get the certificate ID by requesting it
|
||||
const response = await fetch(`${NPM_URL}/api/nginx/certificates`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
domain_names: [domain],
|
||||
provider: 'letsencrypt',
|
||||
letsencrypt_email: NPM_EMAIL,
|
||||
letsencrypt_agree: true
|
||||
})
|
||||
});
|
||||
|
||||
const certData = await response.json();
|
||||
|
||||
if (certData.id) {
|
||||
log(`Requested SSL certificate for ${domain} (Cert ID: ${certData.id})`, 'success');
|
||||
|
||||
// Update proxy host to use this certificate
|
||||
const updateResponse = await fetch(`${NPM_URL}/api/nginx/proxy-hosts/${proxyHostId}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
certificate_id: certData.id,
|
||||
ssl_forced: true
|
||||
})
|
||||
});
|
||||
|
||||
const updateData = await updateResponse.json();
|
||||
|
||||
if (updateData.id) {
|
||||
log(`Updated proxy host ${proxyHostId} with SSL certificate`, 'success');
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
log(`Failed to request SSL certificate for ${domain}: ${certData.error?.message || 'Unknown error'}`, 'error');
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
log(`Error requesting SSL certificate for ${domain}: ${error.message}`, 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('🔒 Nginx Proxy Manager SSL Configuration (API)');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('');
|
||||
log(`NPM URL: ${NPM_URL}`);
|
||||
log(`Email: ${NPM_EMAIL}`);
|
||||
log(`Domains to configure: ${DOMAINS.length}`);
|
||||
console.log('');
|
||||
|
||||
// Get authentication token
|
||||
const token = await getAuthToken();
|
||||
if (!token) {
|
||||
log('Cannot proceed without authentication token', 'error');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
let skipCount = 0;
|
||||
|
||||
// Configure each domain
|
||||
for (const domainConfig of DOMAINS) {
|
||||
const { domain } = domainConfig;
|
||||
|
||||
log(`Processing ${domain}...`);
|
||||
|
||||
// Check if already exists
|
||||
const existing = await checkExistingProxyHost(token, domain);
|
||||
|
||||
if (existing) {
|
||||
log(`Proxy host for ${domain} already exists (ID: ${existing.id}), skipping creation`, 'info');
|
||||
|
||||
// Check if it has SSL certificate
|
||||
if (!existing.certificate_id || existing.certificate_id === 0) {
|
||||
log(`Requesting SSL certificate for existing proxy host ${domain}...`);
|
||||
const sslSuccess = await requestSSLCertificate(token, existing.id, domain);
|
||||
if (sslSuccess) {
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
}
|
||||
} else {
|
||||
log(`SSL certificate already configured for ${domain}`, 'success');
|
||||
successCount++;
|
||||
}
|
||||
|
||||
skipCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create proxy host
|
||||
const proxyHost = await createProxyHost(token, domainConfig);
|
||||
|
||||
if (proxyHost) {
|
||||
// Request SSL certificate
|
||||
log(`Requesting SSL certificate for ${domain}...`);
|
||||
const sslSuccess = await requestSSLCertificate(token, proxyHost.id, domain);
|
||||
|
||||
if (sslSuccess) {
|
||||
successCount++;
|
||||
log(`✓ Successfully configured ${domain}`, 'success');
|
||||
} else {
|
||||
failCount++;
|
||||
log(`✗ Failed to configure SSL for ${domain}`, 'error');
|
||||
}
|
||||
} else {
|
||||
failCount++;
|
||||
log(`✗ Failed to create proxy host for ${domain}`, 'error');
|
||||
}
|
||||
|
||||
// Small delay between requests
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('📊 Configuration Summary');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log(`✅ Successful: ${successCount}`);
|
||||
console.log(`⚠️ Skipped: ${skipCount}`);
|
||||
console.log(`✗ Failed: ${failCount}`);
|
||||
console.log(`📋 Total: ${DOMAINS.length}`);
|
||||
console.log('');
|
||||
|
||||
if (failCount === 0) {
|
||||
log('All domains configured successfully!', 'success');
|
||||
console.log('');
|
||||
log('Note: SSL certificates may take 1-2 minutes to be issued by Let\'s Encrypt');
|
||||
log('Run verification: bash scripts/nginx-proxy-manager/verify-ssl-config.sh');
|
||||
} else {
|
||||
log('Some domains failed to configure. Check errors above.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
log(`Fatal error: ${error.message}`, 'error');
|
||||
process.exit(1);
|
||||
});
|
||||
119
scripts/nginx-proxy-manager/create-npmplus-defi-oracle-hosts.sh
Executable file
119
scripts/nginx-proxy-manager/create-npmplus-defi-oracle-hosts.sh
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create NPMplus proxy hosts for rpc.defi-oracle.io and wss.defi-oracle.io if they don't exist.
|
||||
# Uses .env for NPM_URL, NPM_EMAIL, NPM_PASSWORD. Run from repo root or script dir.
|
||||
# Backend: VMID 2400 (${RPC_THIRDWEB_PRIMARY:-${RPC_THIRDWEB_PRIMARY:-192.168.11.240}}:443 HTTPS, WebSocket enabled).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Preserve NPM credentials from environment so "export NPM_PASSWORD=...; ./script" works
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
set +u
|
||||
set -a
|
||||
# shellcheck source=/dev/null
|
||||
source "$PROJECT_ROOT/.env"
|
||||
set +a
|
||||
set -u
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
fi
|
||||
|
||||
# Default .167: NPMplus (VMID 10233) reachable on ${IP_NPMPLUS:-${IP_NPMPLUS:-192.168.11.167}}:81; set NPM_URL in .env to override
|
||||
NPM_URL="${NPM_URL:-https://${IP_NPMPLUS}:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-admin@example.org}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "❌ NPM_PASSWORD is required. Set it in .env"
|
||||
echo " Example: NPM_PASSWORD=your-password in $PROJECT_ROOT/.env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Authenticate (use jq to build JSON so password is safely escaped)
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$AUTH_JSON")
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || true)
|
||||
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
echo "❌ NPMplus authentication failed. Check NPM_URL, NPM_EMAIL, NPM_PASSWORD in .env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
# NPMplus API uses forward_host (IP string) for proxy host create/update
|
||||
create_if_missing() {
|
||||
local domain=$1
|
||||
local forward_host=$2
|
||||
local forward_port=$3
|
||||
local scheme=$4
|
||||
local websocket=$5
|
||||
|
||||
HOST_ID=$(echo "$PROXY_HOSTS_JSON" | jq -r ".[] | select(.domain_names | type == \"array\") | select(.domain_names[] == \"$domain\") | .id" 2>/dev/null | head -n1 || true)
|
||||
|
||||
if [ -n "$HOST_ID" ] && [ "$HOST_ID" != "null" ]; then
|
||||
echo " ✓ $domain already exists (ID: $HOST_ID)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo " ➕ Creating proxy host: $domain → $scheme://$forward_host:$forward_port (WebSocket: $websocket)"
|
||||
# NPM API create accepts only specific properties; extra ones cause "data must NOT have additional properties"
|
||||
# Minimal set: domain_names, forward_scheme, forward_host, forward_port, allow_websocket_upgrade
|
||||
CREATE_PAYLOAD=$(jq -n \
|
||||
--arg domain "$domain" \
|
||||
--arg scheme "$scheme" \
|
||||
--arg forward_host "$forward_host" \
|
||||
--argjson forward_port "$forward_port" \
|
||||
--argjson websocket "$([ "$websocket" = "true" ] && echo true || echo false)" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: $scheme,
|
||||
forward_host: $forward_host,
|
||||
forward_port: $forward_port,
|
||||
allow_websocket_upgrade: $websocket
|
||||
}')
|
||||
RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$CREATE_PAYLOAD")
|
||||
|
||||
NEW_ID=$(echo "$RESPONSE" | jq -r '.id // empty' 2>/dev/null || true)
|
||||
if [ -n "$NEW_ID" ] && [ "$NEW_ID" != "null" ]; then
|
||||
echo " ✓ Created $domain (ID: $NEW_ID). Request SSL in NPMplus UI or run request-npmplus-certificates.sh for this host."
|
||||
return 0
|
||||
fi
|
||||
|
||||
ERROR=$(echo "$RESPONSE" | jq -r '.message // .error // "Unknown error"' 2>/dev/null || echo "$RESPONSE")
|
||||
echo " ❌ Failed to create $domain: $ERROR"
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔧 Create NPMplus Defi Oracle RPC proxy hosts (from .env)"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# explorer.defi-oracle.io → same as explorer.d-bis.org (VMID 5000 @ ${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0})
|
||||
create_if_missing "explorer.defi-oracle.io" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "http" "false" || true
|
||||
# rpc.defi-oracle.io / wss.defi-oracle.io → same as rpc-http-pub / rpc-ws-pub (VMID 2201 @ ${RPC_PUBLIC_1:-${RPC_PUBLIC_1:-192.168.11.221}})
|
||||
create_if_missing "rpc.defi-oracle.io" "${RPC_PUBLIC_1:-${RPC_PUBLIC_1:-192.168.11.221}}" "8545" "http" "true" || true
|
||||
create_if_missing "wss.defi-oracle.io" "${RPC_PUBLIC_1:-${RPC_PUBLIC_1:-192.168.11.221}}" "8546" "http" "true" || true
|
||||
|
||||
echo ""
|
||||
echo "Done. Run update-npmplus-proxy-hosts-api.sh to sync forward_host/port, then request SSL in NPMplus for new hosts if needed."
|
||||
echo ""
|
||||
113
scripts/nginx-proxy-manager/create-npmplus-defi-oracle-hosts.sh.bak
Executable file
113
scripts/nginx-proxy-manager/create-npmplus-defi-oracle-hosts.sh.bak
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create NPMplus proxy hosts for rpc.defi-oracle.io and wss.defi-oracle.io if they don't exist.
|
||||
# Uses .env for NPM_URL, NPM_EMAIL, NPM_PASSWORD. Run from repo root or script dir.
|
||||
# Backend: VMID 2400 (192.168.11.240:443 HTTPS, WebSocket enabled).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Preserve NPM credentials from environment so "export NPM_PASSWORD=...; ./script" works
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
set +u
|
||||
set -a
|
||||
# shellcheck source=/dev/null
|
||||
source "$PROJECT_ROOT/.env"
|
||||
set +a
|
||||
set -u
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
fi
|
||||
|
||||
# Default .167: NPMplus (VMID 10233) reachable on 192.168.11.167:81; set NPM_URL in .env to override
|
||||
NPM_URL="${NPM_URL:-https://192.168.11.167:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-admin@example.org}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "❌ NPM_PASSWORD is required. Set it in .env"
|
||||
echo " Example: NPM_PASSWORD=your-password in $PROJECT_ROOT/.env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Authenticate (use jq to build JSON so password is safely escaped)
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$AUTH_JSON")
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || true)
|
||||
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
echo "❌ NPMplus authentication failed. Check NPM_URL, NPM_EMAIL, NPM_PASSWORD in .env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
# NPMplus API uses forward_host (IP string) for proxy host create/update
|
||||
create_if_missing() {
|
||||
local domain=$1
|
||||
local forward_host=$2
|
||||
local forward_port=$3
|
||||
local scheme=$4
|
||||
local websocket=$5
|
||||
|
||||
HOST_ID=$(echo "$PROXY_HOSTS_JSON" | jq -r ".[] | select(.domain_names | type == \"array\") | select(.domain_names[] == \"$domain\") | .id" 2>/dev/null | head -n1 || true)
|
||||
|
||||
if [ -n "$HOST_ID" ] && [ "$HOST_ID" != "null" ]; then
|
||||
echo " ✓ $domain already exists (ID: $HOST_ID)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo " ➕ Creating proxy host: $domain → $scheme://$forward_host:$forward_port (WebSocket: $websocket)"
|
||||
# NPM API create accepts only specific properties; extra ones cause "data must NOT have additional properties"
|
||||
# Minimal set: domain_names, forward_scheme, forward_host, forward_port, allow_websocket_upgrade
|
||||
CREATE_PAYLOAD=$(jq -n \
|
||||
--arg domain "$domain" \
|
||||
--arg scheme "$scheme" \
|
||||
--arg forward_host "$forward_host" \
|
||||
--argjson forward_port "$forward_port" \
|
||||
--argjson websocket "$([ "$websocket" = "true" ] && echo true || echo false)" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: $scheme,
|
||||
forward_host: $forward_host,
|
||||
forward_port: $forward_port,
|
||||
allow_websocket_upgrade: $websocket
|
||||
}')
|
||||
RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$CREATE_PAYLOAD")
|
||||
|
||||
NEW_ID=$(echo "$RESPONSE" | jq -r '.id // empty' 2>/dev/null || true)
|
||||
if [ -n "$NEW_ID" ] && [ "$NEW_ID" != "null" ]; then
|
||||
echo " ✓ Created $domain (ID: $NEW_ID). Request SSL in NPMplus UI or run request-npmplus-certificates.sh for this host."
|
||||
return 0
|
||||
fi
|
||||
|
||||
ERROR=$(echo "$RESPONSE" | jq -r '.message // .error // "Unknown error"' 2>/dev/null || echo "$RESPONSE")
|
||||
echo " ❌ Failed to create $domain: $ERROR"
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔧 Create NPMplus Defi Oracle RPC proxy hosts (from .env)"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# explorer.defi-oracle.io → same as explorer.d-bis.org (VMID 5000 @ 192.168.11.140)
|
||||
create_if_missing "explorer.defi-oracle.io" "192.168.11.140" "80" "http" "false" || true
|
||||
# rpc.defi-oracle.io / wss.defi-oracle.io → same as rpc-http-pub / rpc-ws-pub (VMID 2201 @ 192.168.11.221)
|
||||
create_if_missing "rpc.defi-oracle.io" "192.168.11.221" "8545" "http" "true" || true
|
||||
create_if_missing "wss.defi-oracle.io" "192.168.11.221" "8546" "http" "true" || true
|
||||
|
||||
echo ""
|
||||
echo "Done. Run update-npmplus-proxy-hosts-api.sh to sync forward_host/port, then request SSL in NPMplus for new hosts if needed."
|
||||
echo ""
|
||||
117
scripts/nginx-proxy-manager/create-npmplus-rpc-d-bis-hosts.sh
Executable file
117
scripts/nginx-proxy-manager/create-npmplus-rpc-d-bis-hosts.sh
Executable file
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create NPMplus proxy hosts for rpc.d-bis.org, rpc2.d-bis.org and WS variants if they don't exist.
|
||||
# Uses .env for NPM_URL, NPM_EMAIL, NPM_PASSWORD. Run from repo root or script dir.
|
||||
# Backend: VMID 2201 (${RPC_PUBLIC_1:-${RPC_PUBLIC_1:-192.168.11.221}}:8545 HTTP, :8546 WebSocket, besu-rpc-public-1).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Preserve NPM credentials from environment so "export NPM_PASSWORD=...; ./script" works
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
set +u
|
||||
set -a
|
||||
# shellcheck source=/dev/null
|
||||
source "$PROJECT_ROOT/.env"
|
||||
set +a
|
||||
set -u
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
fi
|
||||
|
||||
# Default .167: NPMplus (VMID 10233) reachable on ${IP_NPMPLUS:-${IP_NPMPLUS:-192.168.11.167}}:81; set NPM_URL in .env to override
|
||||
NPM_URL="${NPM_URL:-https://${IP_NPMPLUS}:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-admin@example.org}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "❌ NPM_PASSWORD is required. Set it in .env"
|
||||
echo " Example: NPM_PASSWORD=your-password in $PROJECT_ROOT/.env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Authenticate (use jq to build JSON so password is safely escaped)
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$AUTH_JSON")
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || true)
|
||||
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
echo "❌ NPMplus authentication failed. Check NPM_URL, NPM_EMAIL, NPM_PASSWORD in .env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
# NPMplus API uses forward_host (IP string) for proxy host create/update
|
||||
create_if_missing() {
|
||||
local domain=$1
|
||||
local forward_host=$2
|
||||
local forward_port=$3
|
||||
local scheme=$4
|
||||
local websocket=$5
|
||||
|
||||
HOST_ID=$(echo "$PROXY_HOSTS_JSON" | jq -r ".[] | select(.domain_names | type == \"array\") | select(.domain_names[] == \"$domain\") | .id" 2>/dev/null | head -n1 || true)
|
||||
|
||||
if [ -n "$HOST_ID" ] && [ "$HOST_ID" != "null" ]; then
|
||||
echo " ✓ $domain already exists (ID: $HOST_ID)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo " ➕ Creating proxy host: $domain → $scheme://$forward_host:$forward_port (WebSocket: $websocket)"
|
||||
CREATE_PAYLOAD=$(jq -n \
|
||||
--arg domain "$domain" \
|
||||
--arg scheme "$scheme" \
|
||||
--arg forward_host "$forward_host" \
|
||||
--argjson forward_port "$forward_port" \
|
||||
--argjson websocket "$([ "$websocket" = "true" ] && echo true || echo false)" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: $scheme,
|
||||
forward_host: $forward_host,
|
||||
forward_port: $forward_port,
|
||||
allow_websocket_upgrade: $websocket
|
||||
}')
|
||||
RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$CREATE_PAYLOAD")
|
||||
|
||||
NEW_ID=$(echo "$RESPONSE" | jq -r '.id // empty' 2>/dev/null || true)
|
||||
if [ -n "$NEW_ID" ] && [ "$NEW_ID" != "null" ]; then
|
||||
echo " ✓ Created $domain (ID: $NEW_ID). Request SSL in NPMplus UI or run request-npmplus-certificates.sh for this host."
|
||||
return 0
|
||||
fi
|
||||
|
||||
ERROR=$(echo "$RESPONSE" | jq -r '.message // .error // "Unknown error"' 2>/dev/null || echo "$RESPONSE")
|
||||
echo " ❌ Failed to create $domain: $ERROR"
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔧 Create NPMplus rpc.d-bis.org / rpc2.d-bis.org proxy hosts (from .env)"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# rpc.d-bis.org / rpc2.d-bis.org and WS variants → VMID 2201 @ ${RPC_PUBLIC_1:-${RPC_PUBLIC_1:-192.168.11.221}}
|
||||
create_if_missing "rpc.d-bis.org" "${RPC_PUBLIC_1:-${RPC_PUBLIC_1:-192.168.11.221}}" "8545" "http" "true" || true
|
||||
create_if_missing "rpc2.d-bis.org" "${RPC_PUBLIC_1:-${RPC_PUBLIC_1:-192.168.11.221}}" "8545" "http" "true" || true
|
||||
create_if_missing "ws.rpc.d-bis.org" "${RPC_PUBLIC_1:-${RPC_PUBLIC_1:-192.168.11.221}}" "8546" "http" "true" || true
|
||||
create_if_missing "ws.rpc2.d-bis.org" "${RPC_PUBLIC_1:-${RPC_PUBLIC_1:-192.168.11.221}}" "8546" "http" "true" || true
|
||||
|
||||
echo ""
|
||||
echo "Done. Run update-npmplus-proxy-hosts-api.sh to sync forward_host/port, then request SSL in NPMplus for new hosts if needed."
|
||||
echo ""
|
||||
111
scripts/nginx-proxy-manager/create-npmplus-rpc-d-bis-hosts.sh.bak
Executable file
111
scripts/nginx-proxy-manager/create-npmplus-rpc-d-bis-hosts.sh.bak
Executable file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env bash
|
||||
# Create NPMplus proxy hosts for rpc.d-bis.org, rpc2.d-bis.org and WS variants if they don't exist.
|
||||
# Uses .env for NPM_URL, NPM_EMAIL, NPM_PASSWORD. Run from repo root or script dir.
|
||||
# Backend: VMID 2201 (192.168.11.221:8545 HTTP, :8546 WebSocket, besu-rpc-public-1).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Preserve NPM credentials from environment so "export NPM_PASSWORD=...; ./script" works
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
set +u
|
||||
set -a
|
||||
# shellcheck source=/dev/null
|
||||
source "$PROJECT_ROOT/.env"
|
||||
set +a
|
||||
set -u
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
fi
|
||||
|
||||
# Default .167: NPMplus (VMID 10233) reachable on 192.168.11.167:81; set NPM_URL in .env to override
|
||||
NPM_URL="${NPM_URL:-https://192.168.11.167:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-admin@example.org}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "❌ NPM_PASSWORD is required. Set it in .env"
|
||||
echo " Example: NPM_PASSWORD=your-password in $PROJECT_ROOT/.env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Authenticate (use jq to build JSON so password is safely escaped)
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$AUTH_JSON")
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || true)
|
||||
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
echo "❌ NPMplus authentication failed. Check NPM_URL, NPM_EMAIL, NPM_PASSWORD in .env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
# NPMplus API uses forward_host (IP string) for proxy host create/update
|
||||
create_if_missing() {
|
||||
local domain=$1
|
||||
local forward_host=$2
|
||||
local forward_port=$3
|
||||
local scheme=$4
|
||||
local websocket=$5
|
||||
|
||||
HOST_ID=$(echo "$PROXY_HOSTS_JSON" | jq -r ".[] | select(.domain_names | type == \"array\") | select(.domain_names[] == \"$domain\") | .id" 2>/dev/null | head -n1 || true)
|
||||
|
||||
if [ -n "$HOST_ID" ] && [ "$HOST_ID" != "null" ]; then
|
||||
echo " ✓ $domain already exists (ID: $HOST_ID)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo " ➕ Creating proxy host: $domain → $scheme://$forward_host:$forward_port (WebSocket: $websocket)"
|
||||
CREATE_PAYLOAD=$(jq -n \
|
||||
--arg domain "$domain" \
|
||||
--arg scheme "$scheme" \
|
||||
--arg forward_host "$forward_host" \
|
||||
--argjson forward_port "$forward_port" \
|
||||
--argjson websocket "$([ "$websocket" = "true" ] && echo true || echo false)" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: $scheme,
|
||||
forward_host: $forward_host,
|
||||
forward_port: $forward_port,
|
||||
allow_websocket_upgrade: $websocket
|
||||
}')
|
||||
RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$CREATE_PAYLOAD")
|
||||
|
||||
NEW_ID=$(echo "$RESPONSE" | jq -r '.id // empty' 2>/dev/null || true)
|
||||
if [ -n "$NEW_ID" ] && [ "$NEW_ID" != "null" ]; then
|
||||
echo " ✓ Created $domain (ID: $NEW_ID). Request SSL in NPMplus UI or run request-npmplus-certificates.sh for this host."
|
||||
return 0
|
||||
fi
|
||||
|
||||
ERROR=$(echo "$RESPONSE" | jq -r '.message // .error // "Unknown error"' 2>/dev/null || echo "$RESPONSE")
|
||||
echo " ❌ Failed to create $domain: $ERROR"
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔧 Create NPMplus rpc.d-bis.org / rpc2.d-bis.org proxy hosts (from .env)"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# rpc.d-bis.org / rpc2.d-bis.org and WS variants → VMID 2201 @ 192.168.11.221
|
||||
create_if_missing "rpc.d-bis.org" "192.168.11.221" "8545" "http" "true" || true
|
||||
create_if_missing "rpc2.d-bis.org" "192.168.11.221" "8545" "http" "true" || true
|
||||
create_if_missing "ws.rpc.d-bis.org" "192.168.11.221" "8546" "http" "true" || true
|
||||
create_if_missing "ws.rpc2.d-bis.org" "192.168.11.221" "8546" "http" "true" || true
|
||||
|
||||
echo ""
|
||||
echo "Done. Run update-npmplus-proxy-hosts-api.sh to sync forward_host/port, then request SSL in NPMplus for new hosts if needed."
|
||||
echo ""
|
||||
123
scripts/nginx-proxy-manager/delete-sankofa-proxy-hosts.sh
Executable file
123
scripts/nginx-proxy-manager/delete-sankofa-proxy-hosts.sh
Executable file
@@ -0,0 +1,123 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Delete sankofa.nexus and phoenix.sankofa.nexus proxy hosts from NPMplus
|
||||
# These were incorrectly routing to Blockscout and need to be removed
|
||||
|
||||
set -e
|
||||
|
||||
# Load environment variables
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
export $(cat "$PROJECT_ROOT/.env" | grep -v '^#' | xargs)
|
||||
fi
|
||||
|
||||
NPM_URL="${NPM_URL:-https://192.168.0.166:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-nsatoshi2007@hotmail.com}"
|
||||
# NPM_PASSWORD should come from environment variable
|
||||
if [ -z "${NPM_PASSWORD:-}" ]; then
|
||||
log_error "NPM_PASSWORD environment variable is required"
|
||||
log_info "Set it in ~/.env file: NPM_PASSWORD=your-password"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Domains to delete
|
||||
DOMAINS_TO_DELETE=(
|
||||
"sankofa.nexus"
|
||||
"phoenix.sankofa.nexus"
|
||||
"the-order.sankofa.nexus"
|
||||
"www.sankofa.nexus"
|
||||
"www.phoenix.sankofa.nexus"
|
||||
)
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🗑️ Deleting Sankofa Proxy Hosts from NPMplus"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Authenticate
|
||||
echo "🔐 Authenticating to NPMplus..."
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"identity\":\"$NPM_EMAIL\",\"secret\":\"$NPM_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 ""
|
||||
|
||||
# Get all proxy hosts
|
||||
echo "📋 Fetching proxy hosts..."
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Failed to fetch proxy hosts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Delete each domain
|
||||
deleted_count=0
|
||||
not_found_count=0
|
||||
failed_count=0
|
||||
|
||||
for domain in "${DOMAINS_TO_DELETE[@]}"; do
|
||||
echo "🔍 Searching for proxy host: $domain"
|
||||
|
||||
# Find the host ID
|
||||
HOST_ID=$(echo "$PROXY_HOSTS_JSON" | jq -r ".result[] | select(.domain_names[] == \"$domain\") | .id" 2>/dev/null | head -n1 || echo "")
|
||||
|
||||
if [ -z "$HOST_ID" ] || [ "$HOST_ID" = "null" ]; then
|
||||
echo " ⚠️ Not found (may already be deleted)"
|
||||
not_found_count=$((not_found_count + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
echo " 📍 Found (ID: $HOST_ID)"
|
||||
|
||||
# Delete the proxy host
|
||||
DELETE_RESPONSE=$(curl -s -k -X DELETE "$NPM_URL/api/nginx/proxy-hosts/$HOST_ID" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
# Check if deletion was successful
|
||||
if echo "$DELETE_RESPONSE" | jq -e '.success == true' > /dev/null 2>&1 || \
|
||||
echo "$DELETE_RESPONSE" | jq -e '.id' > /dev/null 2>&1 || \
|
||||
[ -z "$DELETE_RESPONSE" ] || [ "$DELETE_RESPONSE" = "{}" ]; then
|
||||
echo " ✅ Deleted successfully"
|
||||
deleted_count=$((deleted_count + 1))
|
||||
else
|
||||
ERROR=$(echo "$DELETE_RESPONSE" | jq -r '.error.message // .error // "Unknown error"' 2>/dev/null || echo "$DELETE_RESPONSE")
|
||||
echo " ❌ Failed to delete: $ERROR"
|
||||
failed_count=$((failed_count + 1))
|
||||
fi
|
||||
|
||||
echo ""
|
||||
sleep 1 # Rate limiting
|
||||
done
|
||||
|
||||
# Summary
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📊 Summary"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "✅ Deleted: $deleted_count"
|
||||
echo "⚠️ Not found: $not_found_count"
|
||||
echo "❌ Failed: $failed_count"
|
||||
echo ""
|
||||
|
||||
if [ $deleted_count -gt 0 ] || [ $not_found_count -gt 0 ]; then
|
||||
echo "✅ Sankofa proxy hosts have been removed from NPMplus"
|
||||
echo ""
|
||||
echo "ℹ️ These domains will no longer route to Blockscout."
|
||||
echo " When Sankofa services are deployed, re-add them to"
|
||||
echo " configure-npmplus-domains.js with the correct backend IPs."
|
||||
else
|
||||
echo "⚠️ No proxy hosts were deleted"
|
||||
fi
|
||||
56
scripts/nginx-proxy-manager/diagnose-npmplus-error.sh
Executable file
56
scripts/nginx-proxy-manager/diagnose-npmplus-error.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
# Diagnose and fix the docker compose error in NPMplus installation
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔍 Diagnosing NPMplus Installation Error"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
echo "The error 'no configuration file provided: not found' occurs when:"
|
||||
echo " 1. docker compose is run from wrong directory"
|
||||
echo " 2. compose.yaml file wasn't created/downloaded"
|
||||
echo " 3. Installation script failed partway through"
|
||||
echo ""
|
||||
|
||||
echo "📋 Solution:"
|
||||
echo ""
|
||||
echo "If you're running the Proxmox helper script and it fails:"
|
||||
echo ""
|
||||
echo "1. Check which container was created (if any):"
|
||||
echo " ssh root@${PROXMOX_HOST_R630_01:-192.168.11.11} 'pct list | tail -5'"
|
||||
echo ""
|
||||
echo "2. If a container exists, fix it:"
|
||||
echo " bash scripts/nginx-proxy-manager/fix-npmplus-install.sh ${PROXMOX_HOST_R630_01:-192.168.11.11} <CONTAINER_ID>"
|
||||
echo ""
|
||||
echo "3. If no container exists, the installation failed early."
|
||||
echo " Try running the helper script again:"
|
||||
echo " ssh root@${PROXMOX_HOST_R630_01:-192.168.11.11}"
|
||||
echo " bash -c \"\$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/npmplus.sh)\""
|
||||
echo ""
|
||||
echo "4. If it keeps failing, use the direct installation:"
|
||||
echo " bash scripts/nginx-proxy-manager/install-npmplus-direct.sh"
|
||||
echo ""
|
||||
|
||||
# Check for any stopped containers that might be NPMplus
|
||||
echo "🔍 Checking for potential NPMplus containers..."
|
||||
STOPPED_CTS=$(ssh root@${PROXMOX_HOST_R630_01:-192.168.11.11} "pct list | grep stopped | tail -3" || echo "")
|
||||
if [ -n "$STOPPED_CTS" ]; then
|
||||
echo "Found stopped containers:"
|
||||
echo "$STOPPED_CTS"
|
||||
echo ""
|
||||
echo "To check if any are NPMplus:"
|
||||
echo " ssh root@${PROXMOX_HOST_R630_01:-192.168.11.11} 'pct config <CTID> | grep hostname'"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "💡 Recommended: Use the complete migration script which handles errors:"
|
||||
echo " bash scripts/nginx-proxy-manager/complete-migration.sh"
|
||||
echo ""
|
||||
50
scripts/nginx-proxy-manager/diagnose-npmplus-error.sh.bak
Executable file
50
scripts/nginx-proxy-manager/diagnose-npmplus-error.sh.bak
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Diagnose and fix the docker compose error in NPMplus installation
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔍 Diagnosing NPMplus Installation Error"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
echo "The error 'no configuration file provided: not found' occurs when:"
|
||||
echo " 1. docker compose is run from wrong directory"
|
||||
echo " 2. compose.yaml file wasn't created/downloaded"
|
||||
echo " 3. Installation script failed partway through"
|
||||
echo ""
|
||||
|
||||
echo "📋 Solution:"
|
||||
echo ""
|
||||
echo "If you're running the Proxmox helper script and it fails:"
|
||||
echo ""
|
||||
echo "1. Check which container was created (if any):"
|
||||
echo " ssh root@192.168.11.11 'pct list | tail -5'"
|
||||
echo ""
|
||||
echo "2. If a container exists, fix it:"
|
||||
echo " bash scripts/nginx-proxy-manager/fix-npmplus-install.sh 192.168.11.11 <CONTAINER_ID>"
|
||||
echo ""
|
||||
echo "3. If no container exists, the installation failed early."
|
||||
echo " Try running the helper script again:"
|
||||
echo " ssh root@192.168.11.11"
|
||||
echo " bash -c \"\$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/npmplus.sh)\""
|
||||
echo ""
|
||||
echo "4. If it keeps failing, use the direct installation:"
|
||||
echo " bash scripts/nginx-proxy-manager/install-npmplus-direct.sh"
|
||||
echo ""
|
||||
|
||||
# Check for any stopped containers that might be NPMplus
|
||||
echo "🔍 Checking for potential NPMplus containers..."
|
||||
STOPPED_CTS=$(ssh root@192.168.11.11 "pct list | grep stopped | tail -3" || echo "")
|
||||
if [ -n "$STOPPED_CTS" ]; then
|
||||
echo "Found stopped containers:"
|
||||
echo "$STOPPED_CTS"
|
||||
echo ""
|
||||
echo "To check if any are NPMplus:"
|
||||
echo " ssh root@192.168.11.11 'pct config <CTID> | grep hostname'"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "💡 Recommended: Use the complete migration script which handles errors:"
|
||||
echo " bash scripts/nginx-proxy-manager/complete-migration.sh"
|
||||
echo ""
|
||||
74
scripts/nginx-proxy-manager/manual-ssl-config-guide.sh
Executable file
74
scripts/nginx-proxy-manager/manual-ssl-config-guide.sh
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
# Manual SSL Configuration Guide for Nginx Proxy Manager
|
||||
# This script provides step-by-step instructions and can help verify configuration
|
||||
|
||||
set -e
|
||||
|
||||
NPM_URL="http://${IP_NGINX_LEGACY:-192.168.11.26}:81"
|
||||
DOMAINS_FILE="/tmp/npm-domains-list.txt"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📋 Nginx Proxy Manager Manual SSL Configuration Guide"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Since automated login is having issues, here's a manual approach:"
|
||||
echo ""
|
||||
echo "1. Open Nginx Proxy Manager in your browser:"
|
||||
echo " $NPM_URL"
|
||||
echo ""
|
||||
echo "2. Log in with your credentials"
|
||||
echo ""
|
||||
echo "3. For each domain below, follow these steps:"
|
||||
echo " a. Click 'Proxy Hosts' → 'Add Proxy Host'"
|
||||
echo " b. Fill in Details tab"
|
||||
echo " c. Go to SSL tab → Request Let's Encrypt certificate"
|
||||
echo " d. Enable Force SSL, HTTP/2, HSTS"
|
||||
echo " e. Save"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📝 Domains to Configure (19 total):"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
cat > "$DOMAINS_FILE" << 'DOMAINS'
|
||||
sankofa.nexus → http://${IP_BLOCKSCOUT}:80
|
||||
www.sankofa.nexus → http://${IP_BLOCKSCOUT}:80
|
||||
phoenix.sankofa.nexus → http://${IP_BLOCKSCOUT}:80
|
||||
www.phoenix.sankofa.nexus → http://${IP_BLOCKSCOUT}:80
|
||||
the-order.sankofa.nexus → http://${IP_BLOCKSCOUT}:80
|
||||
explorer.d-bis.org → http://${IP_BLOCKSCOUT}:80
|
||||
rpc-http-pub.d-bis.org → https://${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}:443 (WebSocket)
|
||||
rpc-ws-pub.d-bis.org → https://${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}:443 (WebSocket)
|
||||
rpc-http-prv.d-bis.org → https://${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}:443 (WebSocket)
|
||||
rpc-ws-prv.d-bis.org → https://${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}:443 (WebSocket)
|
||||
dbis-admin.d-bis.org → http://${IP_DBIS_FRONTEND:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-192.168.11.13}}}}}0}:80
|
||||
dbis-api.d-bis.org → http://${IP_DBIS_API:-${IP_DBIS_API:-192.168.11.155}}:3000
|
||||
dbis-api-2.d-bis.org → http://${IP_DBIS_API_2:-${IP_DBIS_API_2:-192.168.11.156}}:3000
|
||||
secure.d-bis.org → http://${IP_DBIS_FRONTEND:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-192.168.11.13}}}}}0}:80
|
||||
mim4u.org → http://${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}:80
|
||||
www.mim4u.org → http://${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}:80
|
||||
secure.mim4u.org → http://${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}:80
|
||||
training.mim4u.org → http://${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}:80
|
||||
rpc.public-0138.defi-oracle.io → https://${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}:443
|
||||
DOMAINS
|
||||
|
||||
cat "$DOMAINS_FILE" | nl -w2 -s'. '
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "✅ After configuration, verify with:"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "curl -I https://explorer.d-bis.org"
|
||||
echo "curl -I https://sankofa.nexus"
|
||||
echo ""
|
||||
echo "Full guide: docs/04-configuration/NGINX_PROXY_MANAGER_SSL_CONFIGURATION.md"
|
||||
echo ""
|
||||
68
scripts/nginx-proxy-manager/manual-ssl-config-guide.sh.bak
Executable file
68
scripts/nginx-proxy-manager/manual-ssl-config-guide.sh.bak
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Manual SSL Configuration Guide for Nginx Proxy Manager
|
||||
# This script provides step-by-step instructions and can help verify configuration
|
||||
|
||||
set -e
|
||||
|
||||
NPM_URL="http://192.168.11.26:81"
|
||||
DOMAINS_FILE="/tmp/npm-domains-list.txt"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📋 Nginx Proxy Manager Manual SSL Configuration Guide"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Since automated login is having issues, here's a manual approach:"
|
||||
echo ""
|
||||
echo "1. Open Nginx Proxy Manager in your browser:"
|
||||
echo " $NPM_URL"
|
||||
echo ""
|
||||
echo "2. Log in with your credentials"
|
||||
echo ""
|
||||
echo "3. For each domain below, follow these steps:"
|
||||
echo " a. Click 'Proxy Hosts' → 'Add Proxy Host'"
|
||||
echo " b. Fill in Details tab"
|
||||
echo " c. Go to SSL tab → Request Let's Encrypt certificate"
|
||||
echo " d. Enable Force SSL, HTTP/2, HSTS"
|
||||
echo " e. Save"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📝 Domains to Configure (19 total):"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
cat > "$DOMAINS_FILE" << 'DOMAINS'
|
||||
sankofa.nexus → http://192.168.11.140:80
|
||||
www.sankofa.nexus → http://192.168.11.140:80
|
||||
phoenix.sankofa.nexus → http://192.168.11.140:80
|
||||
www.phoenix.sankofa.nexus → http://192.168.11.140:80
|
||||
the-order.sankofa.nexus → http://192.168.11.140:80
|
||||
explorer.d-bis.org → http://192.168.11.140:80
|
||||
rpc-http-pub.d-bis.org → https://192.168.11.252:443 (WebSocket)
|
||||
rpc-ws-pub.d-bis.org → https://192.168.11.252:443 (WebSocket)
|
||||
rpc-http-prv.d-bis.org → https://192.168.11.251:443 (WebSocket)
|
||||
rpc-ws-prv.d-bis.org → https://192.168.11.251:443 (WebSocket)
|
||||
dbis-admin.d-bis.org → http://192.168.11.130:80
|
||||
dbis-api.d-bis.org → http://192.168.11.155:3000
|
||||
dbis-api-2.d-bis.org → http://192.168.11.156:3000
|
||||
secure.d-bis.org → http://192.168.11.130:80
|
||||
mim4u.org → http://192.168.11.36:80
|
||||
www.mim4u.org → http://192.168.11.36:80
|
||||
secure.mim4u.org → http://192.168.11.36:80
|
||||
training.mim4u.org → http://192.168.11.36:80
|
||||
rpc.public-0138.defi-oracle.io → https://192.168.11.252:443
|
||||
DOMAINS
|
||||
|
||||
cat "$DOMAINS_FILE" | nl -w2 -s'. '
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "✅ After configuration, verify with:"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "curl -I https://explorer.d-bis.org"
|
||||
echo "curl -I https://sankofa.nexus"
|
||||
echo ""
|
||||
echo "Full guide: docs/04-configuration/NGINX_PROXY_MANAGER_SSL_CONFIGURATION.md"
|
||||
echo ""
|
||||
229
scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh
Executable file
229
scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh
Executable file
@@ -0,0 +1,229 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
# Migrate configurations to NPMplus after installation
|
||||
# Run this after NPMplus is installed and running
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="${1:-192.168.11.11}"
|
||||
CONTAINER_ID="${2}"
|
||||
NPM_URL="${3}"
|
||||
|
||||
if [ -z "$CONTAINER_ID" ] || [ -z "$NPM_URL" ]; then
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔄 NPMplus Configuration Migration"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Usage: $0 [PROXMOX_HOST] [CONTAINER_ID] [NPM_URL]"
|
||||
echo ""
|
||||
echo "Example:"
|
||||
echo " $0 ${PROXMOX_HOST_R630_01:-192.168.11.11} 106 https://192.168.11.27:81"
|
||||
echo ""
|
||||
echo "Or run interactively:"
|
||||
read -p "Proxmox Host [${PROXMOX_HOST_R630_01:-192.168.11.11}]: " PROXMOX_HOST
|
||||
PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.11}"
|
||||
read -p "NPMplus Container ID: " CONTAINER_ID
|
||||
read -p "NPMplus URL (https://IP:81): " NPM_URL
|
||||
echo ""
|
||||
fi
|
||||
|
||||
EMAIL="admin@example.org"
|
||||
read -sp "NPMplus Admin Password: " PASSWORD
|
||||
echo ""
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔐 Authenticating to NPMplus..."
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
# Create migration script to run inside container
|
||||
MIGRATE_SCRIPT=$(cat << 'MIGRATE_EOF'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
NPM_URL="${1}"
|
||||
EMAIL="${2}"
|
||||
PASSWORD="${3}"
|
||||
|
||||
echo "🔐 Authenticating..."
|
||||
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
|
||||
sleep 2 # Wait a moment for certificate to be processed
|
||||
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" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "www.sankofa.nexus" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "phoenix.sankofa.nexus" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "www.phoenix.sankofa.nexus" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "the-order.sankofa.nexus" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
|
||||
# d-bis.org (9 domains)
|
||||
create_proxy_host "explorer.d-bis.org" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-pub.d-bis.org" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-pub.d-bis.org" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-prv.d-bis.org" "https" "${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-prv.d-bis.org" "https" "${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-admin.d-bis.org" "http" "${IP_DBIS_FRONTEND:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-192.168.11.13}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-api.d-bis.org" "http" "${IP_DBIS_API:-${IP_DBIS_API:-192.168.11.155}}" "3000" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-api-2.d-bis.org" "http" "${IP_DBIS_API_2:-${IP_DBIS_API_2:-192.168.11.156}}" "3000" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "secure.d-bis.org" "http" "${IP_DBIS_FRONTEND:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-192.168.11.13}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
|
||||
# mim4u.org (4 domains)
|
||||
create_proxy_host "mim4u.org" "http" "${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "www.mim4u.org" "http" "${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "secure.mim4u.org" "http" "${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "training.mim4u.org" "http" "${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
|
||||
# defi-oracle.io (1 domain)
|
||||
create_proxy_host "rpc.public-0138.defi-oracle.io" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-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
|
||||
)
|
||||
|
||||
# Write script to temp file and copy to container
|
||||
TEMP_SCRIPT="/tmp/migrate-npmplus-$$.sh"
|
||||
echo "$MIGRATE_SCRIPT" > "$TEMP_SCRIPT"
|
||||
chmod +x "$TEMP_SCRIPT"
|
||||
|
||||
# Copy to Proxmox host
|
||||
scp "$TEMP_SCRIPT" root@"$PROXMOX_HOST":/tmp/migrate-npmplus.sh
|
||||
|
||||
# Run inside container
|
||||
echo "🚀 Running migration script in NPMplus container..."
|
||||
ssh root@"$PROXMOX_HOST" "pct exec $CONTAINER_ID -- bash /tmp/migrate-npmplus.sh '$NPM_URL' '$EMAIL' '$PASSWORD'"
|
||||
|
||||
# Cleanup
|
||||
rm -f "$TEMP_SCRIPT"
|
||||
ssh root@"$PROXMOX_HOST" "rm -f /tmp/migrate-npmplus.sh"
|
||||
|
||||
echo ""
|
||||
echo "✅ Migration complete!"
|
||||
echo ""
|
||||
echo "📋 Next steps:"
|
||||
echo " 1. Update UDM Pro port forwarding to new container IP"
|
||||
echo " 2. Test all domains: bash scripts/check-east-west-ssl-status.sh"
|
||||
echo " 3. Verify SSL certificates are issued"
|
||||
echo ""
|
||||
223
scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh.bak
Executable file
223
scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh.bak
Executable file
@@ -0,0 +1,223 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Migrate configurations to NPMplus after installation
|
||||
# Run this after NPMplus is installed and running
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="${1:-192.168.11.11}"
|
||||
CONTAINER_ID="${2}"
|
||||
NPM_URL="${3}"
|
||||
|
||||
if [ -z "$CONTAINER_ID" ] || [ -z "$NPM_URL" ]; then
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔄 NPMplus Configuration Migration"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Usage: $0 [PROXMOX_HOST] [CONTAINER_ID] [NPM_URL]"
|
||||
echo ""
|
||||
echo "Example:"
|
||||
echo " $0 192.168.11.11 106 https://192.168.11.27:81"
|
||||
echo ""
|
||||
echo "Or run interactively:"
|
||||
read -p "Proxmox Host [192.168.11.11]: " PROXMOX_HOST
|
||||
PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.11}"
|
||||
read -p "NPMplus Container ID: " CONTAINER_ID
|
||||
read -p "NPMplus URL (https://IP:81): " NPM_URL
|
||||
echo ""
|
||||
fi
|
||||
|
||||
EMAIL="admin@example.org"
|
||||
read -sp "NPMplus Admin Password: " PASSWORD
|
||||
echo ""
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔐 Authenticating to NPMplus..."
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
# Create migration script to run inside container
|
||||
MIGRATE_SCRIPT=$(cat << 'MIGRATE_EOF'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
NPM_URL="${1}"
|
||||
EMAIL="${2}"
|
||||
PASSWORD="${3}"
|
||||
|
||||
echo "🔐 Authenticating..."
|
||||
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
|
||||
sleep 2 # Wait a moment for certificate to be processed
|
||||
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
|
||||
)
|
||||
|
||||
# Write script to temp file and copy to container
|
||||
TEMP_SCRIPT="/tmp/migrate-npmplus-$$.sh"
|
||||
echo "$MIGRATE_SCRIPT" > "$TEMP_SCRIPT"
|
||||
chmod +x "$TEMP_SCRIPT"
|
||||
|
||||
# Copy to Proxmox host
|
||||
scp "$TEMP_SCRIPT" root@"$PROXMOX_HOST":/tmp/migrate-npmplus.sh
|
||||
|
||||
# Run inside container
|
||||
echo "🚀 Running migration script in NPMplus container..."
|
||||
ssh root@"$PROXMOX_HOST" "pct exec $CONTAINER_ID -- bash /tmp/migrate-npmplus.sh '$NPM_URL' '$EMAIL' '$PASSWORD'"
|
||||
|
||||
# Cleanup
|
||||
rm -f "$TEMP_SCRIPT"
|
||||
ssh root@"$PROXMOX_HOST" "rm -f /tmp/migrate-npmplus.sh"
|
||||
|
||||
echo ""
|
||||
echo "✅ Migration complete!"
|
||||
echo ""
|
||||
echo "📋 Next steps:"
|
||||
echo " 1. Update UDM Pro port forwarding to new container IP"
|
||||
echo " 2. Test all domains: bash scripts/check-east-west-ssl-status.sh"
|
||||
echo " 3. Verify SSL certificates are issued"
|
||||
echo ""
|
||||
359
scripts/nginx-proxy-manager/migrate-to-npmplus.sh
Executable file
359
scripts/nginx-proxy-manager/migrate-to-npmplus.sh
Executable file
@@ -0,0 +1,359 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
# Migrate from Nginx Proxy Manager to NPMplus
|
||||
# This script backs up current NPM, installs NPMplus, and migrates all configurations
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="${PROXMOX_HOST_R630_01}"
|
||||
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" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "www.sankofa.nexus" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "phoenix.sankofa.nexus" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "www.phoenix.sankofa.nexus" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "the-order.sankofa.nexus" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
|
||||
# d-bis.org (9 domains)
|
||||
create_proxy_host "explorer.d-bis.org" "http" "${IP_BLOCKSCOUT:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-${IP_DEVICE_14:-192.168.11.14}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-pub.d-bis.org" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-pub.d-bis.org" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-http-prv.d-bis.org" "https" "${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "rpc-ws-prv.d-bis.org" "https" "${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}}}}" "443" "true" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-admin.d-bis.org" "http" "${IP_DBIS_FRONTEND:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-192.168.11.13}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-api.d-bis.org" "http" "${IP_DBIS_API:-${IP_DBIS_API:-192.168.11.155}}" "3000" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "dbis-api-2.d-bis.org" "http" "${IP_DBIS_API_2:-${IP_DBIS_API_2:-192.168.11.156}}" "3000" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "secure.d-bis.org" "http" "${IP_DBIS_FRONTEND:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-${IP_SERVICE_13:-192.168.11.13}}}}}0}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
|
||||
# mim4u.org (4 domains)
|
||||
create_proxy_host "mim4u.org" "http" "${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "www.mim4u.org" "http" "${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "secure.mim4u.org" "http" "${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
create_proxy_host "training.mim4u.org" "http" "${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-${IP_SERVICE_36:-192.168.11.36}}}}}}" "80" "false" && ((SUCCESS++)) || ((FAILED++))
|
||||
|
||||
# defi-oracle.io (1 domain)
|
||||
create_proxy_host "rpc.public-0138.defi-oracle.io" "https" "${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-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 ""
|
||||
353
scripts/nginx-proxy-manager/migrate-to-npmplus.sh.bak
Executable file
353
scripts/nginx-proxy-manager/migrate-to-npmplus.sh.bak
Executable file
@@ -0,0 +1,353 @@
|
||||
#!/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 ""
|
||||
76
scripts/nginx-proxy-manager/post-install-migration.sh
Executable file
76
scripts/nginx-proxy-manager/post-install-migration.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
# Post-installation migration script
|
||||
# Run this AFTER NPMplus is installed
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="${1:-192.168.11.11}"
|
||||
NEW_CONTAINER_ID="${2}"
|
||||
CONTAINER_IP="${3}"
|
||||
|
||||
if [ -z "$NEW_CONTAINER_ID" ] || [ -z "$CONTAINER_IP" ]; then
|
||||
echo "Usage: $0 [PROXMOX_HOST] [CONTAINER_ID] [CONTAINER_IP]"
|
||||
echo ""
|
||||
echo "Example:"
|
||||
echo " $0 ${PROXMOX_HOST_R630_01:-192.168.11.11} 106 192.168.11.27"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔄 Post-Installation Migration"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Get admin password
|
||||
echo "🔑 Retrieving admin password..."
|
||||
ADMIN_PASSWORD=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- bash -c '
|
||||
if [ -f /opt/.npm_pwd ]; then
|
||||
grep -i password /opt/.npm_pwd | cut -d: -f2 | tr -d \" \"
|
||||
else
|
||||
docker logs npmplus 2>/dev/null | grep -i \"Creating a new user\" | tail -1 | grep -oP \"password: \K[^\s]+\" || echo \"\"
|
||||
fi
|
||||
'" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
echo " ⚠️ Could not retrieve password automatically"
|
||||
read -sp " Enter NPMplus admin password: " ADMIN_PASSWORD
|
||||
echo ""
|
||||
else
|
||||
echo " ✅ Admin password retrieved"
|
||||
fi
|
||||
|
||||
# Wait for NPMplus to be ready
|
||||
echo ""
|
||||
echo "⏳ Waiting for NPMplus to be ready..."
|
||||
for i in {1..30}; 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/30)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Migrate configurations
|
||||
echo ""
|
||||
echo "🚀 Migrating configurations..."
|
||||
echo "$ADMIN_PASSWORD" | bash scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh \
|
||||
"$PROXMOX_HOST" \
|
||||
"$NEW_CONTAINER_ID" \
|
||||
"https://$CONTAINER_IP:81"
|
||||
|
||||
echo ""
|
||||
echo "✅ Migration complete!"
|
||||
echo ""
|
||||
echo "📋 Next: Update UDM Pro port forwarding:"
|
||||
echo " HTTP: 76.53.10.36:80 → $CONTAINER_IP:80"
|
||||
echo " HTTPS: 76.53.10.36:443 → $CONTAINER_IP:443"
|
||||
echo ""
|
||||
70
scripts/nginx-proxy-manager/post-install-migration.sh.bak
Executable file
70
scripts/nginx-proxy-manager/post-install-migration.sh.bak
Executable file
@@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Post-installation migration script
|
||||
# Run this AFTER NPMplus is installed
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="${1:-192.168.11.11}"
|
||||
NEW_CONTAINER_ID="${2}"
|
||||
CONTAINER_IP="${3}"
|
||||
|
||||
if [ -z "$NEW_CONTAINER_ID" ] || [ -z "$CONTAINER_IP" ]; then
|
||||
echo "Usage: $0 [PROXMOX_HOST] [CONTAINER_ID] [CONTAINER_IP]"
|
||||
echo ""
|
||||
echo "Example:"
|
||||
echo " $0 192.168.11.11 106 192.168.11.27"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔄 Post-Installation Migration"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Get admin password
|
||||
echo "🔑 Retrieving admin password..."
|
||||
ADMIN_PASSWORD=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- bash -c '
|
||||
if [ -f /opt/.npm_pwd ]; then
|
||||
grep -i password /opt/.npm_pwd | cut -d: -f2 | tr -d \" \"
|
||||
else
|
||||
docker logs npmplus 2>/dev/null | grep -i \"Creating a new user\" | tail -1 | grep -oP \"password: \K[^\s]+\" || echo \"\"
|
||||
fi
|
||||
'" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
echo " ⚠️ Could not retrieve password automatically"
|
||||
read -sp " Enter NPMplus admin password: " ADMIN_PASSWORD
|
||||
echo ""
|
||||
else
|
||||
echo " ✅ Admin password retrieved"
|
||||
fi
|
||||
|
||||
# Wait for NPMplus to be ready
|
||||
echo ""
|
||||
echo "⏳ Waiting for NPMplus to be ready..."
|
||||
for i in {1..30}; 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/30)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Migrate configurations
|
||||
echo ""
|
||||
echo "🚀 Migrating configurations..."
|
||||
echo "$ADMIN_PASSWORD" | bash scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh \
|
||||
"$PROXMOX_HOST" \
|
||||
"$NEW_CONTAINER_ID" \
|
||||
"https://$CONTAINER_IP:81"
|
||||
|
||||
echo ""
|
||||
echo "✅ Migration complete!"
|
||||
echo ""
|
||||
echo "📋 Next: Update UDM Pro port forwarding:"
|
||||
echo " HTTP: 76.53.10.36:80 → $CONTAINER_IP:80"
|
||||
echo " HTTPS: 76.53.10.36:443 → $CONTAINER_IP:443"
|
||||
echo ""
|
||||
182
scripts/nginx-proxy-manager/request-npmplus-7-certs-dns-ui.js
Normal file
182
scripts/nginx-proxy-manager/request-npmplus-7-certs-dns-ui.js
Normal file
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Request SSL certificates for the 7 NPMplus proxy hosts that have no cert.
|
||||
* Uses browser automation: for each host, edit → SSL → Request new certificate
|
||||
* → DNS Challenge → Cloudflare → (first credential) → email + agree → submit.
|
||||
*
|
||||
* Run from repo root: node scripts/nginx-proxy-manager/request-npmplus-7-certs-dns-ui.js
|
||||
* Requires: .env with NPM_URL, NPM_EMAIL, NPM_PASSWORD. HEADLESS=false to watch.
|
||||
*/
|
||||
|
||||
import { chromium } from 'playwright';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import { config } from 'dotenv';
|
||||
import https from 'https';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const PROJECT_ROOT = join(__dirname, '../..');
|
||||
config({ path: join(PROJECT_ROOT, '.env') });
|
||||
|
||||
const NPM_URL = process.env.NPM_URL || 'https://192.168.11.167:81';
|
||||
const NPM_EMAIL = process.env.NPM_EMAIL || 'admin@example.org';
|
||||
const NPM_PASSWORD = process.env.NPM_PASSWORD;
|
||||
const LETSENCRYPT_EMAIL = process.env.SSL_EMAIL || process.env.NPM_EMAIL || NPM_EMAIL;
|
||||
const HEADLESS = process.env.HEADLESS !== 'false';
|
||||
const PAUSE_MODE = process.env.PAUSE_MODE === 'true';
|
||||
|
||||
// Host IDs for the 7 proxy hosts without a certificate (from list-npmplus-proxy-hosts-cert-status.sh)
|
||||
// Set FIRST_ONLY=1 to process only host 22 (for testing)
|
||||
const ALL_HOST_IDS = [22, 26, 24, 27, 28, 29, 25];
|
||||
const HOST_IDS_WITHOUT_CERT = process.env.FIRST_ONLY === '1' || process.env.FIRST_ONLY === 'true' ? ALL_HOST_IDS.slice(0, 1) : ALL_HOST_IDS;
|
||||
|
||||
if (!NPM_PASSWORD) {
|
||||
console.error('❌ NPM_PASSWORD is required. Set it in .env or export NPM_PASSWORD=...');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function log(msg, type = 'info') {
|
||||
const icons = { success: '✅', error: '❌', warning: '⚠️', info: '📋' };
|
||||
console.log(`${icons[type] || '📋'} ${msg}`);
|
||||
}
|
||||
|
||||
async function pause(page, message) {
|
||||
if (PAUSE_MODE) {
|
||||
log(`Paused: ${message}`, 'info');
|
||||
await page.pause();
|
||||
}
|
||||
}
|
||||
|
||||
async function login(page) {
|
||||
log('Logging in to NPMplus...');
|
||||
await page.goto(NPM_URL, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||
await pause(page, 'At login page');
|
||||
|
||||
await page.waitForSelector('input[type="email"], input[name="email"], input[placeholder*="email" i]', { timeout: 10000 });
|
||||
const emailInput = await page.$('input[type="email"]') || await page.$('input[name="email"]') || await page.$('input[placeholder*="email" i]');
|
||||
if (emailInput) await emailInput.fill(NPM_EMAIL);
|
||||
const passwordInput = await page.$('input[type="password"]');
|
||||
if (passwordInput) await passwordInput.fill(NPM_PASSWORD);
|
||||
const loginButton = await page.$('button[type="submit"]') || await page.$('button:has-text("Sign In")') || await page.$('button:has-text("Login")');
|
||||
if (loginButton) await loginButton.click();
|
||||
else await page.keyboard.press('Enter');
|
||||
|
||||
await page.waitForTimeout(3000);
|
||||
const url = page.url();
|
||||
if (url.includes('login') && !url.includes('proxy')) {
|
||||
const body = await page.textContent('body').catch(() => '');
|
||||
if (!body.includes('Proxy Hosts') && !body.includes('dashboard')) {
|
||||
log('Login may have failed – still on login page', 'warning');
|
||||
await page.screenshot({ path: join(PROJECT_ROOT, 'npmplus-login-check.png') }).catch(() => {});
|
||||
}
|
||||
}
|
||||
log('Logged in', 'success');
|
||||
return true;
|
||||
}
|
||||
|
||||
async function requestCertForHostId(page, hostId) {
|
||||
log(`Requesting cert for host ID ${hostId}...`);
|
||||
|
||||
try {
|
||||
// NPM edit URL: open edit form directly by host ID
|
||||
await page.goto(`${NPM_URL}/#/proxy-hosts/edit/${hostId}`, { waitUntil: 'networkidle' });
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
// SSL tab: NPM edit form usually has Details | SSL | Advanced
|
||||
await page.getByText('SSL').first().click();
|
||||
await page.waitForTimeout(1500);
|
||||
|
||||
// "Request a new SSL Certificate" / "Get a new certificate"
|
||||
const requestBtn = page.getByRole('button', { name: /request.*(new )?ssl certificate|get.*certificate/i }).or(
|
||||
page.locator('button:has-text("Request"), button:has-text("Get a new"), a:has-text("Request")').first()
|
||||
);
|
||||
await requestBtn.click();
|
||||
await page.waitForTimeout(1500);
|
||||
|
||||
// DNS Challenge: click option/label for "DNS Challenge" or "Use a DNS Challenge"
|
||||
const dnsOption = page.getByText(/use a dns challenge|dns challenge/i).first();
|
||||
await dnsOption.click();
|
||||
await page.waitForTimeout(800);
|
||||
|
||||
// DNS Provider: Cloudflare (dropdown or first Cloudflare option)
|
||||
const cloudflareOption = page.getByText('Cloudflare').first();
|
||||
await cloudflareOption.click();
|
||||
await page.waitForTimeout(800);
|
||||
|
||||
// Credential: usually first in dropdown if only one Cloudflare credential
|
||||
const credSelect = page.locator('select').filter({ has: page.locator('option') }).first();
|
||||
if (await credSelect.count() > 0) {
|
||||
await credSelect.selectOption({ index: 1 });
|
||||
}
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Email for Let's Encrypt
|
||||
const emailField = page.locator('input[type="email"], input[name*="email" i]').first();
|
||||
await emailField.fill(LETSENCRYPT_EMAIL);
|
||||
|
||||
// Agree to ToS
|
||||
const agree = page.locator('input[type="checkbox"]').filter({ has: page.locator('..') }).first();
|
||||
if (await agree.count() > 0 && !(await agree.isChecked())) await agree.check();
|
||||
|
||||
await pause(page, `Ready to submit cert request for host ${hostId}`);
|
||||
|
||||
// Submit
|
||||
const submitBtn = page.getByRole('button', { name: /save|submit|request|get certificate/i }).first();
|
||||
await submitBtn.click();
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
// Check for success or error
|
||||
const body = await page.textContent('body').catch(() => '');
|
||||
if (body.includes('error') && body.toLowerCase().includes('internal')) {
|
||||
log(`Request for host ${hostId} may have failed (Internal Error). Check NPM UI.`, 'warning');
|
||||
return false;
|
||||
}
|
||||
log(`Submitted cert request for host ${hostId}`, 'success');
|
||||
return true;
|
||||
} catch (e) {
|
||||
log(`Error for host ${hostId}: ${e.message}`, 'error');
|
||||
await page.screenshot({ path: join(PROJECT_ROOT, `npmplus-cert-error-${hostId}.png`) }).catch(() => {});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('🔒 NPMplus – Request 7 certificates (DNS Cloudflare)');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('');
|
||||
log(`NPM: ${NPM_URL}`);
|
||||
log(`Host IDs: ${HOST_IDS_WITHOUT_CERT.join(', ')}`);
|
||||
console.log('');
|
||||
|
||||
const browser = await chromium.launch({ headless: HEADLESS, ignoreHTTPSErrors: true });
|
||||
const context = await browser.newContext({ ignoreHTTPSErrors: true });
|
||||
const page = await context.newPage();
|
||||
|
||||
try {
|
||||
const ok = await login(page);
|
||||
if (!ok) {
|
||||
log('Login failed', 'error');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let success = 0;
|
||||
for (const hostId of HOST_IDS_WITHOUT_CERT) {
|
||||
const ok = await requestCertForHostId(page, hostId);
|
||||
if (ok) success++;
|
||||
await page.waitForTimeout(2000);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
log(`Done. Submitted requests for ${success}/${HOST_IDS_WITHOUT_CERT.length} hosts. Check NPM SSL Certificates and Hosts to confirm.`, 'success');
|
||||
log('Run: ./scripts/list-npmplus-proxy-hosts-cert-status.sh', 'info');
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
131
scripts/nginx-proxy-manager/reset-npm-password.sh
Executable file
131
scripts/nginx-proxy-manager/reset-npm-password.sh
Executable file
@@ -0,0 +1,131 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
# Reset Nginx Proxy Manager Admin Password
|
||||
# This script resets the admin password in NPM database
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="${PROXMOX_HOST_R630_01}"
|
||||
CONTAINER_ID=105
|
||||
# NEW_PASSWORD should come from argument or environment variable
|
||||
NEW_PASSWORD="${1:-${NPM_PASSWORD:-}}"
|
||||
if [ -z "$NEW_PASSWORD" ]; then
|
||||
echo "❌ Password is required. Provide as argument or set NPM_PASSWORD in ~/.env"
|
||||
echo " Usage: $0 <new-password> [email]"
|
||||
exit 1
|
||||
fi
|
||||
EMAIL="${2:-nsatoshi2007@hotmail.com}"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔐 Nginx Proxy Manager Password Reset"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Container: $CONTAINER_ID on $PROXMOX_HOST"
|
||||
echo "New Password: $NEW_PASSWORD"
|
||||
echo ""
|
||||
|
||||
# Check if container is running
|
||||
if ! ssh root@"$PROXMOX_HOST" "pct status $CONTAINER_ID" | grep -q "running"; then
|
||||
echo "❌ Container $CONTAINER_ID is not running"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📋 Resetting password..."
|
||||
|
||||
# Reset password using NPM's built-in method
|
||||
# Try to use NPM's own password hashing
|
||||
echo "📋 Generating password hash using NPM's environment..."
|
||||
|
||||
# Method 1: Try using available bcrypt modules (bcrypt is already installed)
|
||||
PASSWORD_HASH=$(ssh root@"$PROXMOX_HOST" "pct exec $CONTAINER_ID -- bash -c '
|
||||
cd /app
|
||||
# Try bcrypt first (already available)
|
||||
node -e \"
|
||||
try {
|
||||
const bcrypt = require(\\\"bcrypt\\\");
|
||||
console.log(bcrypt.hashSync(process.argv[1], 10));
|
||||
} catch(e1) {
|
||||
// Try bcryptjs if bcrypt fails
|
||||
try {
|
||||
const bcryptjs = require(\\\"bcryptjs\\\");
|
||||
console.log(bcryptjs.hashSync(process.argv[1], 10));
|
||||
} catch(e2) {
|
||||
console.error(\\\"ERROR: Cannot find bcrypt or bcryptjs\\\");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
\" \"$NEW_PASSWORD\"
|
||||
' 2>/dev/null)
|
||||
|
||||
if [ -z "$PASSWORD_HASH" ] || echo "$PASSWORD_HASH" | grep -q "ERROR\|Cannot"; then
|
||||
echo "⚠️ bcrypt modules not available, trying to install bcryptjs..."
|
||||
echo "📦 Installing bcryptjs (this may take a minute)..."
|
||||
ssh root@"$PROXMOX_HOST" "pct exec $CONTAINER_ID -- bash -c 'cd /app && timeout 120 npm install bcryptjs --no-save 2>&1'"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ bcryptjs installed successfully"
|
||||
PASSWORD_HASH=$(ssh root@"$PROXMOX_HOST" "pct exec $CONTAINER_ID -- bash -c '
|
||||
cd /app
|
||||
node -e \"const bcrypt = require(\\\"bcryptjs\\\"); console.log(bcrypt.hashSync(process.argv[1], 10));\" \"$NEW_PASSWORD\"
|
||||
' 2>/dev/null)
|
||||
else
|
||||
echo "❌ Failed to install bcryptjs"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$PASSWORD_HASH" ] || [ "$PASSWORD_HASH" = "null" ]; then
|
||||
echo "❌ Failed to generate password hash"
|
||||
echo "💡 Alternative: Access NPM web UI and use 'Forgot Password' feature"
|
||||
echo " Or manually reset via: http://${IP_NGINX_LEGACY:-192.168.11.26}:81"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Password hash generated"
|
||||
|
||||
# Update database using Node.js and better-sqlite3
|
||||
echo "📝 Updating database using Node.js..."
|
||||
ssh root@"$PROXMOX_HOST" "pct exec $CONTAINER_ID -- bash -c '
|
||||
cd /app
|
||||
npm install better-sqlite3 --no-save --silent 2>&1 | tail -3 || true
|
||||
node -e \"
|
||||
const Database = require(\\\"better-sqlite3\\\");
|
||||
const db = new Database(\\\"/data/database.sqlite\\\");
|
||||
const hash = process.argv[1];
|
||||
const email = process.argv[2];
|
||||
const stmt = db.prepare(\\\"UPDATE user SET password = ?, modified_on = datetime(\\\\\\\"now\\\\\\\") WHERE email = ?\\\");
|
||||
const info = stmt.run(hash, email);
|
||||
if (info.changes > 0) {
|
||||
console.log(\\\"Password updated for \\\" + email);
|
||||
} else {
|
||||
// If user doesn'\''t exist, create it
|
||||
const insertStmt = db.prepare(\\\"INSERT INTO user (email, name, password, is_admin, created_on, modified_on) VALUES (?, ?, ?, 1, datetime(\\\\\\\"now\\\\\\\"), datetime(\\\\\\\"now\\\\\\\"))\\\");
|
||||
const insertInfo = insertStmt.run(email, email.split(\\\"@\\\")[0], hash);
|
||||
if (insertInfo.changes > 0) {
|
||||
console.log(\\\"User created and password set for \\\" + email);
|
||||
} else {
|
||||
console.error(\\\"Failed to update or create user for \\\" + email);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
db.close();
|
||||
\" \"$PASSWORD_HASH\" \"$EMAIL\"
|
||||
'"
|
||||
|
||||
echo ""
|
||||
echo "✅ Password reset complete!"
|
||||
echo ""
|
||||
echo "New credentials:"
|
||||
echo " Email: $EMAIL"
|
||||
echo " Password: $NEW_PASSWORD"
|
||||
echo ""
|
||||
echo "Test login at: http://${IP_NGINX_LEGACY:-192.168.11.26}:81"
|
||||
|
||||
rm -f /tmp/npm-password-hash.txt
|
||||
125
scripts/nginx-proxy-manager/reset-npm-password.sh.bak
Executable file
125
scripts/nginx-proxy-manager/reset-npm-password.sh.bak
Executable file
@@ -0,0 +1,125 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Reset Nginx Proxy Manager Admin Password
|
||||
# This script resets the admin password in NPM database
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="192.168.11.11"
|
||||
CONTAINER_ID=105
|
||||
# NEW_PASSWORD should come from argument or environment variable
|
||||
NEW_PASSWORD="${1:-${NPM_PASSWORD:-}}"
|
||||
if [ -z "$NEW_PASSWORD" ]; then
|
||||
echo "❌ Password is required. Provide as argument or set NPM_PASSWORD in ~/.env"
|
||||
echo " Usage: $0 <new-password> [email]"
|
||||
exit 1
|
||||
fi
|
||||
EMAIL="${2:-nsatoshi2007@hotmail.com}"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔐 Nginx Proxy Manager Password Reset"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Container: $CONTAINER_ID on $PROXMOX_HOST"
|
||||
echo "New Password: $NEW_PASSWORD"
|
||||
echo ""
|
||||
|
||||
# Check if container is running
|
||||
if ! ssh root@"$PROXMOX_HOST" "pct status $CONTAINER_ID" | grep -q "running"; then
|
||||
echo "❌ Container $CONTAINER_ID is not running"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📋 Resetting password..."
|
||||
|
||||
# Reset password using NPM's built-in method
|
||||
# Try to use NPM's own password hashing
|
||||
echo "📋 Generating password hash using NPM's environment..."
|
||||
|
||||
# Method 1: Try using available bcrypt modules (bcrypt is already installed)
|
||||
PASSWORD_HASH=$(ssh root@"$PROXMOX_HOST" "pct exec $CONTAINER_ID -- bash -c '
|
||||
cd /app
|
||||
# Try bcrypt first (already available)
|
||||
node -e \"
|
||||
try {
|
||||
const bcrypt = require(\\\"bcrypt\\\");
|
||||
console.log(bcrypt.hashSync(process.argv[1], 10));
|
||||
} catch(e1) {
|
||||
// Try bcryptjs if bcrypt fails
|
||||
try {
|
||||
const bcryptjs = require(\\\"bcryptjs\\\");
|
||||
console.log(bcryptjs.hashSync(process.argv[1], 10));
|
||||
} catch(e2) {
|
||||
console.error(\\\"ERROR: Cannot find bcrypt or bcryptjs\\\");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
\" \"$NEW_PASSWORD\"
|
||||
' 2>/dev/null)
|
||||
|
||||
if [ -z "$PASSWORD_HASH" ] || echo "$PASSWORD_HASH" | grep -q "ERROR\|Cannot"; then
|
||||
echo "⚠️ bcrypt modules not available, trying to install bcryptjs..."
|
||||
echo "📦 Installing bcryptjs (this may take a minute)..."
|
||||
ssh root@"$PROXMOX_HOST" "pct exec $CONTAINER_ID -- bash -c 'cd /app && timeout 120 npm install bcryptjs --no-save 2>&1'"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ bcryptjs installed successfully"
|
||||
PASSWORD_HASH=$(ssh root@"$PROXMOX_HOST" "pct exec $CONTAINER_ID -- bash -c '
|
||||
cd /app
|
||||
node -e \"const bcrypt = require(\\\"bcryptjs\\\"); console.log(bcrypt.hashSync(process.argv[1], 10));\" \"$NEW_PASSWORD\"
|
||||
' 2>/dev/null)
|
||||
else
|
||||
echo "❌ Failed to install bcryptjs"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$PASSWORD_HASH" ] || [ "$PASSWORD_HASH" = "null" ]; then
|
||||
echo "❌ Failed to generate password hash"
|
||||
echo "💡 Alternative: Access NPM web UI and use 'Forgot Password' feature"
|
||||
echo " Or manually reset via: http://192.168.11.26:81"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Password hash generated"
|
||||
|
||||
# Update database using Node.js and better-sqlite3
|
||||
echo "📝 Updating database using Node.js..."
|
||||
ssh root@"$PROXMOX_HOST" "pct exec $CONTAINER_ID -- bash -c '
|
||||
cd /app
|
||||
npm install better-sqlite3 --no-save --silent 2>&1 | tail -3 || true
|
||||
node -e \"
|
||||
const Database = require(\\\"better-sqlite3\\\");
|
||||
const db = new Database(\\\"/data/database.sqlite\\\");
|
||||
const hash = process.argv[1];
|
||||
const email = process.argv[2];
|
||||
const stmt = db.prepare(\\\"UPDATE user SET password = ?, modified_on = datetime(\\\\\\\"now\\\\\\\") WHERE email = ?\\\");
|
||||
const info = stmt.run(hash, email);
|
||||
if (info.changes > 0) {
|
||||
console.log(\\\"Password updated for \\\" + email);
|
||||
} else {
|
||||
// If user doesn'\''t exist, create it
|
||||
const insertStmt = db.prepare(\\\"INSERT INTO user (email, name, password, is_admin, created_on, modified_on) VALUES (?, ?, ?, 1, datetime(\\\\\\\"now\\\\\\\"), datetime(\\\\\\\"now\\\\\\\"))\\\");
|
||||
const insertInfo = insertStmt.run(email, email.split(\\\"@\\\")[0], hash);
|
||||
if (insertInfo.changes > 0) {
|
||||
console.log(\\\"User created and password set for \\\" + email);
|
||||
} else {
|
||||
console.error(\\\"Failed to update or create user for \\\" + email);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
db.close();
|
||||
\" \"$PASSWORD_HASH\" \"$EMAIL\"
|
||||
'"
|
||||
|
||||
echo ""
|
||||
echo "✅ Password reset complete!"
|
||||
echo ""
|
||||
echo "New credentials:"
|
||||
echo " Email: $EMAIL"
|
||||
echo " Password: $NEW_PASSWORD"
|
||||
echo ""
|
||||
echo "Test login at: http://192.168.11.26:81"
|
||||
|
||||
rm -f /tmp/npm-password-hash.txt
|
||||
179
scripts/nginx-proxy-manager/run-npmplus-migration.sh
Executable file
179
scripts/nginx-proxy-manager/run-npmplus-migration.sh
Executable file
@@ -0,0 +1,179 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
# Complete NPMplus migration - runs all steps automatically
|
||||
# This script orchestrates the entire migration process
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="${PROXMOX_HOST_R630_01}"
|
||||
TZ="America/New_York"
|
||||
ACME_EMAIL="nsatoshi2007@hotmail.com"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔄 Complete NPMplus Migration"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Step 1: Backup current NPM
|
||||
echo "📦 Step 1: Backing up current NPM..."
|
||||
BACKUP_DIR="/tmp/npm-migration-$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
echo " 📋 Exporting current configurations..."
|
||||
ssh root@"$PROXMOX_HOST" "pct exec 105 -- 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\"
|
||||
fi
|
||||
'" > "$BACKUP_DIR/backup.log" 2>&1 || echo " ⚠️ Backup may have issues, continuing..."
|
||||
|
||||
ssh root@"$PROXMOX_HOST" "pct exec 105 -- cat /tmp/npm-database.sql" > "$BACKUP_DIR/database.sql" 2>&1 || echo "" > "$BACKUP_DIR/database.sql"
|
||||
|
||||
echo " ✅ Backup saved to: $BACKUP_DIR"
|
||||
echo ""
|
||||
|
||||
# Step 2: Check if NPMplus is already installed
|
||||
echo "📦 Step 2: Checking for existing NPMplus installation..."
|
||||
EXISTING_CT=$(ssh root@"$PROXMOX_HOST" "pct list | grep -i npmplus | awk '{print \$1}' | head -1" || echo "")
|
||||
|
||||
if [ -n "$EXISTING_CT" ]; then
|
||||
echo " ℹ️ Found existing NPMplus container: $EXISTING_CT"
|
||||
read -p " Use existing container? (y/n): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
NEW_CONTAINER_ID="$EXISTING_CT"
|
||||
echo " ✅ Using existing container: $NEW_CONTAINER_ID"
|
||||
else
|
||||
NEW_CONTAINER_ID=""
|
||||
fi
|
||||
else
|
||||
NEW_CONTAINER_ID=""
|
||||
fi
|
||||
|
||||
# Step 3: Install NPMplus if needed
|
||||
if [ -z "$NEW_CONTAINER_ID" ]; then
|
||||
echo "📦 Step 3: Installing NPMplus..."
|
||||
echo " ⚠️ The Proxmox helper script requires interactive input."
|
||||
echo " 📋 Please run this command on the Proxmox host:"
|
||||
echo ""
|
||||
echo " ssh root@$PROXMOX_HOST"
|
||||
echo " bash -c \"\$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/npmplus.sh)\""
|
||||
echo ""
|
||||
echo " When prompted:"
|
||||
echo " - Timezone: $TZ"
|
||||
echo " - ACME Email: $ACME_EMAIL"
|
||||
echo ""
|
||||
read -p " Press Enter after NPMplus is installed and you have the container ID..."
|
||||
|
||||
read -p " Enter the new NPMplus container ID (VMID): " NEW_CONTAINER_ID
|
||||
if [ -z "$NEW_CONTAINER_ID" ]; then
|
||||
echo " ❌ Container ID is required"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "📦 Step 3: Using existing NPMplus container"
|
||||
fi
|
||||
|
||||
# Step 4: Get container information
|
||||
echo ""
|
||||
echo "📦 Step 4: Getting container information..."
|
||||
CONTAINER_IP=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- hostname -I | awk '{print \$1}'" || echo "")
|
||||
if [ -z "$CONTAINER_IP" ]; then
|
||||
echo " ❌ Could not get container IP. Is the container running?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " ✅ Container IP: $CONTAINER_IP"
|
||||
|
||||
# Get admin password
|
||||
ADMIN_PASSWORD=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- bash -c '
|
||||
if [ -f /opt/.npm_pwd ]; then
|
||||
grep -i password /opt/.npm_pwd | cut -d: -f2 | tr -d \" \"
|
||||
else
|
||||
docker logs npmplus 2>/dev/null | grep -i \"Creating a new user\" | tail -1 | grep -oP \"password: \K[^\s]+\" || echo \"\"
|
||||
fi
|
||||
'" || echo "")
|
||||
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
echo " ⚠️ Could not retrieve password automatically"
|
||||
read -sp " Enter NPMplus admin password: " ADMIN_PASSWORD
|
||||
echo ""
|
||||
else
|
||||
echo " ✅ Admin password retrieved"
|
||||
fi
|
||||
|
||||
# Wait for NPMplus to be ready
|
||||
echo ""
|
||||
echo " ⏳ Waiting for NPMplus to be ready..."
|
||||
for i in {1..30}; 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/30)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Step 5: Migrate configurations
|
||||
echo ""
|
||||
echo "📦 Step 5: Migrating configurations..."
|
||||
bash scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh \
|
||||
"$PROXMOX_HOST" \
|
||||
"$NEW_CONTAINER_ID" \
|
||||
"https://$CONTAINER_IP:81" <<< "$ADMIN_PASSWORD" || {
|
||||
echo " ⚠️ Migration script had issues. Check output above."
|
||||
echo " 💡 You can run it manually:"
|
||||
echo " bash scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh $PROXMOX_HOST $NEW_CONTAINER_ID https://$CONTAINER_IP:81"
|
||||
}
|
||||
|
||||
# Step 6: Update network configuration info
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📋 Step 6: Network Configuration Update Required"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "⚠️ Manual Step Required: Update UDM Pro Port Forwarding"
|
||||
echo ""
|
||||
echo "1. Log into UDM Pro"
|
||||
echo "2. Go to: Settings → Networks → Port Forwarding"
|
||||
echo "3. Update both rules:"
|
||||
echo " • HTTP (Port 80): 76.53.10.36:80 → $CONTAINER_IP:80"
|
||||
echo " • HTTPS (Port 443): 76.53.10.36:443 → $CONTAINER_IP:443"
|
||||
echo ""
|
||||
read -p "Press Enter after updating port forwarding..."
|
||||
|
||||
# Step 7: Test migration
|
||||
echo ""
|
||||
echo "📦 Step 7: Testing migration..."
|
||||
echo " ⏳ Waiting 30 seconds for SSL certificates to process..."
|
||||
sleep 30
|
||||
|
||||
echo " 🔍 Testing SSL certificates..."
|
||||
bash scripts/check-east-west-ssl-status.sh || echo " ⚠️ Some tests may have failed. Check manually."
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "✅ Migration Complete!"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "📋 Summary:"
|
||||
echo " • Old NPM Container: 105"
|
||||
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 " • Backup Location: $BACKUP_DIR"
|
||||
echo ""
|
||||
echo "🔍 Next Steps:"
|
||||
echo " 1. Verify all domains are accessible"
|
||||
echo " 2. Test SSL certificates: bash scripts/check-east-west-ssl-status.sh"
|
||||
echo " 3. Monitor for 24-48 hours"
|
||||
echo " 4. (Optional) Stop old NPM container after verification"
|
||||
echo ""
|
||||
173
scripts/nginx-proxy-manager/run-npmplus-migration.sh.bak
Executable file
173
scripts/nginx-proxy-manager/run-npmplus-migration.sh.bak
Executable file
@@ -0,0 +1,173 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Complete NPMplus migration - runs all steps automatically
|
||||
# This script orchestrates the entire migration process
|
||||
|
||||
set -e
|
||||
|
||||
PROXMOX_HOST="192.168.11.11"
|
||||
TZ="America/New_York"
|
||||
ACME_EMAIL="nsatoshi2007@hotmail.com"
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔄 Complete NPMplus Migration"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Step 1: Backup current NPM
|
||||
echo "📦 Step 1: Backing up current NPM..."
|
||||
BACKUP_DIR="/tmp/npm-migration-$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
echo " 📋 Exporting current configurations..."
|
||||
ssh root@"$PROXMOX_HOST" "pct exec 105 -- 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\"
|
||||
fi
|
||||
'" > "$BACKUP_DIR/backup.log" 2>&1 || echo " ⚠️ Backup may have issues, continuing..."
|
||||
|
||||
ssh root@"$PROXMOX_HOST" "pct exec 105 -- cat /tmp/npm-database.sql" > "$BACKUP_DIR/database.sql" 2>&1 || echo "" > "$BACKUP_DIR/database.sql"
|
||||
|
||||
echo " ✅ Backup saved to: $BACKUP_DIR"
|
||||
echo ""
|
||||
|
||||
# Step 2: Check if NPMplus is already installed
|
||||
echo "📦 Step 2: Checking for existing NPMplus installation..."
|
||||
EXISTING_CT=$(ssh root@"$PROXMOX_HOST" "pct list | grep -i npmplus | awk '{print \$1}' | head -1" || echo "")
|
||||
|
||||
if [ -n "$EXISTING_CT" ]; then
|
||||
echo " ℹ️ Found existing NPMplus container: $EXISTING_CT"
|
||||
read -p " Use existing container? (y/n): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
NEW_CONTAINER_ID="$EXISTING_CT"
|
||||
echo " ✅ Using existing container: $NEW_CONTAINER_ID"
|
||||
else
|
||||
NEW_CONTAINER_ID=""
|
||||
fi
|
||||
else
|
||||
NEW_CONTAINER_ID=""
|
||||
fi
|
||||
|
||||
# Step 3: Install NPMplus if needed
|
||||
if [ -z "$NEW_CONTAINER_ID" ]; then
|
||||
echo "📦 Step 3: Installing NPMplus..."
|
||||
echo " ⚠️ The Proxmox helper script requires interactive input."
|
||||
echo " 📋 Please run this command on the Proxmox host:"
|
||||
echo ""
|
||||
echo " ssh root@$PROXMOX_HOST"
|
||||
echo " bash -c \"\$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/npmplus.sh)\""
|
||||
echo ""
|
||||
echo " When prompted:"
|
||||
echo " - Timezone: $TZ"
|
||||
echo " - ACME Email: $ACME_EMAIL"
|
||||
echo ""
|
||||
read -p " Press Enter after NPMplus is installed and you have the container ID..."
|
||||
|
||||
read -p " Enter the new NPMplus container ID (VMID): " NEW_CONTAINER_ID
|
||||
if [ -z "$NEW_CONTAINER_ID" ]; then
|
||||
echo " ❌ Container ID is required"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "📦 Step 3: Using existing NPMplus container"
|
||||
fi
|
||||
|
||||
# Step 4: Get container information
|
||||
echo ""
|
||||
echo "📦 Step 4: Getting container information..."
|
||||
CONTAINER_IP=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- hostname -I | awk '{print \$1}'" || echo "")
|
||||
if [ -z "$CONTAINER_IP" ]; then
|
||||
echo " ❌ Could not get container IP. Is the container running?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " ✅ Container IP: $CONTAINER_IP"
|
||||
|
||||
# Get admin password
|
||||
ADMIN_PASSWORD=$(ssh root@"$PROXMOX_HOST" "pct exec $NEW_CONTAINER_ID -- bash -c '
|
||||
if [ -f /opt/.npm_pwd ]; then
|
||||
grep -i password /opt/.npm_pwd | cut -d: -f2 | tr -d \" \"
|
||||
else
|
||||
docker logs npmplus 2>/dev/null | grep -i \"Creating a new user\" | tail -1 | grep -oP \"password: \K[^\s]+\" || echo \"\"
|
||||
fi
|
||||
'" || echo "")
|
||||
|
||||
if [ -z "$ADMIN_PASSWORD" ]; then
|
||||
echo " ⚠️ Could not retrieve password automatically"
|
||||
read -sp " Enter NPMplus admin password: " ADMIN_PASSWORD
|
||||
echo ""
|
||||
else
|
||||
echo " ✅ Admin password retrieved"
|
||||
fi
|
||||
|
||||
# Wait for NPMplus to be ready
|
||||
echo ""
|
||||
echo " ⏳ Waiting for NPMplus to be ready..."
|
||||
for i in {1..30}; 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/30)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Step 5: Migrate configurations
|
||||
echo ""
|
||||
echo "📦 Step 5: Migrating configurations..."
|
||||
bash scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh \
|
||||
"$PROXMOX_HOST" \
|
||||
"$NEW_CONTAINER_ID" \
|
||||
"https://$CONTAINER_IP:81" <<< "$ADMIN_PASSWORD" || {
|
||||
echo " ⚠️ Migration script had issues. Check output above."
|
||||
echo " 💡 You can run it manually:"
|
||||
echo " bash scripts/nginx-proxy-manager/migrate-configs-to-npmplus.sh $PROXMOX_HOST $NEW_CONTAINER_ID https://$CONTAINER_IP:81"
|
||||
}
|
||||
|
||||
# Step 6: Update network configuration info
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📋 Step 6: Network Configuration Update Required"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "⚠️ Manual Step Required: Update UDM Pro Port Forwarding"
|
||||
echo ""
|
||||
echo "1. Log into UDM Pro"
|
||||
echo "2. Go to: Settings → Networks → Port Forwarding"
|
||||
echo "3. Update both rules:"
|
||||
echo " • HTTP (Port 80): 76.53.10.36:80 → $CONTAINER_IP:80"
|
||||
echo " • HTTPS (Port 443): 76.53.10.36:443 → $CONTAINER_IP:443"
|
||||
echo ""
|
||||
read -p "Press Enter after updating port forwarding..."
|
||||
|
||||
# Step 7: Test migration
|
||||
echo ""
|
||||
echo "📦 Step 7: Testing migration..."
|
||||
echo " ⏳ Waiting 30 seconds for SSL certificates to process..."
|
||||
sleep 30
|
||||
|
||||
echo " 🔍 Testing SSL certificates..."
|
||||
bash scripts/check-east-west-ssl-status.sh || echo " ⚠️ Some tests may have failed. Check manually."
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "✅ Migration Complete!"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "📋 Summary:"
|
||||
echo " • Old NPM Container: 105"
|
||||
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 " • Backup Location: $BACKUP_DIR"
|
||||
echo ""
|
||||
echo "🔍 Next Steps:"
|
||||
echo " 1. Verify all domains are accessible"
|
||||
echo " 2. Test SSL certificates: bash scripts/check-east-west-ssl-status.sh"
|
||||
echo " 3. Monitor for 24-48 hours"
|
||||
echo " 4. (Optional) Stop old NPM container after verification"
|
||||
echo ""
|
||||
42
scripts/nginx-proxy-manager/run-update-npmplus-alltra-hybx-via-ssh.sh
Executable file
42
scripts/nginx-proxy-manager/run-update-npmplus-alltra-hybx-via-ssh.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run update-npmplus-alltra-hybx-proxy-hosts.sh ON the Proxmox host (r630-01) via SSH.
|
||||
# NPM password: from .env (NPM_PASSWORD) or via pct exec 10235 -- cat /opt/.npm_pwd. Run from repo root.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
[ -f "$PROJECT_ROOT/config/ip-addresses.conf" ] && source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true
|
||||
[ -f "$PROJECT_ROOT/.env" ] && set +u && source "$PROJECT_ROOT/.env" 2>/dev/null || true && set -u
|
||||
|
||||
PROXMOX_HOST="${PROXMOX_HOST_R630_01:-${PROXMOX_R630_01:-192.168.11.11}}"
|
||||
VMID=10235
|
||||
REMOTE_DIR="/tmp/proxmox-npmplus-update-$$"
|
||||
|
||||
# Prefer third NPMplus–specific credentials (192.168.11.169), then fall back to primary NPMplus vars
|
||||
NPM_PASSWORD_FOR_THIRD="${NPM_PASSWORD_ALLTRA_HYBX:-${NPM_PASSWORD:-}}"
|
||||
NPM_EMAIL_FOR_REMOTE="${NPM_EMAIL_ALLTRA_HYBX:-${NPM_EMAIL:-admin@example.org}}"
|
||||
if [ -z "$NPM_PASSWORD_FOR_THIRD" ]; then
|
||||
echo "Getting NPM password from container $VMID via pct..."
|
||||
NPM_PASSWORD_FOR_THIRD=$(ssh -n "root@$PROXMOX_HOST" "pct exec $VMID -- cat /opt/.npm_pwd 2>/dev/null" || true)
|
||||
fi
|
||||
if [ -z "$NPM_PASSWORD_FOR_THIRD" ]; then
|
||||
echo "Set NPM_PASSWORD_ALLTRA_HYBX (or NPM_PASSWORD) in .env for third NPMplus (192.168.11.169:81), or ensure container $VMID has /opt/.npm_pwd."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Run NPMplus Alltra/HYBX update on Proxmox via SSH + pct"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Host: $PROXMOX_HOST (r630-01) VMID: $VMID (NPMplus Alltra/HYBX)"
|
||||
echo ""
|
||||
|
||||
# Copy minimal tree to remote so script can run with correct PROJECT_ROOT
|
||||
ssh "root@$PROXMOX_HOST" "mkdir -p $REMOTE_DIR/config $REMOTE_DIR/scripts/nginx-proxy-manager"
|
||||
scp -q "$PROJECT_ROOT/config/ip-addresses.conf" "root@$PROXMOX_HOST:$REMOTE_DIR/config/"
|
||||
scp -q "$PROJECT_ROOT/scripts/nginx-proxy-manager/update-npmplus-alltra-hybx-proxy-hosts.sh" "root@$PROXMOX_HOST:$REMOTE_DIR/scripts/nginx-proxy-manager/"
|
||||
|
||||
# On Proxmox: run the update script with third NPMplus credentials (passed safely)
|
||||
export NPM_PASSWORD_ESC NPM_EMAIL_ESC
|
||||
NPM_PASSWORD_ESC=$(echo "$NPM_PASSWORD_FOR_THIRD" | sed "s/'/'\\\\''/g")
|
||||
NPM_EMAIL_ESC=$(echo "${NPM_EMAIL_FOR_REMOTE:-}" | sed "s/'/'\\\\''/g")
|
||||
ssh "root@$PROXMOX_HOST" "cd $REMOTE_DIR && NPM_PASSWORD='$NPM_PASSWORD_ESC' NPM_EMAIL='$NPM_EMAIL_ESC' bash ./scripts/nginx-proxy-manager/update-npmplus-alltra-hybx-proxy-hosts.sh; rc=\$?; rm -rf $REMOTE_DIR; exit \$rc"
|
||||
136
scripts/nginx-proxy-manager/test-npm-create-proxy-api.sh.bak
Executable file
136
scripts/nginx-proxy-manager/test-npm-create-proxy-api.sh.bak
Executable file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env bash
|
||||
# Test NPM API proxy host CREATE endpoint to discover accepted properties.
|
||||
# Run from repo root. Uses .env for NPM_URL, NPM_EMAIL, NPM_PASSWORD.
|
||||
# Creates a temporary test host then deletes it. No edits to create-npmplus-defi-oracle-hosts.sh.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Load .env
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
if [ -f .env ]; then
|
||||
set +u
|
||||
set -a
|
||||
# shellcheck source=/dev/null
|
||||
source .env 2>/dev/null || true
|
||||
set +a
|
||||
set -u
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
fi
|
||||
|
||||
NPM_URL="${NPM_URL:-https://192.168.11.167:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-admin@example.org}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "❌ NPM_PASSWORD required in .env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Auth
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON")
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || true)
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
echo "❌ NPM auth failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "NPM API: probe CREATE proxy-hosts (comprehensive test)"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# 1. Get one existing proxy host to see full response shape (property names)
|
||||
echo "1. Fetching existing proxy hosts (first host keys only)..."
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN")
|
||||
FIRST_KEYS=$(echo "$PROXY_HOSTS_JSON" | jq -r 'if type == "array" then (.[0] | keys | join(", ")) else (.[0] // .result[0] // {} | keys | join(", ")) end' 2>/dev/null || echo "unknown")
|
||||
echo " First proxy host top-level keys: $FIRST_KEYS"
|
||||
echo ""
|
||||
|
||||
# 2. Check response structure (array vs .result)
|
||||
if echo "$PROXY_HOSTS_JSON" | jq -e '.result' >/dev/null 2>&1; then
|
||||
echo " API returns proxy hosts in .result array"
|
||||
LIST_JQ='.result'
|
||||
else
|
||||
echo " API returns proxy hosts as top-level array"
|
||||
LIST_JQ='.'
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test domain (unique so we can delete after)
|
||||
TEST_DOMAIN="npm-test-$(date +%s).local"
|
||||
|
||||
# 3. Try minimal payload (only fields we believe are required)
|
||||
echo "2. CREATE with minimal payload (domain_names, forward_scheme, forward_host, forward_port, allow_websocket_upgrade)"
|
||||
MINIMAL_PAYLOAD=$(jq -n \
|
||||
--arg domain "$TEST_DOMAIN" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: "http",
|
||||
forward_host: "127.0.0.1",
|
||||
forward_port: 80,
|
||||
allow_websocket_upgrade: false
|
||||
}')
|
||||
echo " Payload: $MINIMAL_PAYLOAD"
|
||||
RESP_MINIMAL=$(curl -s -k -X POST "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$MINIMAL_PAYLOAD")
|
||||
echo " Response: $RESP_MINIMAL"
|
||||
if echo "$RESP_MINIMAL" | jq -e '.id' >/dev/null 2>&1; then
|
||||
CREATED_ID=$(echo "$RESP_MINIMAL" | jq -r '.id')
|
||||
echo " ✅ Minimal payload ACCEPTED (id=$CREATED_ID)"
|
||||
echo ""
|
||||
echo "3. Deleting test host (id=$CREATED_ID)..."
|
||||
curl -s -k -X DELETE "$NPM_URL/api/nginx/proxy-hosts/$CREATED_ID" -H "Authorization: Bearer $TOKEN" >/dev/null || true
|
||||
echo " Done."
|
||||
else
|
||||
ERR_MSG=$(echo "$RESP_MINIMAL" | jq -r '.message // .error // .error.message // .' 2>/dev/null || echo "$RESP_MINIMAL")
|
||||
echo " ❌ Minimal payload REJECTED: $ERR_MSG"
|
||||
echo ""
|
||||
|
||||
# 4. If minimal failed, try with certificate_id and access_list_id (common optional)
|
||||
echo "4. CREATE with minimal + certificate_id + access_list_id"
|
||||
PAYLOAD_WITH_CERT=$(jq -n \
|
||||
--arg domain "$TEST_DOMAIN" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: "http",
|
||||
forward_host: "127.0.0.1",
|
||||
forward_port: 80,
|
||||
allow_websocket_upgrade: false,
|
||||
certificate_id: 0,
|
||||
access_list_id: 0
|
||||
}')
|
||||
echo " Payload: $PAYLOAD_WITH_CERT"
|
||||
RESP_CERT=$(curl -s -k -X POST "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$PAYLOAD_WITH_CERT")
|
||||
echo " Response: $RESP_CERT"
|
||||
if echo "$RESP_CERT" | jq -e '.id' >/dev/null 2>&1; then
|
||||
CREATED_ID=$(echo "$RESP_CERT" | jq -r '.id')
|
||||
echo " ✅ Payload with cert/list IDs ACCEPTED (id=$CREATED_ID)"
|
||||
curl -s -k -X DELETE "$NPM_URL/api/nginx/proxy-hosts/$CREATED_ID" -H "Authorization: Bearer $TOKEN" >/dev/null || true
|
||||
else
|
||||
echo " ❌ Still rejected."
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 5. List all keys from first existing host (for reference)
|
||||
echo "5. Keys on existing proxy host (for reference):"
|
||||
echo "$PROXY_HOSTS_JSON" | jq -r 'if type == "array" then (.[0] | keys) else (.result[0] // .[0] | keys) end' 2>/dev/null | tr -d '[]"' | sed 's/,/\n/g' | sed 's/^/ /' || true
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Test complete. Use output above to fix create-npmplus-defi-oracle-hosts.sh payload."
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env bash
|
||||
# Add NPMplus proxy hosts for Alltra/HYBX services
|
||||
# NPMplus Alltra/HYBX: 192.168.11.169:81 (VMID 10235)
|
||||
# Usage: NPM_URL=https://192.168.11.169:81 NPM_PASSWORD=xxx bash scripts/nginx-proxy-manager/update-npmplus-alltra-hybx-proxy-hosts.sh
|
||||
# See: docs/04-configuration/NPMPLUS_ALLTRA_HYBX_MASTER_PLAN.md
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true
|
||||
[ -f "$PROJECT_ROOT/.env" ] && set +u && source "$PROJECT_ROOT/.env" 2>/dev/null || true && set -u
|
||||
|
||||
# Alltra/HYBX NPMplus: always use 192.168.11.169 (don't let .env NPM_URL override)
|
||||
NPMPLUS_ALLTRA_IP="${IP_NPMPLUS_ALLTRA_HYBX:-192.168.11.169}"
|
||||
NPM_URL="https://${NPMPLUS_ALLTRA_IP}:81"
|
||||
NPM_EMAIL="${NPM_EMAIL:-admin@example.org}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "Set NPM_PASSWORD. Get from: ssh root@192.168.11.11 'pct exec 10235 -- cat /opt/.npm_pwd 2>/dev/null'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Adding proxy hosts to NPMplus Alltra/HYBX at $NPM_URL..."
|
||||
|
||||
# Authenticate (some NPM 2 instances return only {expires} and set token in cookie)
|
||||
COOKIE_JAR="/tmp/npm_alltra_cookies_$$"
|
||||
cleanup_cookies() { rm -f "$COOKIE_JAR"; }
|
||||
trap cleanup_cookies EXIT
|
||||
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON" -c "$COOKIE_JAR")
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // .accessToken // .access_token // .data.token // empty' 2>/dev/null)
|
||||
|
||||
# If no token in body but response has "expires", auth succeeded via cookie (NPM 2 style)
|
||||
USE_COOKIE_AUTH=0
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
if echo "$TOKEN_RESPONSE" | jq -e '.expires' >/dev/null 2>&1; then
|
||||
USE_COOKIE_AUTH=1
|
||||
echo "Using cookie-based auth (NPM 2 style)."
|
||||
else
|
||||
echo "Authentication failed"
|
||||
MSG=$(echo "$TOKEN_RESPONSE" | jq -r '.message // .error // .error.message // empty' 2>/dev/null)
|
||||
[ -n "$MSG" ] && echo "API: $MSG"
|
||||
KEYS=$(echo "$TOKEN_RESPONSE" | jq -r 'keys | join(", ")' 2>/dev/null)
|
||||
[ -n "$KEYS" ] && echo "Response keys: $KEYS"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Curl auth: Bearer token or cookie
|
||||
curl_auth() {
|
||||
if [ "$USE_COOKIE_AUTH" = "1" ]; then
|
||||
curl -s -k -b "$COOKIE_JAR" "$@"
|
||||
else
|
||||
curl -s -k -H "Authorization: Bearer $TOKEN" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
add_proxy_host() {
|
||||
local domain=$1
|
||||
local fwd_host=$2
|
||||
local fwd_port=$3
|
||||
local ws=${4:-false}
|
||||
local payload
|
||||
payload=$(jq -n \
|
||||
--arg domain "$domain" \
|
||||
--arg host "$fwd_host" \
|
||||
--argjson port "$fwd_port" \
|
||||
--argjson ws "$ws" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: "http",
|
||||
forward_host: $host,
|
||||
forward_port: $port,
|
||||
allow_websocket_upgrade: $ws,
|
||||
block_exploits: false,
|
||||
certificate_id: null,
|
||||
ssl_forced: false
|
||||
}')
|
||||
local resp
|
||||
resp=$(curl_auth -X POST "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload")
|
||||
local id
|
||||
id=$(echo "$resp" | jq -r '.id // empty' 2>/dev/null)
|
||||
if [ -n "$id" ] && [ "$id" != "null" ]; then
|
||||
echo " Added: $domain -> $fwd_host:$fwd_port"
|
||||
return 0
|
||||
else
|
||||
echo " Skip (may exist): $domain - $(echo "$resp" | jq -r '.message // .error // "unknown"' 2>/dev/null)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Update existing proxy host to set block_exploits: false (fixes 405 on JSON-RPC POST to /)
|
||||
# NPM 2 PUT accepts only specific fields; try minimal payload and blockCommonExploits (camelCase)
|
||||
update_block_exploits() {
|
||||
local domain=$1
|
||||
local fwd_host=$2
|
||||
local fwd_port=$3
|
||||
local ws=${4:-false}
|
||||
local hosts_json
|
||||
hosts_json=$(curl_auth -X GET "$NPM_URL/api/nginx/proxy-hosts")
|
||||
local id
|
||||
id=$(echo "$hosts_json" | jq -r ".[] | select(.domain_names | type == \"array\") | select(.domain_names[] == \"$domain\") | .id" 2>/dev/null | head -n1)
|
||||
if [ -z "$id" ] || [ "$id" = "null" ]; then return 1; fi
|
||||
# Minimal payload (NPM 2 rejects "additional properties")
|
||||
local payload
|
||||
payload=$(jq -n \
|
||||
--arg scheme "http" --arg host "$fwd_host" --argjson port "$fwd_port" --argjson ws "$ws" \
|
||||
'{ forward_scheme: $scheme, forward_host: $host, forward_port: $port, allow_websocket_upgrade: $ws, block_exploits: false }')
|
||||
local resp
|
||||
resp=$(curl_auth -X PUT "$NPM_URL/api/nginx/proxy-hosts/$id" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload")
|
||||
local out_id
|
||||
out_id=$(echo "$resp" | jq -r '.id // empty' 2>/dev/null)
|
||||
if [ -n "$out_id" ] && [ "$out_id" != "null" ]; then
|
||||
echo " Updated block_exploits=false: $domain"
|
||||
return 0
|
||||
fi
|
||||
# NPM 2 may use camelCase: blockCommonExploits
|
||||
payload=$(jq -n \
|
||||
--arg scheme "http" --arg host "$fwd_host" --argjson port "$fwd_port" --argjson ws "$ws" \
|
||||
'{ forward_scheme: $scheme, forward_host: $host, forward_port: $port, allow_websocket_upgrade: $ws, blockCommonExploits: false }')
|
||||
resp=$(curl_auth -X PUT "$NPM_URL/api/nginx/proxy-hosts/$id" -H "Content-Type: application/json" -d "$payload")
|
||||
out_id=$(echo "$resp" | jq -r '.id // empty' 2>/dev/null)
|
||||
if [ -n "$out_id" ] && [ "$out_id" != "null" ]; then
|
||||
echo " Updated blockCommonExploits=false: $domain"
|
||||
return 0
|
||||
fi
|
||||
echo " Warning: could not set block_exploits false via API for $domain. Turn off 'Block Common Exploits' in NPM UI (Advanced) for this proxy host."
|
||||
return 1
|
||||
}
|
||||
|
||||
# Add or fix Alltra/HYBX + Nathan core-2 proxy hosts (third NPMplus = 76.53.10.38 → 192.168.11.169)
|
||||
# RPC hosts must have block_exploits false or POST to / returns 405
|
||||
add_proxy_host "rpc-core-2.d-bis.org" "192.168.11.212" 8545 true || true
|
||||
add_proxy_host "rpc-alltra.d-bis.org" "192.168.11.172" 8545 true || true
|
||||
add_proxy_host "rpc-alltra-2.d-bis.org" "192.168.11.173" 8545 true || true
|
||||
add_proxy_host "rpc-alltra-3.d-bis.org" "192.168.11.174" 8545 true || true
|
||||
add_proxy_host "rpc-hybx.d-bis.org" "192.168.11.246" 8545 true || true
|
||||
add_proxy_host "rpc-hybx-2.d-bis.org" "192.168.11.247" 8545 true || true
|
||||
add_proxy_host "rpc-hybx-3.d-bis.org" "192.168.11.248" 8545 true || true
|
||||
add_proxy_host "cacti-alltra.d-bis.org" "192.168.11.177" 80 false || true
|
||||
add_proxy_host "cacti-hybx.d-bis.org" "192.168.11.251" 80 false || true
|
||||
# Firefly (Alltra: 6202-6203 @ .175,.176; HYBX: 6204-6205 @ .249,.250) — port 80 typical for web UI
|
||||
add_proxy_host "firefly-alltra-1.d-bis.org" "192.168.11.175" 80 false || true
|
||||
add_proxy_host "firefly-alltra-2.d-bis.org" "192.168.11.176" 80 false || true
|
||||
add_proxy_host "firefly-hybx-1.d-bis.org" "192.168.11.249" 80 false || true
|
||||
add_proxy_host "firefly-hybx-2.d-bis.org" "192.168.11.250" 80 false || true
|
||||
# Fabric / Indy (Alltra: 6001,6401 @ .178,.179; HYBX: 6002,6402 @ .252,.253) — port 80 or adjust in NPM UI
|
||||
add_proxy_host "fabric-alltra.d-bis.org" "192.168.11.178" 80 false || true
|
||||
add_proxy_host "indy-alltra.d-bis.org" "192.168.11.179" 80 false || true
|
||||
add_proxy_host "fabric-hybx.d-bis.org" "192.168.11.252" 80 false || true
|
||||
add_proxy_host "indy-hybx.d-bis.org" "192.168.11.253" 80 false || true
|
||||
echo "Ensuring block_exploits=false for RPC hosts (fixes 405 on JSON-RPC POST)..."
|
||||
update_block_exploits "rpc-core-2.d-bis.org" "192.168.11.212" 8545 true || true
|
||||
update_block_exploits "rpc-alltra.d-bis.org" "192.168.11.172" 8545 true || true
|
||||
update_block_exploits "rpc-alltra-2.d-bis.org" "192.168.11.173" 8545 true || true
|
||||
update_block_exploits "rpc-alltra-3.d-bis.org" "192.168.11.174" 8545 true || true
|
||||
update_block_exploits "rpc-hybx.d-bis.org" "192.168.11.246" 8545 true || true
|
||||
update_block_exploits "rpc-hybx-2.d-bis.org" "192.168.11.247" 8545 true || true
|
||||
update_block_exploits "rpc-hybx-3.d-bis.org" "192.168.11.248" 8545 true || true
|
||||
|
||||
echo ""
|
||||
echo "Done. Request Let's Encrypt certs in NPMplus UI for each domain."
|
||||
111
scripts/nginx-proxy-manager/update-npmplus-fourth-proxy-hosts.sh
Normal file
111
scripts/nginx-proxy-manager/update-npmplus-fourth-proxy-hosts.sh
Normal file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env bash
|
||||
# Add NPMplus proxy hosts for dev/Codespaces (fourth NPMplus at 192.168.11.170)
|
||||
# Dev VM (Gitea) + direction to all three Proxmox VE admin panels.
|
||||
# Usage: NPM_URL=https://192.168.11.170:81 NPM_PASSWORD=xxx bash scripts/nginx-proxy-manager/update-npmplus-fourth-proxy-hosts.sh
|
||||
# Or use NPM_EMAIL + NPM_PASSWORD from .env (NPM_EMAIL_FOURTH / NPM_PASSWORD_FOURTH if set).
|
||||
# See: docs/04-configuration/DEV_CODESPACES_76_53_10_40.md
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true
|
||||
[ -f "$PROJECT_ROOT/.env" ] && set +u && source "$PROJECT_ROOT/.env" 2>/dev/null || true && set -u
|
||||
|
||||
# Fourth NPMplus (dev/Codespaces)
|
||||
NPMPLUS_FOURTH_IP="${IP_NPMPLUS_FOURTH:-192.168.11.170}"
|
||||
IP_DEV_VM="${IP_DEV_VM:-192.168.11.60}"
|
||||
PROXMOX_ML110="${PROXMOX_HOST_ML110:-192.168.11.10}"
|
||||
PROXMOX_R630_01="${PROXMOX_HOST_R630_01:-192.168.11.11}"
|
||||
PROXMOX_R630_02="${PROXMOX_HOST_R630_02:-192.168.11.12}"
|
||||
|
||||
# Prefer fourth NPMplus URL so .env NPM_URL (e.g. first instance) does not override
|
||||
NPM_URL="${NPM_URL_FOURTH:-https://${NPMPLUS_FOURTH_IP}:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL_FOURTH:-${NPM_EMAIL:-admin@example.org}}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD_FOURTH:-${NPM_PASSWORD:-}}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "Set NPM_PASSWORD or NPM_PASSWORD_FOURTH. Example: get from fourth NPMplus container (VMID TBD) or set in .env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Adding proxy hosts to NPMplus Fourth (dev/Codespaces) at $NPM_URL..."
|
||||
|
||||
# Authenticate (NPM 2 may use cookie-only)
|
||||
COOKIE_JAR="/tmp/npm_fourth_cookies_$$"
|
||||
cleanup_cookies() { rm -f "$COOKIE_JAR"; }
|
||||
trap cleanup_cookies EXIT
|
||||
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON" -c "$COOKIE_JAR")
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // .accessToken // .access_token // .data.token // empty' 2>/dev/null)
|
||||
|
||||
USE_COOKIE_AUTH=0
|
||||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||||
if echo "$TOKEN_RESPONSE" | jq -e '.expires' >/dev/null 2>&1; then
|
||||
USE_COOKIE_AUTH=1
|
||||
echo "Using cookie-based auth (NPM 2 style)."
|
||||
else
|
||||
echo "Authentication failed"
|
||||
MSG=$(echo "$TOKEN_RESPONSE" | jq -r '.message // .error // .error.message // empty' 2>/dev/null)
|
||||
[ -n "$MSG" ] && echo "API: $MSG"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
curl_auth() {
|
||||
if [ "$USE_COOKIE_AUTH" = "1" ]; then
|
||||
curl -s -k -b "$COOKIE_JAR" "$@"
|
||||
else
|
||||
curl -s -k -H "Authorization: Bearer $TOKEN" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
add_proxy_host() {
|
||||
local domain=$1
|
||||
local fwd_host=$2
|
||||
local fwd_port=$3
|
||||
local ws=${4:-false}
|
||||
local payload
|
||||
payload=$(jq -n \
|
||||
--arg domain "$domain" \
|
||||
--arg host "$fwd_host" \
|
||||
--argjson port "$fwd_port" \
|
||||
--argjson ws "$ws" \
|
||||
'{
|
||||
domain_names: [$domain],
|
||||
forward_scheme: "http",
|
||||
forward_host: $host,
|
||||
forward_port: $port,
|
||||
allow_websocket_upgrade: $ws,
|
||||
block_exploits: false,
|
||||
certificate_id: null,
|
||||
ssl_forced: false
|
||||
}')
|
||||
local resp
|
||||
resp=$(curl_auth -X POST "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload")
|
||||
local id
|
||||
id=$(echo "$resp" | jq -r '.id // empty' 2>/dev/null)
|
||||
if [ -n "$id" ] && [ "$id" != "null" ]; then
|
||||
echo " Added: $domain -> $fwd_host:$fwd_port (websocket=$ws)"
|
||||
return 0
|
||||
else
|
||||
echo " Skip (may exist): $domain - $(echo "$resp" | jq -r '.message // .error // "unknown"' 2>/dev/null)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Dev VM (Gitea on 3000); dev and codespaces as aliases
|
||||
add_proxy_host "dev.d-bis.org" "$IP_DEV_VM" 3000 false || true
|
||||
add_proxy_host "gitea.d-bis.org" "$IP_DEV_VM" 3000 false || true
|
||||
add_proxy_host "codespaces.d-bis.org" "$IP_DEV_VM" 3000 false || true
|
||||
|
||||
# Proxmox VE admin panels (port 8006; websocket required for console)
|
||||
add_proxy_host "pve.ml110.d-bis.org" "$PROXMOX_ML110" 8006 true || true
|
||||
add_proxy_host "pve.r630-01.d-bis.org" "$PROXMOX_R630_01" 8006 true || true
|
||||
add_proxy_host "pve.r630-02.d-bis.org" "$PROXMOX_R630_02" 8006 true || true
|
||||
|
||||
echo ""
|
||||
echo "Done. Request Let's Encrypt certs in NPMplus UI (Fourth instance) for: dev, gitea, codespaces, pve.ml110, pve.r630-01, pve.r630-02."
|
||||
echo "Proxmox admin: https://pve.ml110.d-bis.org, https://pve.r630-01.d-bis.org, https://pve.r630-02.d-bis.org"
|
||||
201
scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh
Executable file
201
scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh
Executable file
@@ -0,0 +1,201 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Load IP configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
|
||||
# Update existing NPMplus proxy hosts via API with correct VMIDs and IPs
|
||||
# This script updates existing proxy hosts, not creates new ones
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Preserve NPM credentials from environment so "export NPM_PASSWORD=...; ./script" works
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
set +u
|
||||
# shellcheck source=/dev/null
|
||||
source "$PROJECT_ROOT/.env"
|
||||
set -u
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
fi
|
||||
[ -f "$PROJECT_ROOT/config/ip-addresses.conf" ] && source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true
|
||||
|
||||
# Default .167: NPMplus (VMID 10233) reachable on ${IP_NPMPLUS:-${IP_NPMPLUS:-192.168.11.167}}:81; set NPM_URL in .env to override
|
||||
NPM_URL="${NPM_URL:-https://${IP_NPMPLUS}:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-nsatoshi2007@hotmail.com}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "❌ NPM_PASSWORD is required. Set it in .env or export NPM_PASSWORD=..."
|
||||
echo " Example: echo 'NPM_PASSWORD=your-password' >> $PROJECT_ROOT/.env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔄 Updating NPMplus Proxy Hosts via API"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Connection check (NPMplus is on LAN 192.168.11.x). Try alternate IP if .166/.167 unreachable.
|
||||
echo "🔐 Authenticating to NPMplus..."
|
||||
if ! curl -s -k -o /dev/null --connect-timeout 5 "$NPM_URL/" 2>/dev/null; then
|
||||
alt_url=""
|
||||
if [[ "$NPM_URL" == *"192.168.11.166"* ]]; then
|
||||
alt_url="${NPM_URL//192.168.11.166/192.168.11.167}"
|
||||
elif [[ "$NPM_URL" == *"192.168.11.167"* ]]; then
|
||||
alt_url="${NPM_URL//192.168.11.167/192.168.11.166}"
|
||||
fi
|
||||
if [ -n "$alt_url" ] && curl -s -k -o /dev/null --connect-timeout 5 "$alt_url/" 2>/dev/null; then
|
||||
NPM_URL="$alt_url"
|
||||
echo " Using alternate NPMplus URL: $NPM_URL"
|
||||
else
|
||||
echo "❌ Cannot connect to NPMplus at $NPM_URL"
|
||||
[ -n "$alt_url" ] && echo " Tried alternate: $alt_url"
|
||||
echo " Run this script from a host on the same LAN as NPMplus (e.g. 192.168.11.x). Ensure container 10233 is running."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$AUTH_JSON")
|
||||
|
||||
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 '.message // .error.message // .error // "Unknown error"' 2>/dev/null || echo "")
|
||||
echo "❌ Authentication failed: ${ERROR_MSG:-No token in response}"
|
||||
# Show response (first 300 chars) to help debug
|
||||
RESP_PREVIEW=$(echo "$TOKEN_RESPONSE" | head -c 300)
|
||||
if [ -n "$RESP_PREVIEW" ]; then
|
||||
echo " Response: $RESP_PREVIEW"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Authentication successful"
|
||||
echo ""
|
||||
|
||||
# Get all proxy hosts
|
||||
echo "📋 Fetching existing proxy hosts..."
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Failed to fetch proxy hosts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to update proxy host
|
||||
# block_exploits: set false for RPC hosts (JSON-RPC uses POST to /; block_exploits can cause 405)
|
||||
update_proxy_host() {
|
||||
local domain=$1
|
||||
local target=$2
|
||||
local websocket=$3
|
||||
local block_exploits=${4:-true}
|
||||
|
||||
# Parse target URL
|
||||
local scheme=$(echo "$target" | sed -E 's|^([^:]+):.*|\1|')
|
||||
local hostname=$(echo "$target" | sed -E 's|^[^/]+//([^:]+):.*|\1|')
|
||||
local port=$(echo "$target" | sed -E 's|^[^:]+://[^:]+:([0-9]+).*|\1|')
|
||||
|
||||
# Handle https URLs
|
||||
if [[ "$target" == https://* ]]; then
|
||||
scheme="https"
|
||||
hostname=$(echo "$target" | sed -E 's|^https://([^:]+):.*|\1|')
|
||||
port=$(echo "$target" | sed -E 's|^https://[^:]+:([0-9]+).*|\1|' || echo "443")
|
||||
fi
|
||||
|
||||
# Get host ID - domain_names is an array in the API response
|
||||
HOST_ID=$(echo "$PROXY_HOSTS_JSON" | jq -r ".[] | select(.domain_names | type == \"array\") | select(.domain_names[] == \"$domain\") | .id" 2>/dev/null | head -n1 || echo "")
|
||||
|
||||
if [ -z "$HOST_ID" ] || [ "$HOST_ID" = "null" ]; then
|
||||
echo "⚠️ Domain $domain not found (skipping)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "📋 Updating $domain (ID: $HOST_ID)..."
|
||||
|
||||
# Create minimal update payload - NPMplus API only accepts specific fields
|
||||
# block_exploits must be false for RPC so POST to / is allowed (JSON-RPC)
|
||||
BLOCK_EXPLOITS_JSON="false"
|
||||
[ "$block_exploits" = "true" ] && BLOCK_EXPLOITS_JSON="true"
|
||||
UPDATE_PAYLOAD=$(jq -n \
|
||||
--arg scheme "$scheme" \
|
||||
--arg hostname "$hostname" \
|
||||
--argjson port "$(echo "$port" | sed 's/[^0-9]//g')" \
|
||||
--argjson websocket "$websocket" \
|
||||
--argjson block_exploits "$BLOCK_EXPLOITS_JSON" \
|
||||
'{
|
||||
forward_scheme: $scheme,
|
||||
forward_host: $hostname,
|
||||
forward_port: $port,
|
||||
allow_websocket_upgrade: $websocket,
|
||||
block_exploits: $block_exploits
|
||||
}' 2>/dev/null || echo "")
|
||||
|
||||
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 "$UPDATE_PAYLOAD")
|
||||
|
||||
UPDATE_ID=$(echo "$UPDATE_RESPONSE" | jq -r '.id // empty' 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$UPDATE_ID" ] && [ "$UPDATE_ID" != "null" ]; then
|
||||
echo " ✅ Updated: $scheme://$hostname:$port (WebSocket: $websocket)"
|
||||
return 0
|
||||
else
|
||||
ERROR=$(echo "$UPDATE_RESPONSE" | jq -r '.error.message // .error // "Unknown error"' 2>/dev/null || echo "$UPDATE_RESPONSE")
|
||||
echo " ❌ Failed: $ERROR"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Update all domains
|
||||
updated_count=0
|
||||
failed_count=0
|
||||
|
||||
# Blockscout - Port 80 (nginx serves web UI, proxies /api/* to 4000 internally)
|
||||
update_proxy_host "explorer.d-bis.org" "http://${IP_BLOCKSCOUT}:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
# RPC hosts: block_exploits must be false so POST to / works (JSON-RPC)
|
||||
update_proxy_host "rpc-http-pub.d-bis.org" "http://${RPC_PUBLIC_1}:8545" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc-ws-pub.d-bis.org" "http://${RPC_PUBLIC_1}:8546" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc-http-prv.d-bis.org" "http://${RPC_CORE_1}:8545" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc-ws-prv.d-bis.org" "http://${RPC_CORE_1}:8546" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
# RPC Core-2 (Nathan) is on the THIRD NPMplus (192.168.11.169) — use add-rpc-core-2-npmplus-proxy.sh and update-npmplus-alltra-hybx-proxy-hosts.sh
|
||||
update_proxy_host "rpc.public-0138.defi-oracle.io" "https://${RPC_THIRDWEB_PRIMARY}:443" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
# rpc.defi-oracle.io / wss.defi-oracle.io → same backend as rpc-http-pub / rpc-ws-pub (VMID 2201)
|
||||
update_proxy_host "rpc.defi-oracle.io" "http://${RPC_PUBLIC_1}:8545" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "wss.defi-oracle.io" "http://${RPC_PUBLIC_1}:8546" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
# rpc.d-bis.org / rpc2.d-bis.org and WS variants → VMID 2201 (besu-rpc-public-1)
|
||||
update_proxy_host "rpc.d-bis.org" "http://${RPC_PUBLIC_1}:8545" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc2.d-bis.org" "http://${RPC_PUBLIC_1}:8545" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "ws.rpc.d-bis.org" "http://${RPC_PUBLIC_1}:8546" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "ws.rpc2.d-bis.org" "http://${RPC_PUBLIC_1}:8546" true false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "dbis-admin.d-bis.org" "http://${IP_DBIS_FRONTEND:-192.168.11.130}:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "dbis-api.d-bis.org" "http://${IP_DBIS_API:-192.168.11.155}:3000" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "dbis-api-2.d-bis.org" "http://${IP_DBIS_API_2:-192.168.11.156}:3000" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "secure.d-bis.org" "http://${IP_DBIS_FRONTEND:-192.168.11.130}:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
# MIM4U - VMID 7810 (mim-web-1) @ ${IP_MIM_WEB:-192.168.11.37} - Web Frontend serves main site and proxies /api/* to 7811
|
||||
update_proxy_host "mim4u.org" "http://${IP_MIM_WEB:-192.168.11.37}:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "secure.mim4u.org" "http://${IP_MIM_WEB:-192.168.11.37}:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "training.mim4u.org" "http://${IP_MIM_WEB:-192.168.11.37}:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📊 Summary"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "✅ Updated: $updated_count"
|
||||
echo "❌ Failed: $failed_count"
|
||||
echo ""
|
||||
163
scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh.bak
Executable file
163
scripts/nginx-proxy-manager/update-npmplus-proxy-hosts-api.sh.bak
Executable file
@@ -0,0 +1,163 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Update existing NPMplus proxy hosts via API with correct VMIDs and IPs
|
||||
# This script updates existing proxy hosts, not creates new ones
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Preserve NPM credentials from environment so "export NPM_PASSWORD=...; ./script" works
|
||||
_orig_npm_url="${NPM_URL:-}"
|
||||
_orig_npm_email="${NPM_EMAIL:-}"
|
||||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
set +u
|
||||
# shellcheck source=/dev/null
|
||||
source "$PROJECT_ROOT/.env"
|
||||
set -u
|
||||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||||
fi
|
||||
|
||||
# Default .167: NPMplus (VMID 10233) reachable on 192.168.11.167:81; set NPM_URL in .env to override
|
||||
NPM_URL="${NPM_URL:-https://192.168.11.167:81}"
|
||||
NPM_EMAIL="${NPM_EMAIL:-nsatoshi2007@hotmail.com}"
|
||||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||||
|
||||
if [ -z "$NPM_PASSWORD" ]; then
|
||||
echo "❌ NPM_PASSWORD is required. Set it in .env or export NPM_PASSWORD=..."
|
||||
echo " Example: echo 'NPM_PASSWORD=your-password' >> $PROJECT_ROOT/.env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🔄 Updating NPMplus Proxy Hosts via API"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Authenticate (use jq to build JSON so password is safely escaped)
|
||||
echo "🔐 Authenticating to NPMplus..."
|
||||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$AUTH_JSON")
|
||||
|
||||
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 ""
|
||||
|
||||
# Get all proxy hosts
|
||||
echo "📋 Fetching existing proxy hosts..."
|
||||
PROXY_HOSTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Failed to fetch proxy hosts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to update proxy host
|
||||
update_proxy_host() {
|
||||
local domain=$1
|
||||
local target=$2
|
||||
local websocket=$3
|
||||
|
||||
# Parse target URL
|
||||
local scheme=$(echo "$target" | sed -E 's|^([^:]+):.*|\1|')
|
||||
local hostname=$(echo "$target" | sed -E 's|^[^/]+//([^:]+):.*|\1|')
|
||||
local port=$(echo "$target" | sed -E 's|^[^:]+://[^:]+:([0-9]+).*|\1|')
|
||||
|
||||
# Handle https URLs
|
||||
if [[ "$target" == https://* ]]; then
|
||||
scheme="https"
|
||||
hostname=$(echo "$target" | sed -E 's|^https://([^:]+):.*|\1|')
|
||||
port=$(echo "$target" | sed -E 's|^https://[^:]+:([0-9]+).*|\1|' || echo "443")
|
||||
fi
|
||||
|
||||
# Get host ID - domain_names is an array in the API response
|
||||
HOST_ID=$(echo "$PROXY_HOSTS_JSON" | jq -r ".[] | select(.domain_names | type == \"array\") | select(.domain_names[] == \"$domain\") | .id" 2>/dev/null | head -n1 || echo "")
|
||||
|
||||
if [ -z "$HOST_ID" ] || [ "$HOST_ID" = "null" ]; then
|
||||
echo "⚠️ Domain $domain not found (skipping)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "📋 Updating $domain (ID: $HOST_ID)..."
|
||||
|
||||
# Create minimal update payload - NPMplus API only accepts specific fields
|
||||
# Must use forward_host (not forward_hostname) and locations must be array if present
|
||||
UPDATE_PAYLOAD=$(jq -n \
|
||||
--arg scheme "$scheme" \
|
||||
--arg hostname "$hostname" \
|
||||
--argjson port "$(echo "$port" | sed 's/[^0-9]//g')" \
|
||||
--argjson websocket "$websocket" \
|
||||
'{
|
||||
forward_scheme: $scheme,
|
||||
forward_host: $hostname,
|
||||
forward_port: $port,
|
||||
allow_websocket_upgrade: $websocket
|
||||
}' 2>/dev/null || echo "")
|
||||
|
||||
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 "$UPDATE_PAYLOAD")
|
||||
|
||||
UPDATE_ID=$(echo "$UPDATE_RESPONSE" | jq -r '.id // empty' 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$UPDATE_ID" ] && [ "$UPDATE_ID" != "null" ]; then
|
||||
echo " ✅ Updated: $scheme://$hostname:$port (WebSocket: $websocket)"
|
||||
return 0
|
||||
else
|
||||
ERROR=$(echo "$UPDATE_RESPONSE" | jq -r '.error.message // .error // "Unknown error"' 2>/dev/null || echo "$UPDATE_RESPONSE")
|
||||
echo " ❌ Failed: $ERROR"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Update all domains
|
||||
updated_count=0
|
||||
failed_count=0
|
||||
|
||||
# Blockscout - Port 80 (nginx serves web UI, proxies /api/* to 4000 internally)
|
||||
update_proxy_host "explorer.d-bis.org" "http://192.168.11.140:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc-http-pub.d-bis.org" "http://192.168.11.221:8545" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc-ws-pub.d-bis.org" "http://192.168.11.221:8546" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc-http-prv.d-bis.org" "http://192.168.11.211:8545" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc-ws-prv.d-bis.org" "http://192.168.11.211:8546" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc.public-0138.defi-oracle.io" "https://192.168.11.240:443" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
# rpc.defi-oracle.io / wss.defi-oracle.io → same backend as rpc-http-pub / rpc-ws-pub (VMID 2201)
|
||||
update_proxy_host "rpc.defi-oracle.io" "http://192.168.11.221:8545" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "wss.defi-oracle.io" "http://192.168.11.221:8546" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
# rpc.d-bis.org / rpc2.d-bis.org and WS variants → VMID 2201 (besu-rpc-public-1)
|
||||
update_proxy_host "rpc.d-bis.org" "http://192.168.11.221:8545" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "rpc2.d-bis.org" "http://192.168.11.221:8545" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "ws.rpc.d-bis.org" "http://192.168.11.221:8546" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "ws.rpc2.d-bis.org" "http://192.168.11.221:8546" true && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "dbis-admin.d-bis.org" "http://192.168.11.130:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "dbis-api.d-bis.org" "http://192.168.11.155:3000" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "dbis-api-2.d-bis.org" "http://192.168.11.156:3000" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "secure.d-bis.org" "http://192.168.11.130:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
# MIM4U - VMID 7810 (mim-web-1) @ 192.168.11.37 - Web Frontend serves main site and proxies /api/* to 7811
|
||||
update_proxy_host "mim4u.org" "http://192.168.11.37:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "secure.mim4u.org" "http://192.168.11.37:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
update_proxy_host "training.mim4u.org" "http://192.168.11.37:80" false && updated_count=$((updated_count + 1)) || failed_count=$((failed_count + 1))
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📊 Summary"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "✅ Updated: $updated_count"
|
||||
echo "❌ Failed: $failed_count"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user