Today’s most web applications probably have these characteristics:
- they are complex
- as such, they depend on many moving pieces (e.g. reverse proxy, cache, db, etc)
- require secure connections via TLS
Here are quick tips I found useful to deploy such applications.
Docker Compose is extremely useful to help manage the complexity of the application’s moving pieces. In case you did not use it before, here is my 2 second pitch. Docker Compose allows to define all of the components in a single configuration therefore allowing for easier maintenance and deployment.
For most use-cases the public-facing component of the application will probably be a reverse proxy. Nginx is one of the most popular reverse proxy servers out there. It is really reliable and lightweight. It often uses <5Mb memory. I’m not sure you can ask for more.
Since stateless applications are cool (12 Factor at all that jazz), nginx should be build as a separate docker compose service. In order words, instead of mounting a volume into the nginx container with the nginx configuration, the container should be built with the configurations baked in. That will make nginx container portable. The resulting Dockerfile will be something like:
Then it can simply be used within the
This is where things get more interesting. In order to configure TLS in nginx container, we need to have certificate installed in the container as well. Copying site’s certificate private key into the container does not seem like a good idea though. The fact that LetsEncrypt issues certificates for only 90 days is great for security but does not help in convenience department. So the question is how to do that without adding too much complexity.
Docker Volumes come to the rescue. Volumes allow to manage data attached to a container independently from the container. That means couple of things:
- we can put certificate information on a separate volume which will only be accessible from nginx container
- that volume will only have a single copy - in prod - so we will never touch the certificate in dev machines
docker-compose.yml will be something like:
After volumes are configured, we need to adjust nginx settings in order to make it compatible with LetsEncrypt process.
LetsEncrypt is a free certificate authority which automates the process of creating certs for a site.
Its used via a
Now that nginx is configured to server ACME challenges from
.well-known directory, we can request certificate from LetsEncrypt:
Above command will use ACME protocol to issue the certificate for
While doing that it will validate that we are in control of
example.com by storing some files in
.well-known which nginx will serve.
If successfully validated, certificate for
example.com will be placed in
/etc/letsencrypt which is inside
Since Nginx will have access to the same
certs volume, we can now configure nginx to actually serve the site over TLS:
Above config is btw what I use for my sites which scores
A+ in SSLTest.
After a couple of months, the certs can be easily renewed:
Alternatively cronjob can be used on the host machine to do that automatically every 15 days or so:
Thats it! Its pretty much everything necessary to run site with docker + nginx + LetsEncrypt.
LetsEncrypt is on a mission to encrypt the whole web so if are able to pitch in financially to them, please consider that.