#!/bin/bash # Complete Path Review: DNS → UDM Pro → NPMplus → VMID 5000 # Reviews all hops and configurations without tunnel set -uo pipefail DOMAIN="explorer.d-bis.org" PUBLIC_IP="76.53.10.36" NPMPLUS_IP="192.168.11.166" NPMPLUS_VMID="10233" NPMPLUS_NODE="r630-01" VM_IP="192.168.11.140" VMID=5000 VM_NODE="r630-02" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' echo "==========================================" echo "Complete Path Review: DNS to VM Service" echo "==========================================" echo "Domain: $DOMAIN" echo "Path: DNS → UDM Pro → NPMplus → VMID 5000" echo "==========================================" echo "" ISSUES=0 # ============================================ # HOP 1: DNS Resolution # ============================================ echo -e "${CYAN}=== HOP 1: DNS Resolution ===${NC}" DNS_IP=$(dig +short $DOMAIN A 2>/dev/null | head -1 || echo "") if [ -n "$DNS_IP" ]; then if [ "$DNS_IP" = "$PUBLIC_IP" ]; then echo -e "${GREEN}✅ DNS A Record:${NC} $DOMAIN → $DNS_IP (Correct)" else echo -e "${RED}❌ DNS A Record:${NC} $DOMAIN → $DNS_IP (Expected: $PUBLIC_IP)" ((ISSUES++)) fi else echo -e "${RED}❌ DNS A Record: Not found${NC}" ((ISSUES++)) fi # Check Cloudflare DNS mode echo "Checking Cloudflare DNS configuration..." CLOUDFLARE_MODE=$(curl -s "https://api.cloudflare.com/client/v4/zones" \ -H "Authorization: Bearer $CF_API_TOKEN" \ -H "Content-Type: application/json" 2>/dev/null | \ jq -r ".result[] | select(.name==\"d-bis.org\") | .id" 2>/dev/null || echo "") if [ -n "$CLOUDFLARE_MODE" ]; then echo -e "${GREEN}✅ Cloudflare zone found${NC}" echo " Expected: DNS Only (gray cloud) mode" else echo -e "${YELLOW}⚠️ Cannot verify Cloudflare DNS mode${NC}" fi echo "" # ============================================ # HOP 2: UDM Pro Port Forwarding # ============================================ echo -e "${CYAN}=== HOP 2: UDM Pro Port Forwarding ===${NC}" echo "Expected UDM Pro NAT Rules:" echo " - $PUBLIC_IP:80 → $NPMPLUS_IP:80 (HTTP)" echo " - $PUBLIC_IP:443 → $NPMPLUS_IP:443 (HTTPS)" # Check if we can reach NPMplus from public IP perspective echo "Testing port forwarding..." # Note: We can't directly check UDM Pro config, but we can test connectivity # Test if NPMplus is reachable on expected ports if timeout 3 bash -c "echo > /dev/tcp/$NPMPLUS_IP/80" 2>/dev/null; then echo -e "${GREEN}✅ NPMplus port 80 is reachable${NC}" else echo -e "${RED}❌ NPMplus port 80 is NOT reachable${NC}" ((ISSUES++)) fi if timeout 3 bash -c "echo > /dev/tcp/$NPMPLUS_IP/443" 2>/dev/null; then echo -e "${GREEN}✅ NPMplus port 443 is reachable${NC}" else echo -e "${YELLOW}⚠️ NPMplus port 443 is NOT reachable${NC}" fi echo "" # ============================================ # HOP 3: NPMplus Service & Configuration # ============================================ echo -e "${CYAN}=== HOP 3: NPMplus Service & Configuration ===${NC}" # Check NPMplus container status echo "Checking NPMplus container (VMID $NPMPLUS_VMID on $NPMPLUS_NODE)..." NPMPLUS_STATUS=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$NPMPLUS_NODE 'pct status $NPMPLUS_VMID 2>/dev/null | awk \"{print \\\$2}\"'" 2>/dev/null || echo "unknown") if [ "$NPMPLUS_STATUS" = "running" ]; then echo -e "${GREEN}✅ NPMplus container is running${NC}" else echo -e "${RED}❌ NPMplus container is NOT running (status: $NPMPLUS_STATUS)${NC}" ((ISSUES++)) fi # Check NPMplus docker container echo "Checking NPMplus docker service..." NPMPLUS_DOCKER=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$NPMPLUS_NODE 'pct exec $NPMPLUS_VMID -- docker ps | grep npmplus'" 2>/dev/null || echo "") if [ -n "$NPMPLUS_DOCKER" ]; then echo -e "${GREEN}✅ NPMplus docker container is running${NC}" else echo -e "${RED}❌ NPMplus docker container is NOT running${NC}" ((ISSUES++)) fi # Check NPMplus listening ports echo "Checking NPMplus listening ports..." NPMPLUS_PORTS=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$NPMPLUS_NODE 'pct exec $NPMPLUS_VMID -- ss -tlnp | grep -E \":80 |:443 \" | grep LISTEN'" 2>/dev/null || echo "") if echo "$NPMPLUS_PORTS" | grep -q ":80"; then echo -e "${GREEN}✅ NPMplus listening on port 80${NC}" else echo -e "${RED}❌ NPMplus NOT listening on port 80${NC}" ((ISSUES++)) fi if echo "$NPMPLUS_PORTS" | grep -q ":443"; then echo -e "${GREEN}✅ NPMplus listening on port 443${NC}" else echo -e "${YELLOW}⚠️ NPMplus NOT listening on port 443${NC}" fi # Get NPMplus proxy host configuration echo "Checking NPMplus proxy host configuration for $DOMAIN..." NPMPLUS_CONFIG=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$NPMPLUS_NODE 'pct exec $NPMPLUS_VMID -- docker exec npmplus node -e \" const Database = require(\\\"better-sqlite3\\\"); const db = new Database(\\\"/data/npmplus/database.sqlite\\\", { readonly: true }); const host = db.prepare(\\\"SELECT id, domain_names, forward_scheme, forward_host, forward_port, ssl_forced, enabled FROM proxy_host WHERE domain_names LIKE \\\\\\\"%$DOMAIN%\\\\\\\"\\\").get(); console.log(JSON.stringify(host || {})); db.close(); \" 2>&1'" 2>/dev/null || echo "{}") if echo "$NPMPLUS_CONFIG" | jq -e '.forward_host' >/dev/null 2>&1; then FORWARD_HOST=$(echo "$NPMPLUS_CONFIG" | jq -r '.forward_host // "unknown"') FORWARD_PORT=$(echo "$NPMPLUS_CONFIG" | jq -r '.forward_port // "unknown"') FORWARD_SCHEME=$(echo "$NPMPLUS_CONFIG" | jq -r '.forward_scheme // "unknown"') SSL_FORCED=$(echo "$NPMPLUS_CONFIG" | jq -r '.ssl_forced // false') ENABLED=$(echo "$NPMPLUS_CONFIG" | jq -r '.enabled // false') echo -e "${GREEN}✅ NPMplus Proxy Host Configuration Found:${NC}" echo " Domain: $DOMAIN" echo " Forward Scheme: $FORWARD_SCHEME" echo " Forward Host: $FORWARD_HOST" echo " Forward Port: $FORWARD_PORT" echo " SSL Forced: $SSL_FORCED" echo " Enabled: $ENABLED" # Verify configuration if [ "$ENABLED" != "true" ]; then echo -e "${RED} ❌ Proxy host is DISABLED!${NC}" ((ISSUES++)) fi if [ "$FORWARD_HOST" != "$VM_IP" ]; then echo -e "${RED} ❌ Forward host mismatch! Expected: $VM_IP, Got: $FORWARD_HOST${NC}" ((ISSUES++)) fi if [ "$FORWARD_PORT" != "80" ]; then echo -e "${RED} ❌ Forward port mismatch! Expected: 80, Got: $FORWARD_PORT${NC}" ((ISSUES++)) fi if [ "$FORWARD_SCHEME" != "http" ]; then echo -e "${YELLOW} ⚠️ Forward scheme is $FORWARD_SCHEME (expected http)${NC}" fi else echo -e "${RED}❌ NPMplus proxy host NOT configured for $DOMAIN${NC}" ((ISSUES++)) fi # Test NPMplus to target VM connectivity echo "Testing NPMplus to target VM connectivity..." NPMPLUS_TO_VM=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$NPMPLUS_NODE 'pct exec $NPMPLUS_VMID -- curl -s -o /dev/null -w \"%{http_code}\" --connect-timeout 5 http://$VM_IP:80/ 2>/dev/null'" 2>/dev/null || echo "000") if [ "$NPMPLUS_TO_VM" = "200" ]; then echo -e "${GREEN}✅ NPMplus can reach target VM (HTTP $NPMPLUS_TO_VM)${NC}" else echo -e "${RED}❌ NPMplus cannot reach target VM (HTTP $NPMPLUS_TO_VM)${NC}" ((ISSUES++)) fi echo "" # ============================================ # HOP 4: Target VM (VMID 5000) Configuration # ============================================ echo -e "${CYAN}=== HOP 4: Target VM (VMID 5000) Configuration ===${NC}" # Check container status CONTAINER_STATUS=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$VM_NODE 'pct status $VMID 2>/dev/null | awk \"{print \\\$2}\"'" 2>/dev/null || echo "unknown") if [ "$CONTAINER_STATUS" = "running" ]; then echo -e "${GREEN}✅ Container VMID $VMID is running${NC}" else echo -e "${RED}❌ Container VMID $VMID is NOT running (status: $CONTAINER_STATUS)${NC}" ((ISSUES++)) fi # Check nginx service NGINX_STATUS=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$VM_NODE 'pct exec $VMID -- systemctl is-active nginx 2>/dev/null'" 2>/dev/null || echo "inactive") if [ "$NGINX_STATUS" = "active" ]; then echo -e "${GREEN}✅ Nginx service is running${NC}" else echo -e "${RED}❌ Nginx service is NOT running (status: $NGINX_STATUS)${NC}" ((ISSUES++)) fi # Check nginx listening on port 80 NGINX_PORT80=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$VM_NODE 'pct exec $VMID -- ss -tlnp | grep \":80 \" | grep LISTEN'" 2>/dev/null || echo "") if [ -n "$NGINX_PORT80" ]; then echo -e "${GREEN}✅ Nginx listening on port 80${NC}" echo " Details: $NGINX_PORT80" else echo -e "${RED}❌ Nginx NOT listening on port 80${NC}" ((ISSUES++)) fi # Check nginx configuration echo "Checking nginx configuration..." NGINX_CONFIG_EXISTS=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$VM_NODE 'pct exec $VMID -- test -f /etc/nginx/sites-available/blockscout && echo yes || echo no'" 2>/dev/null || echo "no") if [ "$NGINX_CONFIG_EXISTS" = "yes" ]; then echo -e "${GREEN}✅ Nginx configuration file exists${NC}" # Check server_name SERVER_NAME=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$VM_NODE 'pct exec $VMID -- grep -i \"server_name\" /etc/nginx/sites-available/blockscout | head -1'" 2>/dev/null || echo "") if echo "$SERVER_NAME" | grep -qi "$DOMAIN"; then echo -e "${GREEN} ✅ server_name includes $DOMAIN${NC}" else echo -e "${YELLOW} ⚠️ server_name may not include $DOMAIN${NC}" echo " Found: $SERVER_NAME" fi # Test nginx config NGINX_TEST=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$VM_NODE 'pct exec $VMID -- nginx -t 2>&1'" 2>/dev/null || echo "") if echo "$NGINX_TEST" | grep -q "test is successful"; then echo -e "${GREEN} ✅ Nginx configuration is valid${NC}" else echo -e "${RED} ❌ Nginx configuration has errors${NC}" echo "$NGINX_TEST" | head -5 ((ISSUES++)) fi else echo -e "${RED}❌ Nginx configuration file not found${NC}" ((ISSUES++)) fi # Check frontend file FRONTEND_EXISTS=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$VM_NODE 'pct exec $VMID -- test -f /var/www/html/index.html && echo yes || echo no'" 2>/dev/null || echo "no") if [ "$FRONTEND_EXISTS" = "yes" ]; then echo -e "${GREEN}✅ Frontend file exists${NC}" FRONTEND_SIZE=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$VM_NODE 'pct exec $VMID -- stat -c%s /var/www/html/index.html 2>/dev/null'" 2>/dev/null || echo "0") echo " File size: $FRONTEND_SIZE bytes" else echo -e "${RED}❌ Frontend file not found${NC}" ((ISSUES++)) fi # Test local HTTP response echo "Testing local HTTP response..." LOCAL_HTTP=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$VM_NODE 'pct exec $VMID -- curl -s -o /dev/null -w \"%{http_code}\" http://localhost:80/ 2>/dev/null'" 2>/dev/null || echo "000") if [ "$LOCAL_HTTP" = "200" ]; then echo -e "${GREEN}✅ Local HTTP response: HTTP $LOCAL_HTTP${NC}" else echo -e "${RED}❌ Local HTTP response: HTTP $LOCAL_HTTP${NC}" ((ISSUES++)) fi echo "" # ============================================ # End-to-End Path Test # ============================================ echo -e "${CYAN}=== End-to-End Path Test ===${NC}" echo "Testing complete path:" echo " 1. DNS: $DOMAIN → $PUBLIC_IP" echo " 2. UDM Pro: $PUBLIC_IP:80/443 → $NPMPLUS_IP:80/443" echo " 3. NPMplus: $DOMAIN → $VM_IP:80" echo " 4. VMID 5000: nginx → /var/www/html/index.html" echo "" # Test from NPMplus perspective echo "Testing from NPMplus..." NPMPLUS_RESPONSE=$(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 root@192.168.11.10 \ "ssh -o ConnectTimeout=5 root@$NPMPLUS_NODE 'pct exec $NPMPLUS_VMID -- curl -s -H \"Host: $DOMAIN\" -o /dev/null -w \"%{http_code}\" --connect-timeout 5 http://$VM_IP:80/ 2>/dev/null'" 2>/dev/null || echo "000") if [ "$NPMPLUS_RESPONSE" = "200" ]; then echo -e "${GREEN}✅ NPMplus can serve $DOMAIN (HTTP $NPMPLUS_RESPONSE)${NC}" else echo -e "${RED}❌ NPMplus cannot serve $DOMAIN (HTTP $NPMPLUS_RESPONSE)${NC}" ((ISSUES++)) fi # Test external access (if possible) echo "Testing external domain access..." EXTERNAL_RESPONSE=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 5 --max-time 10 "https://$DOMAIN" 2>/dev/null || echo "000") if [ "$EXTERNAL_RESPONSE" = "200" ] || [ "$EXTERNAL_RESPONSE" = "301" ] || [ "$EXTERNAL_RESPONSE" = "302" ]; then echo -e "${GREEN}✅ External domain access: HTTP $EXTERNAL_RESPONSE${NC}" elif [ "$EXTERNAL_RESPONSE" = "000" ]; then echo -e "${YELLOW}⚠️ External domain access: Timeout (may be firewall/network issue)${NC}" else echo -e "${YELLOW}⚠️ External domain access: HTTP $EXTERNAL_RESPONSE${NC}" fi echo "" # ============================================ # Summary & Recommendations # ============================================ echo "==========================================" echo "Summary & Recommendations" echo "==========================================" echo "" if [ $ISSUES -eq 0 ]; then echo -e "${GREEN}✅ All hops are configured correctly!${NC}" echo "" echo "Path Status:" echo " ✅ DNS → $PUBLIC_IP" echo " ✅ UDM Pro → $NPMPLUS_IP" echo " ✅ NPMplus → $VM_IP:80" echo " ✅ VMID 5000 → nginx serving frontend" echo "" echo "If external access is still not working:" echo " 1. Check UDM Pro firewall rules" echo " 2. Verify UDM Pro port forwarding is active" echo " 3. Check network connectivity from internet to $PUBLIC_IP" else echo -e "${RED}❌ Found $ISSUES issue(s) that need to be fixed:${NC}" echo "" echo "Issues to address:" echo " 1. Review each hop above for ❌ failures" echo " 2. Fix configuration mismatches" echo " 3. Ensure all services are running" echo " 4. Verify network connectivity" fi echo ""