Richard Bernecker

Random Solutions to Random Problems

Utilizing UNIX Sockets for an HTTPS Reverse Proxy

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.