Letsencrypt & haproxy - no down time

Post date: Jan 11, 2016 2:59:12 PM

So letsencrypt requires port 80 and 443 access in order to generate or renew certs. This can be an issue if your server already uses port 80, 443, if you need a cert for a appliance can can't run letsencrypt on that device, or you just can't afford the down time. All the above is a BS attempt at stopping non-admins from generating certs (this is a BS as you can still "get" letsencrypt to give you a cert using the webroot feature and a non-root user, but that's a topic for another time).

My solution is simple, let a "proxy" look at the inbound url and forward *all* letsencrypt connections to the letsencrypt standalone service. This way matter what sub(s) or domain(s) needed or used one copy of letsencrypt can answer ALL the requests. This means you only ever need 1 copy of letsencrypt for all the servers BEHIND the load balancer and you never need to take down or in anyway modify your existing server or website.

What you need to for all this

Heres my haproxy config  

Haproxy config

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

        # Default SSL material locations

        ca-base /etc/ssl/certs

        crt-base /etc/ssl/private

        # 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

defaults

        log     global

        mode tcp

        option tcplog

        #mode   http

        #option httplog

        option  dontlognull

        timeout connect 500

        timeout client  100

        timeout server  500

        errorfile 400 /etc/haproxy/errors/400.http

        errorfile 403 /etc/haproxy/errors/403.http

        errorfile 408 /etc/haproxy/errors/408.http

        errorfile 500 /etc/haproxy/errors/500.http

        errorfile 502 /etc/haproxy/errors/502.http

        errorfile 503 /etc/haproxy/errors/503.http

        errorfile 504 /etc/haproxy/errors/504.http

listen stats

    bind 0.0.0.0:9000       #Listen on all IP's on port 9000

    mode http

    balance

    timeout client 5000

    timeout connect 4000

    timeout server 30000

    #This is the virtual URL to access the stats page

    stats uri /haproxy_stats

    #Authentication realm. This can be set to anything. Escape space characters with a backslash.

    stats realm HAProxy\ Statistics

    #The user/pass you want to use. Change this password!

    stats auth ******:*****

    #This allows you to take down and bring up back end servers.

    #This will produce an error on older versions of HAProxy.

    stats admin if TRUE

#Application Setup

frontend ContentSwitching

  bind 10.1.97.2:80

  bind 10.1.97.2:443 ssl crt /etc/haproxy/ssl/

  mode http

  option httplog

  acl letsencrypt_remote_host path_beg /.well-known/acme-challenge/

  use_backend letsencrypt_nodes if letsencrypt_remote_host

  default_backend linux_www_node

backend letsencrypt_nodes

  mode http

  server letsencrypt 127.0.0.1:8080

backend linux_www_node

  mode http

  compression algo gzip

  compression type text/html text/plain text/css text/js

  balance roundrobin

  stick-table type ip size 200k expire 30m

  stick on src

  server node1 127.0.0.1:80 check

And now and example of the letsencrypt cli

letsencrypt cli

/usr/bin/letsencrypt  --agree-tos --renew-by-default --standalone --standalone-supported-challenges http-01 --http-01-port 8080 certonly -d sub1.nomadcf.com -d sub2.nomadcf.com -d sub3.nomadcf.com