Hi, I am currently using HAProxy to split web traffic between my docker sites, and all other sites. I’d now like to use SSL for my sites.
EDIT:
For the purpose of those coming across this thread in future I have summarised what I have learnt as follows:
It’s easier than you think!
You don’t need to worry whether your sites are served via Docker, or Apache - it’s HAProxy that speaks to the browser so you can let HAProxy handle it all.
You simply need to add bind *:443 ssl crt /etc/haproxy/certs/ to your front-end then just make sure your certs are in that directory.
See this article on how to set-up and renew Lets Encrypt certs.
global
# to have these messages end up in /var/log/haproxy.log you will
# need to:
#
# 1) configure syslog to accept network log events. This is done
# by adding the '-r' option to the SYSLOGD_OPTIONS in
# /etc/sysconfig/syslog
#
# 2) configure local2 events to go to the /var/log/haproxy.log
# file. A line like the following can be added to
# /etc/sysconfig/syslog
#
# local2.* /var/log/haproxy.log
#
# log 127.0.0.1 local2
# chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
# option forwardfor except 127.0.0.0/8
option forwardfor
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
frontend http-in
bind *:80
default_backend main_apache_sites
# Define hosts
redirect prefix http://discourse-forum-1.com code 301 if { hdr(host) -i www.discourse-forum-1.com }
acl host_discourse hdr(host) -i discourse-forum-1.com
redirect prefix http://discourse-forum-2.com code 301 if { hdr(host) -i www.discourse-forum-2.com }
acl host_discourse_2 hdr(host) -i discourse-forum-2.com
redirect prefix http://discourse-forum-3.com code 301 if { hdr(host) -i www.discourse-forum-3.com }
acl host_discourse_3 hdr(host) -i discourse-forum-3.com
# which one to use
use_backend discourse_docker if host_discourse
use_backend discourse_docker_2 if host_discourse_2
use_backend discourse_docker_3 if host_discourse_3
backend main_apache_sites
server server1 127.0.0.1:8080 cookie A check
cookie JSESSIONID prefix nocache
backend discourse_docker
server server2 127.0.0.1:8888 cookie A check
cookie JSESSIONID prefix nocache
backend discourse_docker_2
server server2 127.0.0.1:8889 cookie A check
cookie JSESSIONID prefix nocache
backend discourse_docker_3
server server2 127.0.0.1:8890 cookie A check
cookie JSESSIONID prefix no cache
If you look at # Define hosts you’ll see my docker sites (which are actually Discourse forums - the same as what you are running here). I’d like to enable SSL by using their letsencrypt plugin (if possible) here are the details but essentially it take cares of the certificate and auto-renews it.
Does anyone know what my haproxy.cfg file should look like if I wanted to enable SSL as per their guide?
@lukastribus, I am trying to enable https on some of the sites on the server (not all of them). The original setup was the usual Apache listening on port 80. When I installed HAProxy I configured Apache to listen on port 8080 and that’s what’s used for the default_backend. HAProxy sends requests to one of three Docker containers if one of those domains is requested, otherwise it sends everything else to the default backend. All this works fine for normal http requests.
What I’m trying to do is enable https on my docker containers (which are actually Discourse forums) as well as some of my normal ‘default_backend’ sites.
I have actually been able to enable https successfully on some of the Apache default_backend sites (I guess because Apache is listing on port 443 as normal and HAProxy is just ignoring that port since I don’t tell it otherwise). Hence port 4433, which is what I was going to change Apache’s ssl port to.
Does that better explain what I am trying to do? Thanks for your help - I really appreciate it.
Ok, but what you want to do is enabled SSL between the client/browser to haproxy. There is no need to enable SSL between haproxy and the apache backend, or is it?
If you enable SSL both on the frontend and the backend, your server’s CPU load due to SSL is multiplied by a factor of 3 (SSL termination on the haproxy frontend vs SSL termination on the haproxy frontend + backend + apache backend).
Don’t do this, this configuration is wrong. You want SSL on port 443 and plaintext HTTP on port 80, you cannot configure it on the same bind line.
I don’t see why listening to port 443 would make your sites inaccessible. Does haproxy even start correctly? Can it bind to port 443 (or is there another apache instance listening on port 443)? Do you see anything relevant on stdout/stderr or in the syslog? What about haproxy logging?
Ok I’ve changed Apache’s SSL config to listen on port 4433 (and made sure none of the existing records refer to 443), however the sites are still inaccessible with the following uncommented:
I had thought that /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem was where all .pems were getting concatenated, but perhaps that’s not the case (I am using Webmin’s letsencrypt client to create the certs and even adding /etc/webmin/webmin/letsencrypt.pem as the location renders the sites inaccessible).
If I am using HAProxy, do I still need to get a cert for every domain? Or just one for HAProxy as that’s what the browser connects to?
Ideally, I could just use Webmin’s Letsencrypt client as it also handles renewals for all my Apache sites, and for the Docker containers, just use the Discourse scrip per container as per my first post - but I’m guessing this is not possible?
Any advice you can give will be greatly appreciated. And I’m sorry that I keep replying with more questions.
Don’t jump to conclusions. Respond to the existing question above, like when the sites are inaccessible, is haproxy even correctly started or does it fail to start? Start it manually and check if there are any error messages or warnings.
Sorry I forgot to answer you questions (I couldn’t find the log file anywhere).
Running haproxy -vv didn’t work for me so I tried systemctl status haproxy and got:
systemd[1]: Started HAProxy Load Balancer.
systemd[1]: Starting HAProxy Load Balancer...
haproxy-systemd-wrapper[19941]: haproxy-systemd-wrapper: executing /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds
haproxy-systemd-wrapper[19941]: [ALERT] 159/134514 (19942) : parsing [/etc/haproxy/haproxy.cfg:49] : 'bind *:443' : unable to load SSL certificate from PEM file '/etc/webmin/webmin/letsencrypt.pem'.
haproxy-systemd-wrapper[19941]: [ALERT] 159/134514 (19942) : Error(s) found in configuration file : /etc/haproxy/haproxy.cfg
haproxy-systemd-wrapper[19941]: [WARNING] 159/134514 (19942) : config : log format ignored for frontend 'http-in' since it has no log address.
haproxy-systemd-wrapper[19941]: [ALERT] 159/134514 (19942) : Proxy 'http-in': no SSL certificate specified for bind '*:443' at [/etc/haproxy/haproxy.cfg:49] (use 'crt').
haproxy-systemd-wrapper[19941]: [ALERT] 159/134514 (19942) : Fatal errors found in configuration.
haproxy-systemd-wrapper[19941]: haproxy-systemd-wrapper: exit, haproxy RC=256
```
Looks like the PEM file is not right. I've looked at the files created by the webmin lets encrypt script and it looks like it creates 3 files in the root directory for the domain:
```
-rwxr-xr-x 1 domain.com domain.com 1647 May 23 23:49 ssl.ca*
-rwx------ 1 domain.com domain.com 2159 May 23 23:49 ssl.cert*
-rwx------ 1 domain.com domain.com 3243 May 23 23:49 ssl.key*
```
I can't see any related .PEM files.
```
locate *.pem*
/etc/dhparams.pem
/etc/pki/ca-trust/extracted/pem/email-ca-bundle.pem
/etc/pki/ca-trust/extracted/pem/objsign-ca-bundle.pem
/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
/etc/pki/dovecot/certs/dovecot.pem
/etc/pki/dovecot/private/dovecot.pem
/etc/pki/tls/cert.pem
/etc/postfix/postfix.cert.pem
/etc/postfix/postfix.key.pem
/etc/usermin/miniserv.pem
/etc/webmin/miniserv.pem
/etc/webmin/webmin/letsencrypt.pem
```
Any ideas what to try next?
The pem file must contain the the private key, the certificate and the intermediate certificate [1]. If you have more than one certificate you need to use multiple files and point to each of them or the directory containing all those files.
1 - The link says I need to create a single PEM file with key, crt and chain entries . I do not know what chain entries are. The only three files the webmin lets encrypt client seems to produce are ssl.key, ssl.cert and ssl.ca. I have tried concatenating the cert and key, as well as all three and both versions work. What is the correct approach here?
2 - Can I create one single .pem file that contains all of the separate .pems? Or do I need to specify each file separately (or a directory)
3 - Are there any recommended lets encrypt scripts to use with HAProxy? Having to manually renew the pems (as certs expire every two months) could be a nuisance.
Any other advice appreciated (and thanks once again for all your help).