Fix: Internal Access to Nginx Proxy Manager Fails (MikroTik Hairpin NAT)

Summary This document provides the network configuration required to resolve internal routing failures when local clients attempt to access self-hosted subdomains managed by Nginx Proxy Manager (NPM) using the network’s Public IP address.

Environment

  • Edge Router: MikroTik RouterOS
  • Reverse Proxy: Nginx Proxy Manager (NPM)
  • Local Subnet: 192.168.1.0/24
  • NPM Internal IP: 192.168.1.12
  • WAN (Public) IP: 80.80.80.125 (Example/Masked)

Problem External users from the internet can access all hosted subdomains (e.g., app.domain.com) without any issues. However, when devices inside the local network (192.168.1.0/24) attempt to access the exact same subdomains, the connection times out.

Symptoms

  • Services are fully operational from mobile data or external networks.
  • Accessing the services via the local Wi-Fi or LAN results in infinite loading or connection timeouts.
  • Accessing the NPM internal IP (192.168.1.12) directly via IP address works perfectly from the LAN.

Error Message

ERR_CONNECTION_TIMED_OUT
or
The site can't be reached.

Root Cause This issue is caused by a routing behavior known as Hairpin NAT (or NAT Loopback) limitation.

  1. A local client (192.168.1.X) requests app.domain.com, which DNS resolves to the Public IP (80.80.80.125).
  2. The MikroTik router receives the packet, applies the standard Port Forwarding (dst-nat) rule, and sends it to the NPM server (192.168.1.12).
  3. The NPM server processes the request and sees that the source IP belongs to the local client (192.168.1.X).
  4. Because they are on the same subnet, the NPM server replies directly to the client, bypassing the router.
  5. The client expects a reply from the Public IP (80.80.80.125), but receives a reply from the Private IP (192.168.1.12). Recognizing this as an invalid TCP handshake, the client’s operating system drops the packet, causing the timeout.

Solution To fix this, we must force the internal traffic to flow back through the MikroTik router so the source IP gets masqueraded. Two NAT rules are required:

  1. The Destination NAT (Port Forwarding): Directs incoming traffic on the Public IP to the internal NPM server.
  2. The Source NAT (Hairpin Masquerade): Ensures internal traffic going to the NPM server appears as if it is coming from the router itself, forcing the server to reply to the router, which then correctly replies to the client.

Apply the following commands in the MikroTik terminal:

Code snippet

/ip firewall nat
add chain=dstnat action=dst-nat to-addresses=192.168.1.12 dst-address=80.80.80.125 log=no log-prefix="" comment="Forward HTTP/HTTPS to NPM"
add chain=srcnat action=masquerade protocol=tcp src-address=192.168.1.0/24 dst-address=192.168.1.12 dst-port=80,443 comment="Hairpin NAT for NPM Local Access"

(Explanation of why the solution works: The srcnat rule rewrites the source IP of the local client to the router’s IP. The NPM server now sends the reply back to the router. The router reverses the NAT and sends the packet back to the client with the Public IP as the source, satisfying the TCP handshake.)

Verification

  1. Connect a laptop or smartphone to the local network (192.168.1.0/24).
  2. Flush the local DNS cache or open an Incognito browser window.
  3. Access the domain name [https://app.domain.com]. The site should now load instantly.

Lessons Learned

  • Always implement Hairpin NAT when hosting internal services accessible via a Public IP.
  • An alternative to Hairpin NAT is establishing a “Split DNS” architecture (e.g., configuring a local DNS server like Pi-hole to resolve app.domain.com directly to 192.168.1.12), but Hairpin NAT is a more robust solution at the router level when you don’t want to manage local DNS records.
  • Restricting the src-address to the local subnet (192.168.1.0/24) in the masquerade rule is critical for security; omitting it could create an open proxy.

References

  • MikroTik Official Documentation: Hairpin NAT

Related Articles

  • Currently, there are no related articles in this category. This section will be updated as more internal documentation is published.
Scroll to Top