How to use traefik as a reverse proxy in development
This is the fourth part of the series about local development with b5, docker and traefik. If you haven’t read the first three parts, you should do that to get the full context of this article.
How to resolve a custom top level domain to localhost
As a prerequisite, we need to install dnsmasq
to resolve a custom tld
to localhost.
Throughout the whole series, I will expect that you are using a macOS (10.15.3 from the this was written)
We use brew to install dnsmasq:
1brew install dnsmasq
Additionally, we have to add a dnsmasq.conf
file with one line of configuration:
1echo 'address=/.test/127.0.0.1' > $(brew --prefix)/etc/dnsmasq.conf
This line configures dnsmasq
to point all requests to domains ending on .test
from 127.0.0.1
.
Add a custom macOS resolver
We also need to add a resolver to macOS:
1sudo mkdir -p /etc/resolver2sudo bash -c 'echo "nameserver 127.0.0.1" > /etc/resolver/test'
Let dnsmasq
automatically start on boot
To add dnsmasq to the auto start we use brew services
:
1sudo brew services start dnsmasq
Reboot macOS that the changes take effect.
Test dnsmasq and the resolver
In order to test this part, we can simply ping a random .test
domain. It should get an answer from 127.0.0.1
.
1ping foobar.test2PING foobar.test (127.0.0.1): 56 data bytes364 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.038 ms
Set up the traefik project
In our setup, traefik is a dedicated b5
project that we will put it into a .b5
folder in our home directory. I will not go into details on the project structure because this is explained in detail in (this)[] article.
1mkdir ~/.b5/traefik && cd ~/.b5/traefik2git init # b5 need a initialised repository in order to work
Project structure:
1- build2 - config.yml3 - docker-compose.yml4 - Taskfile5 - traefik.toml
config.yml
We use traefik
as a project key
and enable the docker module of b5
.
1project:2 key: traefik3modules:4 docker:
docker-compose.yml
In this tutorial, we will use version 1.7
of traefik. The latest version at the time that this article was written is 2.1
. I tried for a few hours to figure out a working configuration for the latest version but it was all in vain. As soon as I have a working configuration, I will update this post.
1version: "3.7" 2 3services: 4 5 traefik: 6 image: traefik:1.7 7 restart: always 8 networks: 9 - gateway10 volumes:11 - /var/run/docker.sock:/var/run/docker.sock12 - ./traefik.toml:/traefik.toml13 ports:14 - 80:8015 - 443:44316 - 8080:808017 18networks:19 gateway:
We have a docker-compose.yml
with a single service named traefik
. With the restart: always
configuration, it will automatically start when docker
starts. The service will be attached to the gateway
network, which is defined at the end of the file. Traefik needs the docker socket to mount into the service next to the traefik.toml
, which we create in the next step. We map the hosts port 80
and 443
to traefik because it will proxy all requests later. Port 8080
is for the traefik dashboard which gives us information about running services etc..
traefik.toml
1################################################################ 2# Global configuration 3################################################################ 4 5# Enable debug mode 6# 7# Optional 8# Default: false 9#10debug = true11 12# Entrypoints to be used by frontends that do not specify any entrypoint.13# Each frontend can specify its own entrypoints.14#15# Optional16# Default: ["http"]17#18#defaultEntryPoints = ["http"]19defaultEntryPoints = ["http", "https"]20 21# Entrypoints definition22#23# Optional24# Default:25[entryPoints]26 [entryPoints.http]27 address = ":80"28 [entryPoints.https]29 address = ":443"30 31# Traefik logs32# Enabled by default and log to stdout33#34# Optional35#36[traefikLog]37 38# Enable access logs39# By default it will write to stdout and produce logs in the textual40# Common Log Format (CLF), extended with additional fields.41#42# Optional43#44[accessLog]45 46################################################################47# Web configuration backend48################################################################49 50# Enable web configuration backend51[web]52 53# Web administration port54#55# Required56#57address = ":8080"58 59################################################################60# Docker configuration backend61################################################################62 63# Enable Docker configuration backend64[docker]65 66# Default domain used.67# Can be overridden by setting the "traefik.domain" label on a container.68#69# Optional70# Default: ""71#72domain = "test"73 74# Expose containers by default in traefik75#76# Optional77# Default: true78#79exposedbydefault = false80 81watch = true
This file contains the complete configuration for traefik to act as a reverse proxy for all our projects in development. The explanations are right in the file.
Taskfile
The Taskfile will only contain three commands which are self explanitory:
1task:run() { 2 docker:docker-compose up "$@" 3} 4 5task:halt() { 6 docker:docker-compose down "$@" 7} 8 9task:docker-compose() {10 docker:docker-compose "$@"11}
Start traefik
Now we can start the project with b5. We will demonise it with -d
:
1b5 run -d
The dashboard should now be accessible on localhost:8080
.
Configure our example project to use traefik
In the last article of this series, we built an example project with Laravel, phpMyAdmin and MailHog.
This is the current docker-compose.yml
from our example project:
1version: "3.7" 2 3services: 4 5# ... 6 7 web: 8 image: docker.team23.de/docker/apache:2.4-php 9 environment:10 APACHE_DOCUMENT_ROOT: /app/web/public11 volumes:12 - ../:/app13 ports:14 - 8000:8015 16# ...17 18 phpmyadmin:19 image: phpmyadmin/phpmyadmin:latest20 environment:21 PMA_HOST: mysql22 PMA_USER: root23 PMA_PASSWORD: secret24 depends_on:25 - mysql26 ports:27 - 8001:8028 29# ...30 31 mail:32 image: mailhog/mailhog33 ports:34 - 8025:802535 36# ...
Because we only need to enable traefik for services which need to be accessible from the host system, I have stripped out all services and volumes which are not relevant.
Add traefiks network
Since our traefik does not run inside this project but in its own project with its own namespace, we need to connect these docker networks. This can be achieved by the following configuration at the end of the docker-compose.yml
:
1# ...2 3networks:4 default:5 traefik_gateway:6 external: true
The default
network is as its name says, the network which is created by default in any project. When we add a new network, we also have to list the default
network to be created. Additionally, we add the traefik_gateway
network which is the network that we defined in our traefik project and mark it as external.
Enable traefik for the web and the phpMyAdmin service
To enable traefik for the web service, we have to attach the traefik_gateway
to it and add two labels:
1# ... 2 3 web: 4 image: docker.team23.de/docker/apache:2.4-php 5 environment: 6 APACHE_DOCUMENT_ROOT: /app/web/public 7 volumes: 8 - ../:/app 9 # ports:10 # - 8000:8011 networks:12 - default13 - traefik_gateway14 labels:15 - traefik.enable=true16 - traefik.docker.network=traefik_gateway17 18# ...19 20 phpmyadmin:21 image: phpmyadmin/phpmyadmin:latest22 environment:23 PMA_HOST: mysql24 PMA_USER: root25 PMA_PASSWORD: secret26 depends_on:27 - mysql28 # ports:29 # - 8001:8030 networks:31 - default32 - traefik_gateway33 labels:34 - traefik.enable=true35 - traefik.docker.network=traefik_gateway36 37# ...
As you can see, we commented out the port mapping because we don't need this anymore. The configuration for both services is absolutely identical.
Enable traefik for MailHog
MailHog needs an additional configuration because it does not run on port 80
or 443
by default:
1# ... 2 3 mail: 4 image: mailhog/mailhog 5 # ports: 6 # - 8001:80 7 networks: 8 - default 9 - traefik_gateway10 labels:11 - traefik.enable=true12 - traefik.port=8025 # additional line13 - traefik.docker.network=traefik_gateway14 15# ...
That's all. Now we can test the setup by executing b5 run
.
The new frontends
and backends
in traefik should now be visible n the dahboard
.
The scheme regarding which url will be resolved is as follows:
{service}.{project_key}.test
This means we can access our three services with the following urls:
Recap
We configured dnsmasq
and created an independent traefik
service which is able to proxy requests for multiple projects at the same time. Since we do not need the port mappings anymore, we can start multiple projects at the same time without shifting the ports. As last step we configured our example project to use traefik for three different services.
Thanks for reading the article. If you have questions just drop me a line here.