ce0966179294d77b1c7c4544ec3096dcbc7647ec
haproxy-letsencrypt-docker.md
| ... | ... | @@ -5,7 +5,10 @@ |
| 5 | 5 | Let's set up [HAProxy](https://www.haproxy.org/) with some lovely free certs from [Let's Encrypt](https://letsencrypt.org/) via [certbot](https://certbot.eff.org/) for a couple of domains. |
| 6 | 6 | Everything running in [docker](https://www.docker.com), and all tied together with [docker-compose](https://docs.docker.com/compose/). |
| 7 | 7 | We'll use docker [user-defined networks](https://docs.docker.com/v17.09/engine/userguide/networking/#user-defined-networks), because that's the Right Thing To Do. |
| 8 | -I'll use 'domain1.example.com' and 'domain2.example.com' as the domains involved. You might have more. Or less. Edit as appropriate. |
|
| 8 | + |
|
| 9 | +I'll use 'domain1.example.com' and 'domain2.example.com' as the domains involved. The domain1 site is served from a container called 'container1', and domain2 from a container called 'domain2' You might have more. Or less. Edit as appropriate. |
|
| 10 | + |
|
| 11 | +This wiki is set up very similarly to the below - the running config is on [my github](https://github.com/ilikejam/home-network). |
|
| 9 | 12 | |
| 10 | 13 | # This should be easy. Right? |
| 11 | 14 | Docker: easy. |
| ... | ... | @@ -104,3 +107,72 @@ IMPORTANT NOTES: |
| 104 | 107 | ``` |
| 105 | 108 | |
| 106 | 109 | Certs gotten, and stashed away in a docker volume. Happy days! |
| 110 | + |
|
| 111 | +# Stage 2 - haproxy |
|
| 112 | +We've got ourselves some certs so it's time to fire up haproxy and enjoy all the HAing and Proxying. Don't know about you, but I am excited. |
|
| 113 | + |
|
| 114 | +## Dockerfile |
|
| 115 | +We don't need one. Becuase we're using the official image. Because we're adhering to [rule 1](/rules#love-thy-defaults). |
|
| 116 | + |
|
| 117 | +## haproxy.cfg |
|
| 118 | +Do an `mkdir haproxy/bind`. |
|
| 119 | +Put something like the below in `haproxy/bind/haproxy.fg`: |
|
| 120 | + |
|
| 121 | +```text |
|
| 122 | +global |
|
| 123 | + maxconn 4096 |
|
| 124 | + daemon |
|
| 125 | + log stdout format raw local0 debug |
|
| 126 | + tune.ssl.default-dh-param 2048 |
|
| 127 | + ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 |
|
| 128 | + ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets |
|
| 129 | + ssl-default-server-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 |
|
| 130 | + ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets |
|
| 131 | + |
|
| 132 | +resolvers docker |
|
| 133 | + nameserver docker1 127.0.0.11:53 |
|
| 134 | + |
|
| 135 | +defaults |
|
| 136 | + log global |
|
| 137 | + mode http |
|
| 138 | + option httplog |
|
| 139 | + timeout connect 5000 |
|
| 140 | + timeout client 50000 |
|
| 141 | + timeout server 50000 |
|
| 142 | + default-server init-addr none |
|
| 143 | + |
|
| 144 | +frontend http_in |
|
| 145 | + bind *:8080 |
|
| 146 | + bind *:8443 ssl crt /etc/letsencrypt/haproxy.pem |
|
| 147 | + mode http |
|
| 148 | + redirect scheme https code 301 if !{ ssl_fc } |
|
| 149 | + |
|
| 150 | + capture request header Host len 256 |
|
| 151 | + capture request header User-Agent len 256 |
|
| 152 | + |
|
| 153 | + acl acme_pth path_beg -i /.well-known/acme-challenge |
|
| 154 | + acl domain1_hdr hdr(host) -i domain1.example.com |
|
| 155 | + acl domain2_hdr hdr(host) -i domain2.example.com |
|
| 156 | + |
|
| 157 | + use_backend letsencrypt if acme_pth |
|
| 158 | + use_backend domain1 if domain1_hdr |
|
| 159 | + use_backend domain2 if domain2_hdr |
|
| 160 | + |
|
| 161 | +backend letsencrypt |
|
| 162 | + server letsencrypt letsencrypt:8000 resolvers docker check |
|
| 163 | + |
|
| 164 | +backend domain1 |
|
| 165 | + server domain1-1 container1:5000 resolvers docker check |
|
| 166 | + |
|
| 167 | +backend wiki |
|
| 168 | + server domain2-1 container2:3000 resolvers docker check |
|
| 169 | +``` |
|
| 170 | + |
|
| 171 | +What's going on here? |
|
| 172 | +1. The global section logs everything to stdout, because that's what you do with docker. [rule 6](/rules#thou-shalt-respect-the-sanctity-of-stdout) does not apply in dockerland. |
|
| 173 | +2. We're setting the Mozilla recommended ciphers and DH values. Check the [current recommendations](https://mozilla.github.io/server-side-tls/ssl-config-generator/) if you're foolish enough to go into production with this stuff. |
|
| 174 | +3. We're using 'resolvers' and 'default-server init-addr none' to get around problem of containers not being up at startup time. Docker with user-define networks always puts a resolver at 127.0.0.11:53, and haproxy can use that to resolve container names at runtime instead of startup time. |
|
| 175 | +4. We're binding to port 8080 and 8443, and setting the cert to the Let's Encrypt cert we dumped out in the previous section. Those ports will be mapped back to 80 and 443 by docker later on. |
|
| 176 | +5. Always redirect to https. |
|
| 177 | +6. All traffic that matches the certbot [ACME](https://ietf-wg-acme.github.io/acme/draft-ietf-acme-acme.html) protocol is directed to out letsencrypt container. |
|
| 178 | +7. Other traffic is matched by request hostname to their respective containers. Your routing will probably be more complicated than this, but it's a start. |