[Guide] Reverse Proxy via HAProxy + ACME on pfSense

This is going to serve as a quick and dirty introduction to using HAProxy in tandem with ACME on your pfsense machine to serve some pages via reverse proxy with SSL/TLS encrypted traffic.

The ACME portion is optional, but it’s trivial and good practice. Note that while it makes it much easier, you don’t need a domain or a dynamic DNS service that allows TXT records to verify ownership. If you don’t have these options, the firewall can host the challenge file for validation via the Webroot Local Folder option, or the Standalone option worst-case.

First we’re going to quickly install the required packages - navigate to System->Package Manager->Available Packages; install acme and haproxy.

(OPTIONAL) Once those are ready, we're going to do the letsencrypt portion. (0:56)
  1. Navigate to Services->Acme Certificates->Account keys and press Add.
    Set a name, select the ACME server (Production ACME v2), set your email address, and press Create new account key to generate your key. Once the box is populated, press Register ACME account key and hit Save.

  2. Now that we’ve got an account key, we can make a cert. Navigate to Certificates and click Add. Fill in the name and description for your reference, and ensure the account you just made is selected below.
    Scroll down to Domain SAN List, this is where we validate your ownership of the destination on your cert. We’re going to operate as though you have a domain, but again this process does not require one - if your DDNS service allows TXT records (like DuckDNS), you can use that. If not, you can use webroot local folder with some HAProxy config, or the Standalone option.
    With our own domain, we’ll give ourselves a wildcard cert for subdomain usage. Enter the FQDN and the FQDN with an asterisk subdomain as two separate entries.
    For the method, select one that is an integration for your DNS provider if available, otherwise you’ll have to use manual (which will require a few extra steps).

After that, press Save. It will return us to the Certificates page with an Issue and Renew button next to our new entry.

  1. With anything other than the manual options, these buttons are a fire and forget solution - you click Issue to get the cert, it’ll tell you when it succeeds, and you’re set.
    With manual, you have to manually enter the keys it gives you as TXT records where your nameservers are managed, so there’s an additional step or two.

You’ll see that the Last renewed field is updated, that means your cert is valid.

Now we’ll do the actual reverse proxy steps, so

Navigate to `Services`->`HAProxy`->`Settings`. (3:12)
  1. Check the box at the top to enable HAProxy. Set your maximum connections to something around 1000.

  2. Set an internal stats port to enable the HAProxy status monitor, which is very convenient to identify outages or manage your load balancer.
    You can also optionally set up logging and alerts for a similar purpose here.

  3. We need to set our Diffie-Hellman size, so change Max SSL Diffie-Hellman size to 2048 under Tuning.

  4. Press Save followed by Apply Changes.

Let’s define our servers in some backends now.

Navigate to `Backend` and Press `Add`. (3:52)
  1. Enter a name - I generally use the subdomain or path I’m using.

  2. Add the server by pressing the arrow in the server list. Name it and enter the IP address and port that the service is listening on.

Note that you do not need to check Encrypt or enter any certificate information here, that’s all being handled by HAProxy, not your servers.

You can enter multiple servers for a single backend and set the mode to backup for failover or active for load balancing.
If you do the latter, you’ll want to select a load balancing method by expanding the Load balancing section, and selecting whatever is appropriate - round robin and least connections are both solid choices.

  1. Save and apply your settings.

Make a backend for each service you’d like to expose. Also note that for Plex, you will still need the listen port to be forwarded.

Now we’ll make frontends for these services.

First, we'll make a shared frontend for all HTTPS traffic. (4:56)
  1. Navigate to Frontend and click Add.

  2. Name your service (https_shared works).

  3. Change the port to 443 and check the box for SSL offloading.

Optionally enable separate sockets in Stats.

  1. Scroll to SSL Offloading, and select the certificate that you just created with ACME.

If you’re not using letsencrypt, leave the port and offloading settings as is.

  1. Press Save and apply your changes.

Next, we'll make an HTTPS enforcement rule. (5:37)
  1. Make a new rule, call it http_redirect. Have it listen on WAN at port 80, no offloading.

  2. Scroll to Actions. Press the arrow to create one. Change the action to http-request redirect and set the rule to scheme-https.

  3. Save and apply.

Now we can make the individual frontends for your services. (6:01)
  1. Press Add, enter the name, and check the Shared Frontend box and select https_shared.

  2. We’ll use Access Control lists to define which backend is used based on the subdomain/path given. You can use host starts with or host contains for subdomains, and path starts with or path contains for paths. In value, set the subdomain/path that will be used to access the service (i.e. ombi for ombi.domain.com, or /ombi for domain.com/ombi).

For subdomains, you will need that subdomain to be pointing at your WAN address. Paths are more appropriate for a dynamic DNS setup.

  1. Create an Action with action Use Backend, set the conditional ACL name to the name of the rule you made above, and set the backend to the associated service you’re exposing.

You can set a default backend if you want something else to display if your Ombi backend is down.

  1. Press Save and apply your changes.

Once you’ve done this for your various services, we can go make some firewall rules.

Navigate to `Firewall` -> `Rules` (7:25)
  1. Create a new one called HAProxy_HTTP. Pass IPv4 TCP traffic on the WAN interface, with destination This firewall at port 80 (select HTTP in the Destination Port Range From dropdown).
  2. Make an identical entry for HAProxy_HTTPS traffic at port 443.

Once these firewall rules are made, your subdomains/paths will now reach the services you created frontends and backends for in HAProxy.


Thanks for this, been waiting for you to release it.