Why you may need "Hairpin NAT" (NAT Reflection, NAT Loopback) for AIO/NC

Hello all,

When Nextcloud AIO is set up there are assumptions made about networking and DNS resolution that come into play from the start of the install, the “domain check” process, required to get AIO installed.

What is NAT?
Network Address Translation.
Many people use “RFC 1918” addresses on their private networks - these are specially reserved address ranges that cannot be routed on the Internet. NAT allows a lot of addresses to be “hidden” behind (originate from) a single address - it’s how you connect from your Internet provider to the Internet.

The “typical” AIO setup:
In this example say your internal Nextcloud server IP is 192.168.1.100 (private).
You have a static (or dynamic) IP of 130.57.66.5 (public).
Your domain (DNS) name is “nextcloud.yourdomain.com”.

When someone on the internet accesses “nextcloud.yourdomain.com” DNS points them to 130.57.66.5 which is translated to 192.168.1.100 by your firewall and is processed, returned as needed to the source. That’s NAT.

What is “Hairpin NAT”?
“Hairpin NAT” is causing a client to see a host’s external IP - from an internal network.

Why do you need to use “Hairpin NAT”? - Use Case 1
When your Nextcloud server at 192.168.1.100 resolves to “nextcloud.yourdomain.com” DNS resolves that name to130.57.66.5.

If 192.168.1.100 traffic is DNS going to google DNS server 8.8.8.8 it’s, from a firewall perspective:
192.168.1.100 (source) → 8.8.8.8 (destination) from 130.57.66.5 (NAT)
No problem there, normal NAT/

AIO/NC domain check & office assume your server can talk to itself over it’s EXTERNAL (public) IP - from a firewall perspective that’s not typical as the firewall sees the 192.168.1.100 traffic as locally connected.

The domain check function in AIO won’t accept RFC 1918 addresses so you can’t “fool” it by making 192.168.1.100 = “nextcloud.yourdomain.com”.

Solution?
You need to make 192.168.1.100 (the interface all of your docker containers access the Internet via - using NAT at the Linux Host/Docker level) see itself as 130.57.66.5.

In order to make this work your router/firewall must support “Hairpin NAT” and the creation of a “Virtual IP” (or VIP) - a virtual mapping of your internal server to an external address.

You will need to create a rule that is typically:
Source Network: LAN (192.168.1.0/24)
Desination Network: LAN (192.168.1.0/24)
Source: 192.168.1.100
Destination: “Virtual IP” of 192.168.1.100 (130.57.66.5)
Forwarding port: 443

This is in addition to the “default” policies:

  1. Inbound: Allowing Internet traffic to your server (typically using the same “Virtual IP” - source all, destination VIP, port 443) as well as
  2. Outbound: A generic “allow my host to the Internet” policy (from server private IP to destination all, port 80/443/53/25 or 587 - web, secure web, DNS, email)

This “Hairpin NAT” should allow the 192.168.1.100 server resolving “nextcloud.yourdomain.com” to 130.57.66.5 to trick the firewall into allowing your internal server to see itself using it’s external IP and port.

Yes, this means your firewall/router must support “Hairpin NAT” and you must have a port forward rule for each port you want to support inbound - 443 for SSL/HTTPS and 3478 if you are supporting a Talk server.

When “domaincheck” first runs it will see itself at 130.57.66.5 - the proper external (public) IP address for “nextcloud.yourdomain.com” and should be successful first time, everytime.

This should also work for Office - which needs to see “nextcloud.yourdomain.com” in the Collabora server URL.

In both cases this will work even if you are using a reverse proxy in front of AIO, or not.

Why do you need to use “Hairpin NAT”? - Use Case 2

Say you have an internal LAN that is 192.168.2.0/24 connected to your firewall/router.

Same process exists - resolve “nextcloud.yourdomain.com” to 130.57.66.5 and the router/firewall knows that 192.168.2.0 is a locally connected network and 130.57.66.5 = 192.168.1.100, on another locally connected network (perhaps a “DMZ” network).

If you are using DNS, even with your own server, “nextcloud.yourdomain.com” will resolve to 130.57.66.5.

While you could add your own DNS entries to make your 192.168.2.0/24 clients “see” “nextcloud.yourdomain.com” as 192.168.1.100 it’s additional configuration and if your nextcloud install is using your internal DNS can cause domaincheck to fail as it won’s support the 192 addresses in the check.

You need a way to make your internal clients “see” 192.168.1.100 as 130.57.66.5. How can you do that? Hairpin NAT again.

Create a rule as follows:
Source Network: LAN (192.168.2.0/24)
Desination Network: DMZ LAN (192.168.1.0/24)
Source: LAN (192.168.2.0/24)
Destination: “Virtual IP” of 192.168.1.100 (130.57.66.5)
Forwarding port: 443

This will allow your internal clients to resolve “nextcloud.yourdomain.com” to 130.57.66.5 without any DNS changes - and can also allow your nextcloud install, if using the same DNS, to be successfully installed.

If you have any questions please let me know.

2 Likes

Hi, thanks a lot for this post!

I wonder, would you mind posting this again here for better visibility?

Happy to help.

The post appears on the Wiki here:

Why you may (likely do) need “Hairpin NAT” (NAT Reflection, NAT Loopback) for AIO/Nextcloud · nextcloud/all-in-one · Discussion #5849

1 Like

@szaimen Maybe a silly question, but Is Hairpin NAT really needed for the domain check, and more importantly for Office to work in AIO, as suggested in @gp3’s post?

I’m asking because, to be honest, I’m not a big fan of Hairpin NAT, and if I were ever to set up AIO in my home network, I’d much prefer to use a proper split-brain DNS setup, as I already do now with my manually installed Nextcloud.

No, split-brain DNS is also supported.

However in case of AIOs “normal mode” where AIO manages its own TLS, the domain validation will block split-brain DNS as it cannot check if the instance is publicly reachable which is needed to make sure that the certificates can be created correctly. In that case, one can skip the domain validation though which should work as long as DNS and port-forwarding is correctly set up.

In “reverse proxy mode” where AIO is installed behind a reverse proxy, split-brain DNS is not blocked by the domain validation as the reverse proxy and thus TLS is set up before starting all the other containers and can thus be checked.

I hope this clarifies things a bit? :slight_smile:

1 Like

Split brain DNS is only supported, from my testing with AIO, if the domain name (really host name) used in the configuration does not resolve to an RFC 1918 address. The domaincheck process is configured to check to see if the resolved IP is an internet IP, not an internal IP. If you set the hostname to equal an RFC 1918 address the domain check will throw errors in the nextcloud-aio-mastercontainer logs.

My installations were no reverse proxy mode and reverse proxy mode.

Keep in mind that in AIO there may be a reverse proxy in play, it’s caddy resident on the nextcloud-aio-apache container to handle the collabora connections if using the integrated nextcloud office from the AIO installation.

In non-reverse proxy mode NAT is still in play - if you attempt to resolve yourservername.yourdomain.com it will return your public IP (130.57.66.5 in the example above). If you have not configured traffic originating from your server to “see” its external IP it won’t be able to curl the web page (itself, seen as 130.57.66.5). The domaincheck traffic is from a container on the bridge network, traffic NAT’d behind the linux host.

This is really no different than using a reverse proxy - I have installed both reverse proxy on the nextcloud-aio network and on a caddy network and connected to the nextcloud-aio network and as the reverse proxy is simply replacing port 443 on the nextcloud-aio-apache container later the install the traffic pattern is no different (unless your reverse proxy is on another host).

During the initial install the domaincheck creation only the nextcloud-aio-mastercontainer exists, you access the admin page via 8080 which spawns the domaincheck container which uses the apache port variable to impersonate the apache server to run the domaincheck.

While Nextcloud is trying to verify a domain by checking the resolvable DNS name and external IP of the server its on this creates potential issues in any installation.

In our case we still need a hairpin nat for the production server, port 443 and the talk port, for the internet lookback for both domaincheck and AIO Nextcloud office - and found out that policy NAT on our specific model of firewall broke the server to itself hairpin NAT but not the LAN to server hairpin.

If Nextcloud wants to support split brain DNS IMHO it needs to be clearly documented - or just change the domain checking process to validate a domain key another way as an option. Biggest problem installing NC was the domaincheck, the lack of logs (any logs) was a real problem.

Sorry, to clarify things:

What I meant with “normal mode” was APACHE_PORT is unset or set to 443.

What I meant with “reverse proxy mode” was APACHE_PORT is set to something else than 443.

I hope this clarifies things again :slight_smile:

Just as a follow up the reason we refused to skip the domain validation is that we then could not have back-end traffic encrypted in transit. It also didn’t fix the Nextcloud office issues we were having as that uses a Caddy reverse proxy installed by Nextcloud and resident on the apache container. Until we hairpinned the server nothing we did would make AIO Nextcloud Office work with our server URL.

No problem!

I think the install is very interesting.

IMHO many may assume all of the AIO containers are created when they execute the script - that’s not the case. The install really happens in two phases…

The Nextcloud-aio-mastercontainer comes up first (along with the creation of the nextcloud-aio network) and then when a person accesses the 8080 admin port the nextcloud-aio-domaincheck container is created - no others.

The nextcloud-aio-domaincheck will either use 443 (apache port, no reverse proxy install) or 11000 (apache port, reverse proxy install) to send traffic out of. In the second case your reverse proxy is responding on port 443 so in both cases the domaincheck is returned to the external IP of the port forward/NAT for :443 traffic, from an Internet perspective.

One of the challenges with the install script for “reverse proxy” is that by setting the apache port to 11000 and the nextcloud-aio network only being created once the install script is run it creates a catch-22 - you need your reverse proxy, but you can’t install it if the network(s) it requires are not created…

To get around that you need to start the AIO install, get the nextcloud-aio network created and then launch your reverse proxy install…

Additionally if your reverse proxy file uses the DNS name of the apache container - nextcloud-aio-apache - during the install you’ll need to change that to nextcloud-aio-domaincheck. Once the domain check has been completed you need to go back in and change it to apache…

The key is having :443 resolvable and curl’able using the external IP and DNS and not using an RFC 1918 address.

Only once the domain check process completes the other containers (nextcloud, apache, office, etc.) are created by the installation script.

Hello, I’m sorry, could you help me with setting up mikrotik? I’ve been trying to beat him for 2 months now. The domain check is not being checked.

@Iv_Dark Probably want to created your own dedicated thread for that.