Developing Traefik Plugins

The Traefik plugin architecture makes it easy for developers to create new plugins, modify existing ones, and share plugins with the Traefik community.

Traefik plugins are developed using the Go language, and a Traefik middleware plugin is just a Go package that provides an http.Handler to perform specific processing of requests and responses.

Rather than being pre-compiled and linked, however, plugins are executed on the fly by Yaegi, a Go interpreter that's embedded in the Traefik application proxy.

This means plugins do not need to be compiled and no elaborate toolchain is required to get started. The process of developing Traefik plugins is comparable to that of web browser extensions.

Experimental Features

Plugins can potentially modify the behavior of Traefik in undesired ways. Exercise caution when adding new plugins to production Traefik instances.

Packaging Plugins

As mentioned in the overview, Traefik admins can browse and add plugins to their instances from the catalog in the Traefik Pilot dashboard.

From a technical perspective, the actual code for each plugin is stored and hosted in a public GitHub repository. Every 30 minutes, Traefik Pilot polls GitHub to find repositories that match the criteria for a Traefik plugin and adds them to its catalog.

Prerequisites

To be recognized by Traefik Pilot, your plugin's repository must meet the following criteria:

  • The traefik-plugin topic must be set.
  • The .traefik.yml manifest must exist and have valid contents.

In addition, Traefik Pilot gets your sources from a Go module proxy, so your plugins must be versioned with a git tag.

If your repository fails to meet these prerequisites, Traefik Pilot will not recognize it and your plugin will not be added to the catalog.

Manifest

A manifest is also mandatory, and it should be named .traefik.yml and stored at the root of your project.

This YAML file provides Traefik Pilot with information about your plugin, such as a description, a full name, and so on.

# The name of your plugin as displayed in the Traefik Pilot web UI.
displayName: Name of your plugin

# For now, `middleware` is the only type available.
type: middleware

# The import path of your plugin.
import: github.com/username/my-plugin

# A brief description of what your plugin is doing.
summary: Description of what my plugin is doing

# Configuration data for your plugin.
# This is mandatory,
# and Traefik Pilot will try to execute the plugin with the configuration you provide as part of its startup validity tests.
testData:
  Headers:
    Foo: Bar

Properties include:

  • displayName: The name of your plugin as displayed in the Traefik Pilot web UI.
  • type: For now, middleware is the only type available.
  • import: The import path of your plugin.
  • summary: A brief description of what your plugin is doing.
  • testData: Configuration data for your plugin. This is mandatory, and Traefik Pilot will try to execute the plugin with the data you provide as part of its startup validity tests.

There should also be a go.mod file at the root of your project. Traefik Pilot will use this file to validate the name of the project.

Developer Mode

For those who prefer to develop their plugins in private before deploying them to GitHub, Traefik also offers a developer mode that can be used for temporary testing.

To deploy a plugin in dev mode requires changes to both the static and dynamic configurations. The static configuration must define the module name (as is usual for Go packages) and a path to a Go workspace, which can be what's stored in the local GOPATH environment variable or any other path. The dynamic configuration must reference the label dev.

# Plugin will be loaded from path '/plugins/go/src/github.com/traefik/plugindemo'
pilot:
  token: xxxxx

experimental:
  devPlugin:
    goPath: /plugins/go
    moduleName: github.com/traefik/plugindemo
http:
  routers:
    my-router:
      rule: host(`demo.localhost`)
      service: service-foo
      entryPoints:
        - web
      middlewares:
        - my-plugin

  services:
   service-foo:
      loadBalancer:
        servers:
          - url: http://127.0.0.1:5000

  middlewares:
    my-plugin:
      plugin:
        dev:
          headers:
            Foo: Bar

Developer Mode Limitations

Note that only one plugin can be tested in dev mode at a time, and when using dev mode, Traefik will shut down after 30 minutes.

Defining a Plugin

A plugin package must define the following exported Go objects:

  • A type type Config struct { ... }. The struct fields are arbitrary.
  • A function func CreateConfig() *Config.
  • A function func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error).
// Package example (an example plugin).
package example

import (
    "context"
    "net/http"
)

// Config the plugin configuration.
type Config struct {
    // ...
}

// CreateConfig creates the default plugin configuration.
func CreateConfig() *Config {
    return &Config{
        // ...
    }
}

// Example a plugin.
type Example struct {
    next     http.Handler
    name     string
    // ...
}

// New created a new plugin.
func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error) {
    // ...
    return &Example{
        // ...
    }, nil
}

func (e *Example) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
    // ...
    e.next.ServeHTTP(rw, req)
}

Additional Dependencies

If your plugin has any external module dependencies, they must be vendored and included in the plugin's GitHub repository. Go modules are not supported.

Troubleshooting

If something goes wrong with the integration of your plugin, Traefik Pilot will create an issue inside your GitHub repository explaining the problem and will stop trying to add your plugin until you close the issue.

In order for your plugin to be successfully imported by Traefik Pilot, consult this checklist:

  • The traefik-plugin topic must be set on your repository.
  • There must be a .traefik.yml file at the root of your project describing your plugin, and it must have a valid testData property for testing purposes.
  • There must be a valid go.mod file at the root of your project.
  • Your plugin must be versioned with a git tag.
  • If you have package dependencies, they must be vendored and added to your GitHub repository.

Sample Code

In addition to the skeleton example above, a complete example plugin, demo, is available for you to use as a reference for developing your own plugins.

To view the code and explore further, please visit the demo plugin GitHub repository.