In this guide, we’ll configure HAProxy on OPNsense to support TLS passthrough with SNI-based routing. This allows secure HTTPS traffic to be routed based on domain names without decrypting the traffic on the firewall.
- Install HAProxy Plugin
- Go to System > Firmware > Plugins
- Search for: os-haproxy
- Click Install
- After installation, go to Services > HAProxy (you may need to reboot)
- Enable HAProxy
- Go to Services > HAProxy > Settings > Service
- Check Enable HAProxy
- Click Apply
- Add Real Servers
- Go to Services > HAProxy > Settings > Real Servers
- Click Add
| Name | app | k8s-controller | 
| Type | static | static | 
| FQDN or IP | 10.0.128.5 | 10.0.128.240 | 
| Port | 443 | 443 | 
| SSL | Unchecked | Unchecked | 
| Verify SSL Certificate | Unchecked | Unchecked | 
- Click Save
- Click Apply
- Create Backend Pools
- Go to Services > HAProxy > Settings > Virtual Services > Backend Pools
- Click Add
| Name | app | k8s-controller | 
| Mode | TCP (Layer 4) | TCP (Layer 4) | 
| Servers | app | k8s-controller | 
| Enable Health Checking | Unchecked | Unchecked | 
- Click Save
- Click Apply
- Create TCP Frontend with SNI Routing
- Go to Services > HAProxy > Settings > Virtual Services > Public Services
- Click Add
 Name: frontend-https
 Listen Address: 0.0.0.0:443
 Type: SSL/HTTPS(TCP mode)
 Default Backend Pool: None
- Option pass-through
 Enable advanced mode and scroll down to Advanced settings > Option pass-through
 Paste this:
# Required to extract SNI from TLS handshake in TCP mode
tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
# ACL: is_app_tls
acl is_app_tls req.ssl_sni -i maksonlee.com
acl is_app_tls req.ssl_sni -i www.maksonlee.com
acl is_app_tls req.ssl_sni -i zabbix.maksonlee.com
acl is_app_tls req.ssl_sni -i jenkins-test.maksonlee.com
# ACL: is_k8s_tls
acl is_k8s_tls req.ssl_sni -i whoami.maksonlee.com
# ACTION: app
use_backend app if is_app_tls
# ACTION: k8s
use_backend k8s-controller if is_k8s_tls
This enables SNI-based routing in the correct order, which the UI doesn’t handle automatically.
- Click Save
 Click Apply
Done, now it’s time to test.
HTTP Pass-through (Optional)
If you want to forward port 80 traffic as plain HTTP (not TLS passthrough), here is the configuration:
# Frontend: frontend-http ()
frontend frontend-http
    bind 0.0.0.0:80 name 0.0.0.0:80 
    mode http
    option http-keep-alive
    # logging options
    # WARNING: pass through options below this line
    # ACL: is_app_http
    acl is_app_http hdr(host) -i maksonlee.com
    acl is_app_http hdr(host) -i www.maksonlee.com
    acl is_app_http hdr(host) -i zabbix.maksonlee.com
    acl is_app_http hdr(host) -i jenkins-test.maksonlee.com
    # ACL: is_k8s_http
    acl is_k8s_http hdr(host) -i whoami.maksonlee.com
    
    # ACTION: app
    use_backend app-http if is_app_http
    # ACTION: k8s
    use_backend k8s-controller-http if is_k8s_http
# Backend: app-http ()
backend app-http
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m  
    stick on src
    http-reuse safe
    server app 10.0.128.5 
# Backend: k8s-controller-http ()
backend k8s-controller-http
    # health checking is DISABLED
    mode http
    balance source
    # stickiness
    stick-table type ip size 50k expire 30m  
    stick on src
    http-reuse safe
    server k8s-controller 10.0.128.240 
