Problem
I recently purchased a new ‘server’ and started setting up a bunch of services including GitLab and Taiga. I also want these services available outside my home network but I also want to meet at least the bare modicum of security by having my sites secured via TLS. This isn’t too much of a problem if they’re all hosted on the same IP address or each service has a dedicated IP address like you’ll find in many public scenarios. It’s also not hard if you have a TLS-terminating proxy set up such as nginx and all these scenarios are made much easier with Let’s Encrypt.
In my case though I want to run the services:
- Inside my home network
- On different servers
- On different internal IPs
- Behind one (1) public IP address
- Terminating TLS on each server
- With auto-renewing certificates
Solution
After much umming and ahhing I managed to formulate the words for what I wanted: “TCP proxying”. I set about looking around and stumbled upon HAProxy which met my needs perfectly.
I created another virtual machine and installed only HAProxy and then set up something similar to the following configuration:
frontend http_frontend
bind *:80
option httplog
mode http
acl host_gitlab hdr(host) -i gitlab.example.com
acl host_taiga hdr(host) -i taiga.example.com
use_backend http_gitlab if host_gitlab
use_backend http_taiga if host_taiga
backend http_gitlab
mode http
balance roundrobin
server gitlab 192.168.0.100:80 check
backend http_taiga
mode http
balance roundrobin
server taiga 192.168.0.101:80 check
frontend https_frontend
bind *:443
option tcplog
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend https_gitlab if { req.ssl_sni -i gitlab.example.com }
use_backend https_taiga if { req.ssl_sni -i taiga.example.com }
backend https_gitlab
mode tcp
balance roundrobin
option ssl-hello-chk
server gitlab 192.168.0.100:443
backend https_taiga
mode tcp
balance roundrobin
option ssl-hello-chk
server taiga 192.168.0.101:443
This setup will accept both HTTP and HTTPS connections and route them to the correct server based on either the hostname in the unsecured request or the Server Name Indication in the SSL/TLS request. Now I can have my traffic encrypted and also allow automatic renewal of the certs by Certbot over HTTP.