Traefik is a very interesting tool which I've come across just recently. Originally I was looking to use nginx as a reverse proxy and setup some automation in order to request a certificate from let's encrypt so I could setup my site for https.
Then I found out Traefik could do exactly what I want. This website is in fact being handled with Traefik right now and will request a new cert when it's close to the expiry, but also act as a reverse proxy with very little setup.
So with my setup, I'm using docker containers for my sites. So this will be from that perspective.
To start, I created a docker network which can be used either with single instances or in a swarm and attach containers. This is the command to do that.
docker network create -d overlay --attachable web
After the network is created, let's create a username and password so we can access traefik later on.
htpasswd -nb username securepassword
Be sure to keep the output for now as we will need that for later.
Now let's create a folder to make sure we don't get confused with all this. So create a folder in a path you have permissions and want to continue with this and call it traefik.
mkdir traefik cd traefik
Create two files and we also need to change the permissions of one to make sure we can write the cert information later on when we run traefik.
touch acme.json traefik.toml chmod 600 acme.json
Edit traefik.toml and add the following, but replace the email with your domain email and the user being setup with the secure password you created earlier.
defaultEntryPoints = ["http", "https"] [entryPoints] [entryPoints.dashboard] address = ":8080" [entryPoints.dashboard.auth] [entryPoints.dashboard.auth.basic] users = ["username:securepassword"] [entryPoints.http] address = ":80" [entryPoints.http.redirect] entryPoint = "https" [entryPoints.https] address = ":443" [entryPoints.https.tls] [api] entrypoint="dashboard" [acme] email = "[email protected]" storage = "acme.json" entryPoint = "https" onHostRule = true [acme.httpChallenge] entryPoint = "http" [docker] watch = true
For the next part, you'll need to go to your domain provider and create a new A name value. This is so we can access traefik over a sub domain. For this example we'll use traefik.yourdomain.example. So make sure you add a new A name for the sub domain traefik.
When that's complete, let's run traefik in docker whilst you're in the traefik folder.
docker run -d \ -v /var/run/docker.sock:/var/run/docker.sock \ -v $PWD/traefik.toml:/traefik.toml \ -v $PWD/acme.json:/acme.json \ -p 80:80 \ -p 443:443 \ -l traefik.frontend.rule=Host:traefik.yourdomain.example \ -l traefik.port=8080 \ --network web \ --name traefik \ traefik:1.7.19-alpine
Give it a few minutes and then try accessing traefik by going to the sub domain we created earlier. It should ask you for a username and password. Enter what you put in earlier and it should load.
Next step is to setup our containers with traefik as a reverse proxy. To do this, look at the example below and we will go through it.
version: '3.1' services: ghost: image: ghost:3.0.3-alpine depends_on: - db environment: # see https://docs.ghost.org/docs/config#section-running-ghost-with-config-env-variables database__client: mysql database__connection__host: db database__connection__user: root database__connection__password: example database__connection__database: ghost labels: - traefik.backend=ghost - traefik.frontend.rule=Host:yourdomain.example - traefik.docker.network=web - traefik.port=2368 networks: - web - internal db: image: mysql:5.7 volumes: - ghost_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: example networks: - internal labels: - traefik.enable=false networks: web: external: true internal: external: false volumes: ghost_data:
So what's going on here? Let me explain some of the not so obvious parts.
In the following:
labels: - traefik.backend=ghost - traefik.frontend.rule=Host:yourdomain.example - traefik.docker.network=web - traefik.port=2368 networks: - web - internal
What we are doing here is setting a bunch of labels for traefik to interpret.
We're setting the backend to look for the service called ghost. We set the frontend to be the domain we have purchased. We set the docker network to web as traefik to monitoring that network and we set it to port 2368 as that is the port exposed by default for ghost.
We then set this container to attach to web and internal. The reason for this is everything on the web network will be on the frontend and so long as we provide a sub domain and set the same kind of labels as we did for ghost, we should be able to access it through traefik. We also attach internal which is the backend and we add any services we don't want access via the reverse proxy.
For the db we have:
networks: - internal labels: - traefik.enable=false
All we're doing here is setting the db to work on the internal network so it can communicate with ghost and making sure traefik doesn't monitor this container by setting traefik to false.
And the last part is adding the networks:
networks: web: external: true internal: external: false
So all we're doing here is adding the web network we created earlier so the containers can attached to the pre existing network and communicate with traefik.
If you run docker-compose on this file everything should start going. I haven't talked much about let's encrypt because when you bring up the containers, check the acme.json file and you'll most likely see the certs setup. This is because of the http challenge which was setup in the first config file. It's that easy. Now traefik will be used as a reverse proxy and request new certs close to expiry.