Fully automated dockerized Let's Encrypt reverse proxy

Easy HTTPS for websites using Let's Encrypt

Motivation

While most people agree that securing web sites with SSL is a good thing, many sites still lack the necessary certificates. There are free options available when it comes to trusted certificates, but setting them up is a tedious process. The domain validation still requires much human work that can not be automated.

The Let’s Encrypt project aims to remedy this. It’s built on a protocol called ACME (Automated Certificate Management Environment) that automates the domain validation. On the down side, certificate registration and renewal is still a mostly manual process.

One possible solution is to use a Docker container that automates all the tasks regarding the certificate and also provide a reverse proxy for the application. This approach moves the SSL part into a separate component.

In effect, you’ll need only a few lines of configuration and your app is secured with a valid and evergreen certificate.

How to use

The easiest way is to use Docker Compose and define the bridged network there.

version: '2'
services:
  proxy:
    image: sashee/letsencrypt-proxy-docker
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - angular
    networks:
      - proxy
    environment:
      # Set your host
      #- HOST=<yourhost>
      - PORT=80
      # Set your email
      #- EMAIL=<your email>
      # Turn on production mode
      #- MODE=PRODUCTION
    links:
      - angular:proxied
  angular:
    image: thanhson1085/angular-admin-seed
    networks:
      - proxy
networks:
  proxy:

This compose file defines a network called proxy that provides a connection between the reverse proxy and the business app (this case it’s called angular and it’s a simple AngularJS app). The app must be accessible with the proxied name, and the target port is configurable. Most likely you’ll use 80 or 8080.

The most important configuration is the HOST. It defines the URL for the certificate; make sure it’s valid, as the validation process will fail otherwise. You should use your own registered domain here, if you have one. For testing purposes, you can use nip.io; it provides a domain for public IPs.

Let’s Encrypt has a blacklist of domains you can’t use. For example you can’t use amazonaws.com as it would be a security risk. Keep this in mind if you are using it from AWS.

If you don’t use Docker Compose, you can manually set up a Docker Network and add an alias to your application.

The default option is to use the staging servers, which generates a not trusted certificate. Let’s Encrypt limits the number of certificates that can be issued, so that it’s best practice to test with dummy ones. If you request too many live certs in a short period of time, you can easily find yourself limited and have to wait a week or two to get back on track. Only uncomment the MODE variable when you are deploying to production and you’ve already tested your setup.

How it works

The container utilises Supervisor to start and manage the different services. First and foremost, there is an Apache web server that provides the reverse proxy. Then the certificate registration and the renewal is separated, as the former is only needed during initialization, and the latter is persistent.

The initialization process is as follow:

  • The Apache web server starts
  • The certificate registration task kicks off and generates a cert
  • After the cert is received, it reconfigures then restarts Apache
  • Then it kicks off the renewal script, which Supervisor will restart when finished
  • The renewal script checks the expiration date every day and requests a new one if needed. It restarts Apache when a new cert is installed

Conclusion

This solution provides a fully automated, configure-and-forget way to have HTTPS for your website. It is suitable to provide SSL termination in any environment that uses Docker networks without much configuration.

10 May 2016

Interesting article?

Get hand-crafted emails on new content!