If you’re accessing several web services via a single host, you may quickly find yourself running out of available ports to use. UNIX sockets provide a quick and efficient workaround. I’ll be using HAProxy 2.4.22 in our example, but the principal can be applied to any reverse proxy software that supports UNIX sockets.
From HAProxy’s perspective, the only functional difference between a TCP port and UNIX socket is syntax and permissions. They both can be used to send and receive data. Let’s look at a couple of examples below:
Typical Proxy With TCP Port
frontend A
mode http
bind 127.0.0.1:8000 ssl crt /etc/ssl/certs/haproxy.pem
# 16000000 seconds is a bit more than 6 months
http-response set-header Strict-Transport-Security "max-age=16000000; includeSubDomains; preload;"
default_backend B
option http-server-close
option httplog
option dontlognull
option http-server-close
option forwardfor
maxconn 2000
backend B
mode http
server AB 127.0.0.1:8888
Proxy With UNIX Socket
frontend Y
mode http
bind /run/example.sock user haproxy group haproxy mode 660 ssl crt /etc/ssl/certs/haproxy.pem
http-response set-header Strict-Transport-Security "max-age=16000000; includeSubDomains; preload;"
default_backend Z
option http-server-close
option httplog
option dontlognull
option http-server-close
maxconn 2000
backend Z
mode http
server YZ 127.0.0.1:8800
Between these two listening pairs, you’ll see that the only difference is that frontend Y is bound to a UNIX socket in the /run directory and has extra parameters defined. Since a UNIX socket is treated as a file, we need to ensure that HAProxy is able to read and write to the socket properly. This is achieved by assigning the HAProxy user as the owner and group for the socket at runtime. We also set read and write permissions with the “mode” parameter.
Something to consider is that our UNIX socket-based proxy won’t be very useful for HTTPS as it’s configured right now. After all, any web browser will be expecting an IP socket, i.e. 80 or 443. Let’s modify our above example to deal with this little hiccup.
frontend mainhttps
mode tcp
bind :443
option tcplog
tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
use_backend ABProxy if { req.ssl_sni -i foo.com }
use_backend YZProxy if { req.ssl_sni -i bar.com }
default_backend anythingElseSSL
frontend A
mode http
bind 127.0.0.1:8000 ssl crt /etc/ssl/certs/haproxy.pem
# 16000000 seconds is a bit more than 6 months
http-response set-header Strict-Transport-Security "max-age=16000000; includeSubDomains; preload;"
default_backend B
option http-server-close
option httplog
option dontlognull
option http-server-close
option forwardfor
maxconn 2000
backend ABProxy
server abproxy1 127.0.0.1:8000
backend B
mode http
server AB 127.0.0.1:8888
frontend Y
mode http
bind /run/example.sock user haproxy group haproxy mode 660 ssl crt /etc/ssl/certs/haproxy.pem
http-response set-header Strict-Transport-Security "max-age=16000000; includeSubDomains; preload;"
default_backend Z
option http-server-close
option httplog
option dontlognull
option http-server-close
maxconn 2000
backend YZProxy
server yzproxy1 /run/example.sock
backend Z
mode http
server YZ 127.0.0.1:8800
backend anythingElseSSL
server something 127.0.0.1:8443
I’ve setup HAProxy to reroute traffic to different frontends depending on what application the user is trying to reach after hitting TCP/443. If the user’s request isn’t for foo.com or bar.com, then we will send the traffic off to another application on this host. This approach allows us to scale the HAProxy config for additional web apps and allows us to use UNIX sockets at the same time to limit the number of ports we need to listen on.
You may have also noticed that I have the main frontend running in TCP mode rather than HTTP mode. This is not a strict requirement, but is specific to my production environment from which this configuration is based.
That’s it! You can now use UNIX sockets to proxy several web applications from a single host.