Protecting services with client certificates using Haproxy

 What we want to achieve

We want to be able to connect to services inside a private network using client certificates, in this example we will be connecting to Redis.


 Install or compile Haproxy

I am using Debian, so this is what I use to compile Haproxy for testing out this setup.

apt-get -y install make gcc g++ libssl-dev

tar xzf haproxy-1.8.4.tar.gz
cd haproxy-1.8.4
make TARGET=generic USE_OPENSSL=1
make install PREFIX=/usr/local

 Install and configure firewall

I am testing with a Redis-server, but it can be anything. First firewall off everything except for port 22 (ssh) and port 88 (our external redis port):

apt-get -y install ufw

ufw default deny incoming
ufw default allow outgoing
ufw allow 22
ufw allow 88

 Install Redis

apt-get -y install redis-server

Since Debian and Debian-related distros have the terrible idea that software need to run by default, you should now have a running redis-server on port 6379.

 Generate certificates

This is just for testing, please use some better tooling like easy-rsa to manage your certificates:

openssl genrsa -nodes -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt # with
cat ca.crt ca.key > ca.pem

openssl genrsa -out client.key 4096
openssl req -new -key client.key -out client.csr #
openssl x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
cat client.crt client.key > client.pem

 Setup Haproxy server

This let Haproxy listen on port 88, and it will verify the connecting certificates, and if the authentication is succesful, it will forward the traffic to redis on

Create a file named: haproxy_server.cfg:

  pidfile /var/run/
  maxconn 4000
  tune.ssl.default-dh-param 2048

listen redis
  bind ssl crt /root/ca.pem ca-file /root/ca.crt verify required
  mode tcp
  server redis-1 maxconn 1024

Run the config in a non-daemonized way:
haproxy -f haproxy_server.cfg.

 Connecting to Redis through another Haproxy

Create a file named: haproxy_client.cfg:

  maxconn 4000

listen redis
    mode tcp
  server redis-serv01 ssl crt client.pem ca-file ca.crt

Run the config in a non-daemonized way:
haproxy -f haproxy_client.cfg.

Now you should be able to connect to Redis from your terminal:

$ redis-cli -h localhost -p 7945
localhost:7945> ping

 Connect to Redis through Ruby

If you do not want to install a Haproxy instance just to manage the client certificates, you can connect directly from your favorite programming language, here is an example on how to do it in Ruby:

require 'socket'
require 'openssl'

sock ='', 88)

ctx =
ctx.cert ='/root/client.pem'))
ctx.key  ='/root/client.key'))
# ctx.key ='client.key'), 'secret_password')

@socket =, ctx).tap do |socket|
  socket.sync_close = true
  socket.write "PING\n"
  socket.each_line do |line|
    puts line


Consider using CRL-files for making your life easier, CRL stands for Client Revocation List, and it is a list of certificates that you no longer trust for one reason or another, so if a server gets hacked, or an employee laptop goes missing, you can revoke the certificate and sleep nicely afterwards knowing that they can’t use the certificate for anything.

When you have a crl-file, It is as easy as adding crl-file <crlfile> to the server configuration.

There is a nice article about crls here:


Now read this

I bought a Playstation Vita in 2016, 4 years after the initial release. Here are my first impressions

I love gaming, I own over 300 games on Steam, I buy virtual items for my game characters, and I gift games to friends. I support game creators, and I embrace the modern game marketplace that includes digital downloads, DLCs and items. I... Continue →