7 min read

Using Docassemble with Traefik and HTTPS

I push my docker skills to put docassemble behind a reverse proxy, Traefik, complete with HTTPS!
Using Docassemble with Traefik and HTTPS

Things you can only do during a lockdown – install a new server. As I mentioned previously, I got round to installing the latest Ubuntu LTS on my home server. Instead of using apt get for new software, I would run my server services through Docker instead. First up, I got Pi-Hole working and blocking ads. I's been sweet.

Let’s Play with: Pi-Hole
I try to install Pi-Hole Server to block all ads and tracking websites at home.

My conviction to use containers started with docassemble. You can use docassemble to generate contracts from answering questions. It's relevant to my work and I am trying to get more of my (non-legal) colleagues to try it. Unlike other software I have tried, docassemble recommends just using docker. With one command, docker run -d jhpyle/docassemble, I would get a fully-featured server. My mind was blown.

A free, open-source expert system for guided interviews and document assembly, based on Python, YAML, and Markdown.

However, as I became more familiar with how to get docker to do what I want, the limitations of that simple command began to restrict me. Docassemble uses several ports. Many other applications shares the sames port, especially for a web server: 80 and 443. If docker and docassemble took these ports, no one else was going to get them. I wasn't sure if I wanted my home server to be just a docassemble server.

Furthermore, using secure ports (HTTPS) became a serious problem. I wanted to use my home server's docassemble installation as a development base, so it should be accessible to the outside world. For some reason, docassemble wouldn't accept my wildcard certs. If I planned to use it for anything serious, having an unsecured website was impossible.

It got so frustrating, I gave up.

Enter the Reverse-Proxy: Traefik

The short answer to my problems was to use a reverse proxy. A reverse proxy is a kind of server that gets information from another server for a client. Or in this case, a traefik server receives a request and figures out which docker container it should go to. A traefik server can also do other things, such as providing end to end security for your communications by obtaining free SSL certificates from Let's Encrypt.

Traefik Documentation

I was convinced to go for this because it claimed that it would make "publishing your services a fun and easy experience". When I read that, I let a tear go. Is it actually possible for this program to automatically detect the right configuration for your services? Even for something as big as docassemble?

I'll let you be the judge of that at the end of this article.

Step 1: Set up Traefik

Of course, you would need to have docker set up and good to go.

There are a bunch of ways to get Traefik going, but I would be using a docker-compose.yml file like in the QuickStart.

The documentation for docassemble does not mention anything about docker compose. It is a shame because I found it to be a more user-friendly tool than the docker command-line interface. So instead of writing a bash script just to shorten my long docker run command, I would write out the blueprint of my setup in the docker-compose.yml. After that, I can run docker-compose up -d and the services in the file will start altogether.

This is very important in my setup, because there are other services in my home server like plex or grocy (another lockdown project) too. For the sake of convenience, I decided to include all these like projects in the same docker-compose.yml file. This is the blueprint of my home server!

Back to Traefik, this is the section of my docker-compose.yml file setting out the reverse proxy server:

    # The official v2 Traefik docker image
    image: traefik:v2.2
    container_name: traefik
    # Enables the web UI and tells Traefik to listen to docker
    command: --api.insecure=true --providers.docker
      # The HTTP/HTTPS port
      - "80:80"
      - "443:443"
      # The Web UI (enabled by --api.insecure=true)
      - "8080:8080"
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock
      - /home/houfu/traefik/:/etc/traefik/
    restart: unless-stopped

Just a few notes:

  • This line /home/houfu/traefik/:/etc/traefik/ under volumes allows me to have access to the configuration file used by traefik.
  • This line DO_AUTH_TOKEN: XXX under environment is to generate SSL certificates using my personal domain, which is managed by DigitalOcean.

Step 2: Prepare Traefik to generate SSL Certificates

Instead of having docassemble obtain the SSL certificates to use HTTPS, I decided to get Traefik to do it instead. Reverse proxies do this job much better, and I wouldn't need to "enter" the docassemble container to hunt down why SSL is not working.

Besides, my other services on my home server were already getting their certificates through Traefik, so getting docassemble to do the same would be straightforward right?

For this step, you would need to define a certificate resolver for Traefik to use. Please read the documentation as it is quite informative. For my set up, I decided to use DigitalOcean as I was already using it for my DNS.

In the configuration file (traefik.toml), add a section to define the certificate resolver.

    email = "admin@admin.com"
    storage = "acme.json"

    # used during the challenge
    provider = "digitalocean"

The final step, especially if you have chosen DigitalOcean as a provider, is to get an API key and provide it to Traefik so that the process of getting a certificate can be automated. This was the DO_AUTH_TOKEN in the docker-compose.yml file referred to in the first step.

Step 3: Provide a blueprint for the Docassemble service

Once we have the reverse proxy set up, it’s time to get docassemble to run. This is the final form of the docker-compose.yml file for the docassemble service.

    image: "jhpyle/docassemble:latest"
    hostname: docassemble
    container_name: docassemble
    stop_grace_period: 1m30s
      - DBPREFIX=postgresql+psycopg2://
      - DBNAME=docassemble
      - DBUSER=docassemble
      - DBPASSWORD=abc123
      - DBHOST=localhost
      - USEHTTPS=false
      - DAHOSTNAME=docassemble.example.com
      - USELETSENCRYPT=false
      - S3ENABLE=true
      - S3SECRETACCESSKEY=1234567
      - S3BUCKET=docassemble
      - S3ENDPOINTURL=https://xxxx.sgp1.digitaloceanspaces.com
      - TIMEZONE=Asia/Singapore
      - traefik.backend=docassemble
      - traefik.http.routers.docassemble.rule=Host(`docassemble.example.com`)
      - traefik.http.services.docassemble.loadbalancer.server.port=80
      - traefik.http.routers.docassemble.tls=true
      - traefik.http.routers.docassemble.tls.certresolver=docassembleResolver
      - traefik.http.middlewares.docassemble-redirect.redirectscheme.scheme=https
      - traefik.http.middlewares.docassemble-redirect.redirectscheme.permanent=true
      - traefik.http.routers.docassemble.middlewares=docassemble-redirect

One of the most important aspects of setting up your own docassemble server is figuring out the environment variables. The docassemble documentation recommends that we use an env.list file or pass a list of configuration values to the docker run command. For our docker-compose file, we pass them as a dictionary to the environment section of the service blueprint. Feel free to add or modify these options as you need. For example, you can see that I am using DigitalOcean Spaces as my S3 compatible storage.

So where does the magic of Trafik’s automatic configuration come in? Innocuously under the label section of the blueprint. Let’s split this up for easy explanation.

  - traefik.backend=docassemble
  - traefik.http.routers.docassemble.rule=Host(`docassemble.example.com`)
  - traefik.http.services.docassemble.loadbalancer.server.port=80
In the first block of labels, we define the name and the host of the docassemble server. Traefik now knows what to call this server, and to direct queries from “docassemble.example.com” to this server. As docassemble exposes several ports, we also help prod traefik to use the correct port to access the server.
  - traefik.http.routers.docassemble.tls=true
  - traefik.http.routers.docassemble.tls.certresolver=docassembleResolver
In this block of labels, we tell Traefik to use HTTPS and to use the certificate provider we defined earlier to get these certificates.
  - traefik.http.middlewares.docassemble-redirect.redirectscheme.scheme=https
  - traefik.http.middlewares.docassemble-redirect.redirectscheme.permanent=true
  - traefik.http.routers.docassemble.middlewares=docassemble-redirect
Finally we tell traefik to use a middleware here — a redirect. The redirect middleware ensures that uses will use HTTPS to communicate with the server.

Note that in our environment variables for the docassemble server, we tell docassemble not to use https (“USEHTTPS=false”). This is because traefik is already taking care of it. We don’t need docassemble to bother with it.

It works!

Docassemble servers take a bit of time to set up. But once you get it up, you will see my favourite screen in the entire application.

docassemble server is working.
I would like to thank my...

Notice the grey padlock in the address bar of my Firefox browser? That’s right, HTTPS baby!!

Final Thoughts

I am glad I learnt a lot about docker from docassemble, and its documentation is top-notch for what it is. However, running one is not easy. Using docker-compose helped iron out of some of the pain. In any case, I am glad I got over this. It’s time to get developing! What should I work on next?

Enjoyed this post? You can read more about law or technology on Love.Law.Robots. by subscribing today. I post at least once a week and subscribers get a free members only newsletter.  Thank you!