Using iocaine as a Traefik middleware
Last updated: 2025-11-14

# Getting started

Because Traefik’s documentation heavily emphasizes containers, in this guide, we’ll combine Traefik’s Docker example, and our own Getting Started with Containers guide. We will, of course, need Docker (or Podman) too.

We’ll start with a `compose.yaml`, modeled after the Traefik documentation, with Traefik itself, and the “whoami” demo application:

    services:
      traefik:
        image: traefik:v3.5
        command:
          - "--api.dashboard=true"
          - "--api.insecure=true"
          - "--providers.docker=true"
          - "--entrypoints.web.address=:80"
        ports:
          - "80:80"
          - "8080:8080"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock

      whoami:
        image: traefik/whoami
        labels:
          - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"

We’re going to need `iocaine` too, and the Traefik iocaine middleware. We’re going to add the former to our `compose.yaml`, but lets clone the latter!

    # git clone https://git.mstar.dev/mstar/traefik-iocaine-middleware.git \
        plugins-local/src/git.mstar.dev/mstar/traefik-iocaine-middleware

Why into such a directory? Because the plugin is (thankfully) not on GitHub, so the only way to install it is through local mode, and that requires this layout.

A full configuration will be shown at the end of this guide, should you wish to skip ahead and start playing immediately.

# Integrating iocaine

First, lets add the `iocaine` container to our compose file! For the sake of simplicity, I’ll use a simplified version, but feel free to follow the Getting Started with iocaine and containers guide, and copy the service you ended up with.

Here, we’ll add the following block under `services`:

      iocaine:
        image: git.madhouse-project.org/iocaine/iocaine:latest
        ports:
          - '127.0.0.1:42069:42069'
        environment:
          - RUST_LOG=iocaine=info

This doesn’t do much yet, we have to tell Traefik about it! Lets add two more lines to the `traefik` service’s commandline: one to enable the middleware, and the other to tell `traefik` where to find it. The `traefik` service should look like this after that:

      traefik:
        image: traefik:v3.5
        command:
          - "--api.dashboard=true"
          - "--api.insecure=true"
          - "--providers.docker=true"
          - "--entrypoints.web.address=:80"
          # The following two lines are NEW:
          - "--entrypoints.web.http.middlewares=iocaine@docker"
          - "--experimental.localPlugins.iocaine.moduleName=git.mstar.dev/mstar/traefik-iocaine-middleware"
        ports:
          - "80:80"
          - "8080:8080"
        volumes:
          # The next line is also NEW:
          - ./plugins-local:/plugins-local
          - /var/run/docker.sock:/var/run/docker.sock

Oh, right, yes, we also mount the local `plugins-local` to `/plugins-local`, to make the source of the plugin available for `traefik`! The `entrypoints` line tells `traefik` where to find the configuration for the entrypoint: attached to `iocaine@docker`. Lets adjust our `iocaine` service, and add a label or two:

      iocaine:
        image: git.madhouse-project.org/iocaine/iocaine:latest
        ports:
          - '127.0.0.1:42069:42069'
        environment:
          - RUST_LOG=iocaine=info
        labels:
          - 'traefik.http.middlewares.iocaine.plugin.iocaine.iocaineHttpUrl=http://iocaine:42069'
          - 'traefik.http.middlewares.iocaine.plugin.iocaine.methods=GET,HEAD'

This tells the middleware the `iocaine` URL, and makes it filter `GET` and `HEAD` request methods only.

Surprisingly, once we `docker compose up -d`, we’re done:

    # curl http://whoami.localhost
    Hostname: dc31c07c9b64
    IP: 127.0.0.1
    IP: ::1
    IP: 10.89.2.2
    IP: fe80::88a1:78ff:fe16:ef69
    RemoteAddr: 10.89.2.4:54760
    GET / HTTP/1.1
    Host: whoami.localhost
    User-Agent: curl/8.14.1
    Accept: */*
    Accept-Encoding: gzip
    X-Forwarded-For: 10.89.2.1
    X-Forwarded-Host: whoami.localhost
    X-Forwarded-Port: 80
    X-Forwarded-Proto: http
    X-Forwarded-Server: d7cf6d6301bb
    X-Real-Ip: 10.89.2.1

    # curl http://whoami.localhost -A GPTBot
    ...garbage...

# Full configuration

To summarize, this is the final `compose.yaml` we ended up with:

    services:
      iocaine:
        image: git.madhouse-project.org/iocaine/iocaine:latest
        ports:
          - '127.0.0.1:42069:42069'
        environment:
          - RUST_LOG=iocaine=info
        labels:
          - 'traefik.http.middlewares.iocaine.plugin.iocaine.iocaineHttpUrl=http://iocaine:42069'
          - 'traefik.http.middlewares.iocaine.plugin.iocaine.methods=GET,HEAD'

      traefik:
        image: traefik:v3.5
        command:
          - "--api.dashboard=true"
          - "--api.insecure=true"
          - "--providers.docker=true"
          - "--entrypoints.web.address=:80"
          - "--entrypoints.web.http.middlewares=iocaine@docker"
          - "--experimental.localPlugins.iocaine.moduleName=git.mstar.dev/mstar/traefik-iocaine-middleware"
        ports:
          - "80:80"
          - "8080:8080"
        volumes:
          - ./plugins-local:/plugins-local
          - /var/run/docker.sock:/var/run/docker.sock

      whoami:
        image: traefik/whoami
        labels:
          - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"