Tutorial 2024/06: HAProxy + Let's Encrypt Wildcard Certificates + 100% A+ Rating

Started by TheHellSite, May 31, 2021, 01:06:11 PM

Previous topic - Next topic
I have a somewhat difficult question: How can I implement a rule to allow "local" traffic only for specific named backends?

That means, I want to selectively block external access for specific domains.

I know how this works for IPv4: you can simply create a rule with a condition based on RFC1918 IPs and create a 4xx response if if does not match.

However, my situation is that my LAN clients use IPv6 GUAs generated from dynamic prefixes as assigned by my ISP, so I cannot specify the prefix to match. The WAN IPv6 is also from that prefix ("Request prefix only") and it is the target for the DNS names that HAproxy handles. Since that IPv6 always has more priority than any IPv4 or ULA IPv6, it will be the target for the HTTP(S) requests, thus NAT66 will not really cut it.

Access to lower layers than 4 is impossible within HAproxy, so I cannot use hop limits either. I have not even found a way to ask for the inbound interface because of this restriction.

All solutions I have pondered are too crude and involve scripting or using split DNS. Port-forwarding is also questionable, given the fact that there are internal layer 4 redirects to localhost with this setup already.
Intel N100, 4* I226-V, 2* 82559, 16 GByte, 500 GByte NVME, Leox LXT-010H-D

1100 down / 450 up, Bufferbloat A+

This is an excellent tutorial. I'm fairly new to opnsense, and this was a great start to get me going getting the services up and running. @TheHellSite I appreciate the work you have dedciated to it, despite your busy schedule. Thank you.

With OPNsense 26.1.9, some of the settings have moved or not available, so there were placed I had to think and google to proceed. Ideally, the guide should be updated, but I know its a big ask.

There isn't a need to enable NAT reflection it seems (which puzzled me a little bit why it was working to connect from LAN). What I think happens is when a package from LAN destined for the public IP, opnsense will see that the package is for itself using its public facing IP and send it directly to HAproxy without NAT due to its `0.0.0.0:443` listen of `0_SNI_frontend`. So perhaps "part 6" should be updated? I'm left with the open question: When do we use option A) Split DNS or B) NAT reflection when option 0) Do nothing seems to work?

Is it always necessary to create a backend and a server when there is 1 to 1 relationship between the two? Can it be combined somehow? I assume this is a core design of HAProxy?

Part 6 in the tutorial adds support for hosting public services as well as internal services. This works great, but after some consideration I deemed it too risky. The safety of the internal services ending up publicly on the net is the src address condition rule. In addition, the webui of OPNsense (currently 26.1.9) doesn't handle the order of the "select rules" where it is critical to get the order of the `LOCAL_SUBDOMAINS_rule` and the `PUBLIC_SUBDOMAINS_rule` to have a functioning setup. I deemed this too risky.

I was running 1_HTTP_frontend and 1_HTTPS_frontend directly to 0.0.0.0:80 and 0.0.0.0:443 respectively. I'm not running 0_SNI_frontend.

1. Clone 1_HTTP_frontend into 1_HTTP_WAN_frontend. Change the listen address to use the *WAN* address :80.
2. Clone 1_HTTP_frontend into 1_HTTP_LAN_frontend. Change the listen address to use the *LAN* address :80.
3. Disable 1_HTTP_frontend
4. Clone 1_HTTPS_frontend into 1_HTTPS_WAN_frontend. Change the listen address to use the *WAN* address :443. Under Select rules, select only the PUBLIC_SUBDOMAINS_rule.
5. Clone 1_HTTPS_frontend into 1_HTTPS_LAN_frontend. Change the listen address to use the *LAN* address :443. User Select rules, select only the LOCAL_SUBDOMAINS_rule.
6. Disable 1_HTTPS_frontend.
7. Press Apply

For this to work, one needs to override the external addresses to internal addresses.

8. Go to Unbound DNS -> Overrides.
9. Add a new entry. Set host, domain and entry. Use the IP for the *LAN* port from above. E.g. www, my.domain, A to 192.168.1.1.
10. Rinse an repeat for all entries that must be overridden.

My system just started have weird issues. I figured out it was related to this. Basically the ability to select a map file type is now available. When we started with this guide this option was not available and the map type was set to dom. With this configuration if you have domain.com before sub1.domain.com only domain.com's content will be returned.

After changing the type to str the expected behavior will resume.

Probably something to update in the first post @TheHellSite...

I second that. Different map file types should be mentioned in the tutorial.

I even use type "reg", because sometimes, I use HAproxy as a first-level reverse proxy for CG-NAT backends that are only reachable via IPv4.
I want to use that for *.domain.xyz (DOMAIN_dyndns), while keeping another local backend (DOMAIN_backend) for www.domain.xyz and domain.xyz.

This does not even work with map type "beg" and ".domain.xyz", because the first dot will be ignored. You have to use a regex map with a setup like:

(?i)^www\.domain\.xyz$            DOMAIN_backend
(?i)^.+\.domain\.xyz$             DOMAIN_dyndns
(?i)^domain\.xyz$                 DOMAIN_backend

Note the order, which is relevant for "reg" maps.
Intel N100, 4* I226-V, 2* 82559, 16 GByte, 500 GByte NVME, Leox LXT-010H-D

1100 down / 450 up, Bufferbloat A+