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.