Install HAProxy:
Latest stable 1.6:
sudo add-apt-repository ppa:vbernat/haproxy-1.6
sudo apt-get update
sudo apt-get install haproxy
Haproxy plugin for webroot validation:
I used this haproxy plugin to be able to serve simple files so that I can use the "webroot" validation protocol of the letsencrypt client:
https://github.com/janeczku/haproxy-acme-validation-plugin
So I just download the .lua file into my /etc/haproxy/
:
sudo wget https://raw.githubusercontent.com/janeczku/haproxy-acme-validation-plugin/master/acme-http01-webroot.lua /etc/haproxy
then I add the following to my /etc/haproxy/haproxy.cfg
:
global
lua-load /etc/haproxy/acme-http01-webroot.lua
frontend http
acl url_acme_challenge path_beg /.well-known/acme-challenge/
http-request use-service lua.acme-http01 if METH_GET url_acme_challenge
Letsencrypt client:
https://github.com/letsencrypt/letsencrypt
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
Now I can run my letsencrypt command:
(during test add --test-cert --break-my-certs
)
sudo ./letsencrypt-auto certonly --text --webroot --webroot-path /var/lib/haproxy --renew-by-default --agree-tos --email hedefalk@gmail.com -d woodenstake.se -d jenkins.woodenstake.se -d jenkins-nas.woodenstake.se -d repo.woodenstake.se -d blog.woodenstake.se -d transmission.woodenstake.se -d uniplybeta.woodenstake.se -d crm.woodenstake.se -d docker.woodenstake.se
So this puts challenge response files in /var/lib/haproxy
that the lua-plugin then serves to the letsencrypt requests coming in, proving that I own the domains.
Concat the SAN cert:
sudo cat /etc/letsencrypt/live/repo.woodenstake.se/privkey.pem /etc/letsencrypt/live/repo.woodenstake.se/fullchain.pem | sudo tee /etc/letsencrypt/live/repo.woodenstake.se/haproxy.pem >/dev/null
and reload haproxy:
sudo service haproxy reload
Now all my address bars are green, yey!
Caveats:
-
check
(health check) on server fails for 403 if not logged in which marks server as down. Don't know if there's solution for this. Probably: -
https://cbonte.github.io/haproxy-dconv/configuration-1.6.html#http-check expect
-
I can't seem to figure out why my SAN cert gets put into
repo.woodenstake.se
subfolder: https://github.com/letsencrypt/letsencrypt/issues/1946#issuecomment-167810408 -
Cannot use forwardfor globally since this will break: https://github.com/janeczku/haproxy-acme-validation-plugin/issues/1#issuecomment-165721178
-
I had to add extra clauses to my backend switches or they took prio over the lua-plugin: https://github.com/janeczku/haproxy-acme-validation-plugin/issues/2#issuecomment-167803265
TODO:
- cronjob to update my certs
For completeness, here's almost my entire haproxy.cfg at the point when I publish this:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
crt-base /etc/letsencrypt/live
# Default ciphers to use on SSL-enabled listening sockets.
# For more information, see ciphers(1SSL). This list is from:
# https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
ssl-default-bind-options no-sslv3
tune.ssl.default-dh-param 2048
lua-load /etc/haproxy/acme-http01-webroot.lua
defaults
log global
mode http
option httplog
timeout connect 5000
timeout client 50000
timeout server 50000
frontend http
mode http
bind *:80
option httplog
# Letsencrypt: https://github.com/janeczku/haproxy-acme-validation-plugin
acl url_acme_challenge path_beg /.well-known/acme-challenge/
http-request use-service lua.acme-http01 if METH_GET url_acme_challenge
redirect scheme https code 301 if { hdr(Host) -i repo.woodenstake.se } !{ ssl_fc }
redirect scheme https code 301 if { hdr(Host) -i jenkins.woodenstake.se } !{ ssl_fc }
acl host_blog hdr(host) -i blog.woodenstake.se
use_backend ghost if host_blog !url_acme_challenge
frontend https
mode http
bind *:443 ssl crt /etc/letsencrypt/live/repo.woodenstake.se/haproxy.pem
# Define hosts based on domain names
acl host_jenkins hdr(host) -i jenkins.woodenstake.se
acl host_repo hdr(host) -i repo.woodenstake.se
acl host_jenkins_nas hdr(host) -i jenkins-nas.woodenstake.se
acl host_transmission hdr(host) -i transmission.woodenstake.se
acl host_blog hdr(host) -i blog.woodenstake.se
acl host_docker hdr(host) -i docker.woodenstake.se
use_backend jenkins if host_jenkins
use_backend nexus if host_repo
use_backend jenkins_nas if host_jenkins_nas
use_backend transmission_nas if host_transmission
use_backend ghost if host_blog
use_backend docker if host_docker
backend jenkins
mode http
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
server jenkins_backend 127.0.0.1:8080
backend nexus
mode http
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
server nexus_backend 127.0.0.1:8081
backend jenkins_nas
mode http
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
server jenkins_nas_backend 10.0.1.30
backend transmission_nas
mode http
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
server jenkins_nas_backend 10.0.1.30:8181
backend ghost
mode http
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
server ghost_docker 127.0.0.1:2368
backend docker
mode http
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
server docker_registry 127.0.0.1:5000
Update 20170406:
Installed certbot and now:
sudo certbot certonly --text --webroot --webroot-path /var/lib/haproxy --agree-tos --email hedefalk@gmail.com -d woodenstake.se -d jenkins.woodenstake.se -d jenkins-nas.woodenstake.se -d repo.woodenstake.se -d blog.woodenstake.se -d transmission.woodenstake.se -d uniplybeta.woodenstake.se -d crm.woodenstake.se -d docker.woodenstake.se -d drone.github.woodenstake.se -d drone.gitlab.woodenstake.se
sudo cat /etc/letsencrypt/live/transmission.woodenstake.se/privkey.pem /etc/letsencrypt/live/transmission.woodenstake.se/fullchain.pem | sudo tee /etc/letsencrypt/live/woodenstake.se/haproxy.pem > /dev/null
sudo haproxy reload
to renew.