Exposing multiport Docker containers with Traefik

Exposing containers with multiple ports through Traefik

Exposing multiport Docker containers with Traefik

Traefik does a really nice job of auto-discovering containers and the network ports where the service running within is exposed.

But some pieces of software make use of multiple network ports.

In this post, I want to illustrate how you can help Traefik to deal with this scenario.

Let's look at an example of a container that exposes multiple ports.


MQTT

MQTT is a popular and lightweight messaging protocol used for small sensors and mobile devices.

In this example, I'm using the Docker image of eclipse-mosquitto, an implementation of the protocol.

I want Mosquitto to make my MQTT endpoint available on both TCP port 1883 and through a Websocket on port 8080.

My Mosquitto configuration at its base looks like this:

port 1883
protocol mqtt

listener 8080
protocol websockets

Super easy right?

Since I want to leverage Let's Encrypt for encrypting the traffic from the outside to my services, I'm going to expose the TCP connection on a slightly different port, 8883, which is typically used for a TLS protected connection to Mosquitto. I need to instruct Traefik to listen on those ports on the host and restart (you need to restart Traefik when binding to ports)

[entryPoints.mqtt-secure]
  address = ":8883"

[entryPoints.mqtt-websockets]
  address = ":8080"

I then need to configure the correct labels in my docker container to tell Traefik how it needs to expose the internal ports.

The trick is to define the services separately where you define the internal ports, use them in your TCP and HTTP router definitions, and of course, use the entrypoints which we defined before in Traefik's configuration file.

docker run -d \
  --restart always \
  --name mqtt \
  -l traefik.tcp.routers.mqtt.rule='HostSNI(`mqtt.mydomain.org`)' \
  -l traefik.tcp.routers.mqtt.entrypoints=mqtt-secure \
  -l traefik.tcp.routers.mqtt.tls=true \
  -l traefik.tcp.routers.mqtt.tls.certresolver=default \
  -l traefik.tcp.routers.mqtt.service=mqtt-internal \
  -l traefik.tcp.services.mqtt-internal.loadbalancer.server.port=1883 \
  -l traefik.http.routers.mqtt-websockets.rule='Host(`mqtt.mydomain.org`)' \
  -l traefik.http.routers.mqtt-websockets.entrypoints=mqtt-websockets \
  -l traefik.http.routers.mqtt-websockets.tls=true \
  -l traefik.http.routers.mqtt-websockets.tls.certresolver=default \
  -l traefik.http.routers.mqtt-websockets.service=mqtt-websockets \
  -l traefik.http.services.mqtt-websockets.loadbalancer.server.port=8080 \
  --mount source=mosquitto-conf,target=/mosquitto/config \
  --mount source=mosquitto-data,target=/mosquitto/data \
  --mount source=mosquitto-logs,target=/mosquitto/log \
  --network internal \
  eclipse-mosquitto:1.6
Mastodon