Good tech adventures begin with some frustration, a necessity, or a requirement. That is the story of how I simplified the administration and entry of my native net purposes with the assistance of Traefik and dnsmasq. The reasoning applies simply as properly for a manufacturing server utilizing Docker.
My dev atmosphere consists of a rising variety of net purposes self-hosted on my laptop computer. Such purposes embody a number of web sites, instruments, editors, registries, … They use databases, REST APIs, or extra complicated backends. Take the instance of Supabase, the Docker Compose file consists of the Studio, the Kong API gateway, the authentication service, the REST service, the real-time service, the storage service, the meta service, and the PostgreSQL database.
The result’s a rising variety of containers began on my laptop computer, accessible at
localhost on varied ports. A few of them use the default ports and can’t run in parallel to keep away from conflicts. For instance, the
8000 ports are frequent to numerous containers current on my machine. To avoid the difficulty, some containers use customized ports which I usually occur to neglect.
The answer is to create native domains that are straightforward to recollect and use an online proxy to route the requests to the right container. Traefik helps within the routing and the invention of these companies and dnsmasq offers a customized top-level area (pseudo-TLD) to entry them.
One other utilization of Traefik is a manufacturing server utilizing a number of Docker Compose information for varied web sites and net purposes. The containers talk inside an inside community and are uncovered by means of a proxy service, in our case applied with Caddy.
Out of many, let’s take 3 net purposes operating domestically. All of them are managed with Docker Compose:
- Adaltas web site, 1 container, Gatsby-based static web site
- Alliage web site, 10 containers, Subsequent.js frontend, Node.js backend, and Supabase
- Penpot, 6 containers, Penpot frontend, backend companies plus Inbucket for e mail testing (private addition)
By default, these containers expose the next ports on localhost:
8000Gatsby server in dev mode
9000Gatsby service to serve a construct web site
3000Subsequent.js web site each dev and construct mode
3001Node.js customized API
2500Inbucket SMTP server
9000Inbucket Net interface
1100Inbucket POP3 server
2500Inbucket SMTP server
9000Inbucket Net interface
1100Inbucket POP3 server
Word, relying in your atmosphere and wishes, some ports is likely to be restricted whereas different ports is likely to be accessible.
As you possibly can see, many ports collide with one another. It isn’t simply the two cases of Inbucket operating in parallel. For instance, port
8000 is used each by Gatsby and Kong. It’s a frequent default port for a number of purposes. The identical goes for ports
One resolution is to assign distinctive ports for every service. Nevertheless, this strategy will not be scalable. Quickly sufficient, I neglect to which port every service is assigned.
A greater resolution is the utilization of a reverse proxy with hostnames straightforward to recollect. Here’s what we count on:
www.adaltas.nativeGatsby server in dev mode
construct.adaltas.nativeGatsby service to serve a construct web site
www.alliage.nativeSubsequent.js web site each dev and construct mode
api.alliage.nativeNode.js customized API
smtp.alliage.nativeInbucket SMTP server
mail.alliage.nativeInbucket Net interface
pop3.alliage.nativeInbucket POP3 server
smtp.penpot.nativeInbucket SMTP server
mail.penpot.nativeInbucket Net interface
pop3.penpot.nativeInbucket POP3 server
In a standard setting, the reverse proxy is configured with one or a number of configuration information with all of the routing data. Nevertheless, a central configuration will not be so handy. It’s preferable to have every service declares which hostname they resolve.
Automated routing registration
All my net companies are managed with Docker Compose. Ideally, I count on data to be current contained in the Docker Compose file. Traefik is cloud-native within the sense that it configures itself utilizing cloud-native workflows. The applying offers some directions current in its
docker-compose.yml file and the containers are robotically uncovered.
The way in which Traefik works with Docker, it plugs into the Docker socket, detects new companies, and creates the routes for you.
To start out Traefik inside Docker is easy (by no means say straightforward). The
docker-compose.yml file is:
model: '3' companies: reverse-proxy: picture: traefik:v2.9 command: --api.insecure=true --suppliers.docker ports: - "80:80" - "8080:8080" volumes: - /var/run/docker.sock:/var/run/docker.sock
Registering new companies
Let’s take into account a further service. The Adaltas web site is a single container based mostly on Gatsby. In improvement mode, it begins an online server on port
8000. I count on it to be accessible with the hostname
www.adaltas.native on port
Following the Traefik’s getting began with Docker, the mixing is made with the property
traefik.http.routers.router_name.rule current within the
labels area of the docker service. It defines the hostname underneath which our web site is accessible on port
80. It’s set to
www.adaltas.localhost as a result of the
.localhost TLD resolves domestically by default. Since I favor to make use of the
.native area, we set the area to
www.adaltas.native later utilizing dnsmasq. The site visitors is then routed to the container IP on port 8000. The container port is obtained by Traefik from the Docker Compose’s
model: '3' companies: www: container_name: adaltas-www ... labels: - "traefik.http.routers.adaltas-www.rule=Host(`www.adaltas.localhost`)" ports: - "8000:8000"
This works when each the Traefik and the Adaltas companies are outlined in the identical Docker compose file. Firing
docker-compose up and you’ll:
http://localhost:8080: Entry the Traefik net UI
http://localhost:8080/api/rawdata: Entry the Traefik’s API rawdata
http://www.adaltas.localhost: Entry the Adaltas web site in improvement mode
http://localhost:8080: Similar as
There are 3 limitations we have to take care of:
- Inside networking
It solely works as a result of all of the companies are declared inside the identical Docker Compose file. With separated Docker Compose information, an inside community should be used to speak between the Traefic container and the targetted containers.
- Area identify
I want to use a pseudo top-level area (TLD), for instance,
www.adaltas.nativeas a substitute of
.nativeTLD doesn’t but resolve domestically, an area DNS server should be configured.
- Port label
The port of Adaltas is outlined contained in the Docker Compose file. Thus, it’s uncovered on the host machine and it collides with different companies. Port forwarding should be disabled and Traefik should be instructed concerning the port with one other mechanism than the
When outlined throughout separated information, the container can not talk. Every Docker Compose file generates a devoted community. The focused service is seen contained in the Traefik UI. Nevertheless, the request fails to be routed.
The containers should share a standard community to speak. When the Traefik container is began, a
traefik_default community is created, see
docker community checklist. As an alternative of making a brand new community, let’s reuse it. Enrich the Docker Compose file of the targetted container, the Adaltas web site in our case, with the
model: '3' companies: www: container_name: adaltas-www networks: default: identify: traefik_default
After beginning the two Docker Compose setups with
docker-compose up, the Traefik and the Web site containers begin speaking.
It’s time to sort out the FQDN of our companies. The present TLD in use,
.localhost, is completely high quality. It really works by default and it’s formally reserved for this utilization. Nevertheless, I want to use my very own top-level domains (pseudo-TLD identify), we’ll use
.native on this instance.
Disclaimer, utilizing a pseudo-TLD identify will not be really useful. The
.nativeTLD is utilized by multicast DNS / zero-configuration networking. In follow, I haven’t encountered any points. To mitigate the chance of conflicts, RFC 2606 reserves the next TLD names:
.take a look at,
A neighborhood DNS server is used to resolve the
*.native addresses. I had some expertise with Bind previously. A less complicated and extra light-weight possibility is the utilization of dnsmasq. The directions under cowl the set up on MacOS and Ubuntu Desktop. In each instances, dnsmaq is put in and configured to not intervene with the present DNS settings.
brew set up dnsmasq mkdir -pv $(brew --prefix)/and many others/ echo 'handle=/.native/127.0.0.1' >> $(brew --prefix)/and many others/dnsmasq.conf sudo brew companies begin dnsmasq sudo mkdir -v /and many others/resolver sudo bash -c 'echo "nameserver 127.0.0.1" > /and many others/resolver/take a look at' scutil --dns
Linux directions with NetworkManager (eg Ubuntu Desktop):
systemctl disable systemd-resolved systemctl cease systemd-resolved unlink /and many others/resolv.conf cat <<CONF | sudo tee /and many others/NetworkManager/conf.d/00-use-dnsmasq.conf [main] dns=dnsmasq CONF cat <<CONF | sudo tee /and many others/NetworkManager/dnsmasq.d/00-dns-public.conf server=188.8.131.52 CONF cat <<CONF | sudo tee /and many others/NetworkManager/dnsmasq.d/00-address-local.conf handle=/.native/127.0.0.1 CONF systemctl restart NetworkManager
dig to validate that any FQDN utilizing our pseudo-TLD resolves to the native
With the introduction of a reverse proxy like Traefik, exposing the container port on the host machine is now not essential, thus, eliminating the chance of collision between the uncovered port and those of different companies.
One label is already current to outline the hostname of the web site service. Traefik comes with numerous complementary labels. The
traefik.http.companies.service_name.loadbalancer.server.port property tells Traefik to make use of a particular port to connect with a container.
The ultimate Docker Compose file seems to be like this:
model: '3' companies: www: container_name: adaltas-www picture: node:18 volumes: - .:/app consumer: node working_dir: /app command: bash -c "yarn set up && yarn run develop" labels: - "traefik.http.routers.adaltas-www.rule=Host(`www.adaltas.native`)" - "traefik.http.companies.adaltas-www.loadbalancer.server.port=8000" networks: default: identify: traefik_default
With Traefik, I like the concept of my container companies registering robotically in a cloud-native philosophy. It offered me with confort and ease. Additionally, dnsmasq has proved to be well-documented and fast to regulate to my varied necessities.