Az

TCP Proxying

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.