DEV Community
Follow
Nineteen Subdomains, One Allowed IP
A wildcard DNS record enables easy service publishing by automatically resolving any subdomain to a single IP address. Nginx Proxy Manager (NPM) simplifies publishing further, requiring only a few fields to expose services securely with HTTPS. This automation led to the creation of nineteen proxy hosts, all running self-hosted software with varying authentication methods. The core problem identified is that the ease of publishing bypasses critical security decisions about access control.The author's goal was not to hide services entirely but to make them accessible only from a private network built on public infrastructure. The wildcard DNS record, while simplifying setup, does not inherently provide security. NPM uses HTTP-01 challenges for Let's Encrypt certificates, necessitating port 80 to remain open, which is a security vulnerability. A wildcard certificate via DNS-01 would allow port 80 to close but requires granting write access to the DNS zone.Services are published by placing their containers on a shared Docker network, allowing NPM to proxy requests internally. This means services do not need to expose ports directly to the host, enhancing security. A self-hosted proxy gateway on the same VPS routes traffic back to NPM, appearing as inbound HTTPS from the VPS’s public IP. This gateway's behavior, initially mistaken for a routing fault, is integral to the security design.NPM enforces access control using Nginx configuration blocks that allow requests only from the gateway's internal Docker IP or the VPS's public IP, followed by basic HTTP authentication. This ensures that even though services are publicly resolvable and have valid certificates, access is restricted. A specific location for Let's Encrypt challenges remains open to the internet, as required for certificate validation. Two critical hosts, the gateway's admin panel and a config distribution endpoint, are exceptions to the strict access control, as they need to be accessible before full gateway integration.A significant issue arose when a service, which baked its server address into user connection profiles, mistakenly advertised the wrong address. Because NPM forwards the real client IP via the X-Forwarded-For header, the service interpreted this header as its own public address, leading clients to connect to the wrong server. This bug was hidden because the author's own testing, using the gateway, always presented the correct expected address. TLS termination occurs at NPM, with traffic between NPM and backend containers transmitted as unencrypted HTTP over the Docker network.