Pfsense HAProxy
HAProxy ports 80/443
pfsense admin port change
Step one here is to change pfsense admin interface port from 443. pfsense Admin Port Change
Adjust Firewall Rules
In order for HAProxy to be used, we need to change some firewall rules to pass traffic for 80/443
If you previously NATted 80/443
You will want to disable these NAT rules.
Adjust WAN rules to allow access
Add these rules to allow access to HAProxy
HAProxy setup
Go to your package manager and download and install HAproxy.
Make sure the above settings are set.
Create Basic HTTP site
Below, we will demonstrate a simple Port 80 access to a dummy webpage. I'd recommend a dummy nginx setup on another device.
Create First Backend
Here, we will create a Backend that goes to a dummy webpage (set this up on a seperate device)
There are only a few settings to change here:
Then scroll to the bottom and change the following:
Create a host matching frontend
We will now utilize the shared frontend to match a requested host name and direct that traffic to the backend that we setup.
Test
Assuming you've already directed the A Record for your domain name to you external IP, opening your domain name in a browser should now show your test webpage.
Upgrade Basic HTTP site to HTTPS
Now that we have a basic HTTP site functioning, we will add a certificate to HAProxy and allow HTTPS traffic on port 443.
Obtain Certificate
For this setup I will focus on using Acme Letsencrypt to obtain a certificate. There are other ways to add a cert to your haproxy setup.
See https://docs.netgate.com/pfsense/en/latest/certificates/certificate-management.html
Create Acme cert Backend
MAKE SURE HEALTH CHECKS ARE DISABLED
Create Frontend Rule to use Acme Backend
For ease of copy-paste,
/.well-known/acme-challenge/
Use The Acme package to get a cert
Install and prepare Acme
Restart HAProxy
Now that we have a working Certificate, we'll add a shared fronend similar to the HTTP one before.
Copy Acme ACL from HTTP to HTTPS
For good measure, we'll copy the acme rule to the shared HTTPS frontend
(The rectangle icon is the copy button)
Now we will want all HTTP traffic to use HTTPS on port 443:
Move Domain Matched ACL to HTTP
Go to edit the previously created Frontend for your dummy webserver.
Change the "Primary Frontend" from "Shared-HTTP" to "Shared-HTTPS"
Test
You should now be able to open your domain in a browser to see your dummy webpage with HTTPS.
Frontend ACL Tricks
These ACLs can be applied to both HTTP and HTTPS frontends
Blocks
Block access by IP Address
Using Host-Regex matching with http-request-deny 403:
IPv4
^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$
IPv6
(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))
Block access by Charter Spectrum Address
Using Host-Regex matching with http-request-deny 403:
.spectrum.com
.charter.com
Block access by Hurricane Electric Address
Using Host-Regex matching with http-request-deny 403:
.ipv6.he.net
Set a robots.txt globally
Lua Script
Under the "Files" tab of HAProxy, create a filename "robots" with the type "Lua script" with the following content
robots = function(applet)
local response = "User-agent: *\nDisallow: /"
applet:add_header("Content-Length", string.len(response))
applet:add_header("Content-Type", "text/plain")
applet:set_status(200)
applet:start_response()
applet:send(response)
end
core.register_service("robots", "http", robots)
Frontend ACL
Other
Redirect Naked Domains to www.domain.net
Use a Custom-acl with "Not" checked with a value of:
hdr_reg(host) -i .*\..*\..* :
Then use http-request-redirect
prefix https://www.%[hdr(host)] code 301
Backend ACL Tricks
Rewrite / to /somethingelse/
Use Path-Matches to http-request-redirect
prefix https://%[hdr(host)]/somethingelse/ code 301


















