Fix NPM forward host: use real host IP instead of Docker gateway

- npm_service._get_forward_host() now detects the actual host IP via
  UDP socket (works inside Docker containers) instead of using
  172.17.0.1 Docker gateway which NPM can't reach
- install.sh uses hostname -I for NPM forward host
- Removed npm_api_url parameter from _get_forward_host()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-08 20:45:01 +01:00
parent 55e2c3b80b
commit b56f0eb8a4
3 changed files with 20 additions and 32 deletions

View File

@@ -224,7 +224,7 @@ async def deploy_customer(db: Session, customer_id: int) -> dict[str, Any]:
npm_proxy_id = None npm_proxy_id = None
npm_stream_id = None npm_stream_id = None
if not local_mode: if not local_mode:
forward_host = npm_service._get_forward_host(config.npm_api_url) forward_host = npm_service._get_forward_host()
npm_result = await npm_service.create_proxy_host( npm_result = await npm_service.create_proxy_host(
api_url=config.npm_api_url, api_url=config.npm_api_url,
npm_email=config.npm_api_email, npm_email=config.npm_api_email,

View File

@@ -13,8 +13,8 @@ Also manages NPM streams for STUN/TURN relay UDP ports.
""" """
import logging import logging
import socket
from typing import Any from typing import Any
from urllib.parse import urlparse
import httpx import httpx
@@ -24,34 +24,29 @@ logger = logging.getLogger(__name__)
NPM_TIMEOUT = 30 NPM_TIMEOUT = 30
def _get_forward_host(npm_api_url: str) -> str: def _get_forward_host() -> str:
"""Determine the IP/hostname to forward traffic to. """Detect the host machine's real IP address.
The NPM proxy host must forward to the MSP appliance's host IP, NPM proxy hosts must forward to the actual host IP where Docker
NOT to a Docker container name, because the customer's Caddy port mappings are exposed — NOT a container name or Docker gateway.
container exposes its port on the host via Docker port mapping.
We extract the host from the NPM API URL — if the admin configured Uses a UDP socket to determine the primary outbound IP address
``http://10.0.0.5:81/api``, we forward to ``10.0.0.5``. of the host (works inside Docker containers).
If the admin configured ``http://npm:81/api`` (container name),
we fall back to the Docker gateway IP ``172.17.0.1``.
Args:
npm_api_url: The NPM API base URL from system config.
Returns: Returns:
IP address or hostname to forward to. The host's primary IP address (e.g. ``192.168.26.191``).
""" """
parsed = urlparse(npm_api_url) try:
host = parsed.hostname or "172.17.0.1" s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
# If the host looks like a container name (no dots, not an IP), use Docker gateway host_ip = s.getsockname()[0]
if not any(c == "." for c in host) and not host.startswith("172.") and host != "localhost": s.close()
logger.info("NPM URL host '%s' looks like a container name, using Docker gateway 172.17.0.1", host) logger.info("Detected host IP: %s", host_ip)
return host_ip
except Exception:
logger.warning("Could not detect host IP, falling back to 172.17.0.1")
return "172.17.0.1" return "172.17.0.1"
return host
async def _npm_login(client: httpx.AsyncClient, api_url: str, email: str, password: str) -> str: async def _npm_login(client: httpx.AsyncClient, api_url: str, email: str, password: str) -> str:
"""Authenticate with NPM and return a JWT token. """Authenticate with NPM and return a JWT token.

View File

@@ -442,15 +442,8 @@ if [ -n "$MSP_DOMAIN" ]; then
echo "" echo ""
echo -e "${CYAN}Creating NPM proxy host for MSP Appliance (${MSP_DOMAIN})...${NC}" echo -e "${CYAN}Creating NPM proxy host for MSP Appliance (${MSP_DOMAIN})...${NC}"
# Determine forward host from NPM API URL # Use the actual host IP for NPM forwarding (not Docker gateway!)
NPM_HOST=$(echo "$NPM_API_URL" | sed -E 's|https?://([^:/]+).*|\1|') FORWARD_HOST=$(hostname -I | awk '{print $1}')
# If host looks like a container name (no dots), use Docker gateway
if ! echo "$NPM_HOST" | grep -q '\.'; then
FORWARD_HOST="172.17.0.1"
else
FORWARD_HOST="$NPM_HOST"
fi
# Step 1: Login to NPM # Step 1: Login to NPM
NPM_TOKEN=$(curl -s -X POST "${NPM_API_URL}/tokens" \ NPM_TOKEN=$(curl -s -X POST "${NPM_API_URL}/tokens" \