Custom middlewares

Traefik middleware changes a request before it reaches a resource. Common uses include rate limits, response headers, IP allow lists, redirects, and external authentication.

How you attach middleware depends on the resource type. Standard applications can use generated labels or manually edited labels. Docker Compose applications and services can use Coolify's coolify.traefik.middlewares shorthand.

Keep labels managed by Coolify when possible

Choosing Managed manually (edit labels yourself) in Label management stops Coolify from regenerating application labels. You become responsible for every router, middleware, service, and certificate label for the application. Use dynamic configuration with a small reference label when it can meet the requirement.

Define reusable middleware

Open Servers > your server > Proxy > Dynamic Configurations and create a file such as shared-middlewares.yaml. Start with the example that matches the request change you need. You can combine multiple middleware definitions in the same file.

http:
  middlewares:
    app-rate-limit:
      rateLimit:
        average: 100
        period: 1m
        burst: 50

The @file suffix identifies middleware loaded from Traefik's file provider.

Attach middleware to a resource

Open the application General page and find Container labels. Set Label management to Managed manually (edit labels yourself), then append the middleware names to the existing HTTPS router label:

traefik.http.routers.https-0-<resource-id>.middlewares=gzip 
traefik.http.routers.https-0-<resource-id>.middlewares=gzip,app-rate-limit@file,security-headers@file 

Keep every existing middleware name. Save and redeploy the application.

If the route breaks, select Reset to defaults, set Label management back to Managed by Coolify (auto-generated), and redeploy before trying again.

You can also define middleware with Docker labels. For example:

labels: 
  - 'traefik.http.middlewares.app-rate-limit.ratelimit.average=100'
  - 'traefik.http.middlewares.app-rate-limit.ratelimit.period=1m'
  - 'traefik.http.middlewares.app-rate-limit.ratelimit.burst=50'
  - 'coolify.traefik.middlewares=app-rate-limit'

Use file-based configuration when several resources share the same middleware. Use labels when the middleware belongs to one Compose service.

Coolify attaches every middleware that the service defines

Coolify adds each middleware that a traefik.http.middlewares.<name>.* label of the service defines to all routers that it generates for that service. The coolify.traefik.middlewares line in the example above is optional. You need it only for middleware that the service does not define, such as @file middleware. If a middleware must apply to some requests only, read Use your own routers in Docker Compose.

Use your own routers in Docker Compose

You can add your own Traefik routers to a Compose service, for example to protect one path or one hostname with a different middleware. Coolify still generates its own routers, so two routers can match the same request.

How the routers work together

For each URL in the Domains field of a service, Coolify generates one HTTPS router and one HTTP router. Their names start with https-<n>-<resource-uuid>-<service> and http-<n>-<resource-uuid>-<service>. Their rule is:

Host(`example.com`) && PathPrefix(`/`)

These generated routers get every middleware that the service defines with labels. Coolify does not check whether one of your routers already uses that middleware.

When more than one router matches a request, Traefik uses the router with the highest priority. If you do not set a priority, the priority is the length of the rule. For the same hostname, the rule of the generated router is usually longer than your rule, so the generated router gets the request.

This has two results:

  • A middleware that you attach to your router also applies to the generated routers. For example, an IP allow list that is for /admin only also blocks all other paths of the domain.
  • If the generated router gets the request, the middleware chain of your router does not run.

Choose a setup

GoalSetup
A middleware for one path or one hostname onlyDefine the middleware in a dynamic configuration file and attach it to your router as <name>@file. Set priority on your router to a value that is higher than the length of every generated rule, for example 100.
Your router must be the only router for a hostnameRemove that hostname from the Domains field. Your router must then set entrypoints, tls, tls.certresolver, and service itself. The generated routers for the other domains of the service still get the middleware that the service defines.
The same middleware on all generated routersDefine the middleware with labels. You do not have to attach it.
Do not attach access rules with labels only

A middleware that you define with labels also applies to all generated routers. An IP allow list or a deny rule for one path then blocks the full domain. If you use @file middleware and your router has no priority, the generated router can get the request, and your access rule does not run.

Example

This example lets only one IP address open /admin on https://example.com. All other paths stay public. The Domains field of the service contains https://example.com.

Add this dynamic configuration in Servers > your server > Proxy > Dynamic Configurations:

http:
  middlewares:
    admin-allow:
      ipAllowList:
        sourceRange:
          - '203.0.113.10/32'

Add the router to the service:

services:
  app:
    image: nginx:alpine
    labels:
      - 'traefik.http.routers.app-admin.rule=Host(`example.com`) && PathPrefix(`/admin`)'
      - 'traefik.http.routers.app-admin.entrypoints=https'
      - 'traefik.http.routers.app-admin.tls=true'
      - 'traefik.http.routers.app-admin.tls.certresolver=letsencrypt'
      - 'traefik.http.routers.app-admin.priority=100'
      - 'traefik.http.routers.app-admin.middlewares=admin-allow@file'

Because of priority=100, Traefik sends requests for /admin to app-admin, and admin-allow@file runs. The generated router gets all other requests without the allow list.

After you deploy, run this command on the server to see the middleware chain of each router:

docker inspect <container-name> --format '{{json .Config.Labels}}' | jq 'with_entries(select(.key | endswith(".middlewares")))'

Redirects

Choose the redirect that matches the result you need.

Standard applications have a built-in www redirect setting on Domains. Add both hostnames, keep labels managed by Coolify, then choose one of:

www redirectResult
No redirectBoth configured hostnames remain available.
Redirect to wwwThe non-www hostname redirects to the configured www hostname.
Redirect to non-wwwThe www hostname redirects to the configured non-www hostname.

Select Save changes and redeploy if the running container does not yet have the regenerated labels. Both hostnames also need DNS records that point to the server.

Docker Compose applications and services

Add both domains to the resource, then add the redirect middleware labels to the service that receives them.

labels: 
  - 'traefik.http.middlewares.example-redirect.redirectregex.regex=^(http|https)://(?:www\.)?(.+)'
  - 'traefik.http.middlewares.example-redirect.redirectregex.replacement=${1}://www.${2}'
  - 'traefik.http.middlewares.example-redirect.redirectregex.permanent=true'
  - 'coolify.traefik.middlewares=example-redirect'

These examples assume Escape special characters in labels? remains enabled. If you disable it, write each $ as $$ in the source Compose file.

Troubleshooting

On this page