How to have HTTPs on development with Docker, Traefik v2 and mkcert
Tags: docker, webdev
Published: 2019-10-13 16:09:21

## Docker is cool

I've discovered Docker recently. I know... it's been there for a while, but I've never added it to my workflow until very recently and I'm quite happy with the solutions it gives me to the problems I have. I'm still a newbie with it and enjoying a lot what I'm learning. 

One of the things I like about Docker is that it allows me to carry the stack definition I want for my project between different computers and reduces a lot the amount of effort I need to setup my dev env when I'm playing with some side projects.

This article is meant for Docker newbies like myself who need to solve this fairly common  web development problem.

## HTTPs and domain names in development are important

Making sure that your development environment looks similar to your production one is important. It helps reducing unexpected issues when going live.

I've used nginx in the past for this and it is still a very solid solution. But in development and just for a simple development reverse proxy I prefer to use [traefik][] these days. Mainly because it works pretty well with Docker.

In addition to that, to simply generate signed certificates in development I use [mkcert][], which is super simple to use. Many also propose and use [Let's Encrypt][letsencrypt] and traefik itself has some support for it, but we won't use in this example.

## Stop it already! what do I need?

- You need an application of some sort. Ours is going to be `ruby -run -e httpd . -p 3000` which is a server showing the current folder's contents. Note as well that I don't run my apps inside Docker itself during development. I don't do it because I run things like linters, test suites, etc from my editor and running the app inside Docker is usually a barrier for that. 

    If you run the app inside docker check the [traefik][] documentation because having this same proxy in your case is even easier!
- You need Docker running on your machine.
- Some way to resolve the domain you want to your app. In my case I just add the domain I need to my `/etc/hosts` but you might prefer other solutions like using dnsmasq.

## The config!

1. You need something like this in your `docker-compose.yml`.
    {% gist https://gist.github.com/franciscoj/4ba7dbbba1406f9d2b70b8d2404855fb file=docker-compose.yml %}

     You don't need to have only that. I typically declare other stuff there like databases or other infrastructure pieces that I need in development.
2. This is the static configuration for traefik.
    {% gist https://gist.github.com/franciscoj/4ba7dbbba1406f9d2b70b8d2404855fb file=traefik.toml %}


3. And this is the dynamic one, which defines the routing between the different parts.
    {% gist https://gist.github.com/franciscoj/4ba7dbbba1406f9d2b70b8d2404855fb file=traefik.config.toml %}

4. Last but not least you need to install [mkcert][] and run it to generate a couple of mock certs for you. What I usually do is that I keep a `devcerts` folder in my projects that I ignore. And then I generate a new cert on each new dev machine. In this case with:

    ```sh
    mkcert mkcert my-app.com "*.my-app.com"
    ```
    To have *.my-app.com available.

    Note however that you could avoid that by using [Let's Encrypt][letsencrypt], but I've not needed it, so I don't use it.

5. Put it all together! This is how I organize the code in this example:

    ```
    example
    ├── devcerts
    │   ├── my-app.com+1-key.pem
    │   └── my-app.com+1.pem
    ├── docker-compose.yml
    ├── traefik.config.toml
    └── traefik.toml

    ```
6. Run your app (`ruby -run -e httpd . -p 3000` or whatever your app incantation is!)
7. Run `docker-compose up` and see the magic happen!

You can now go go `http://my-app.com` and see how you're automatically redirected to `https://my-app.com` and have your app working there :D

Remember to check `http://my-app.com:8080` to see traefik's dashboard.

Finally kudos to my mate gtrias for showing me what I can do with Docker!

(Spoiler, he's on dev.to too!)

 {% user gtrias %} 





[traefik]: https://traefik.io
[mkcert]: https://mkcert.dev
[letsencrypt]: https://letsencrypt.org