Skip to content

Writing a Plugin: Directives

Matt Holt edited this page Sep 19, 2016 · 7 revisions

Join the Caddy Community Forum to chat with other Caddy developers!

This page describes how to write a plugin that registers a new directive for the Caddyfile.

Directives can do things like run code when the server starts or shuts down, change server configuration, etc. For example, a common thing is to use a directive to configure and inject a middleware handler into an HTTP server.

  1. Create a new Go package
  2. Implement a Setup Function
  3. Order your Directive
  4. Plug in your Plugin (applies to any plugin)

1. Create a new Go package

Caddy plugins are Go packages. Create a new one that imports the caddy package and registers your plugin. Let's create one called "gizmo" that is specific to the HTTP server only:

import "github.com/mholt/caddy"

func init() {
	caddy.RegisterPlugin("gizmo", caddy.Plugin{
		ServerType: "http",
		Action:     setup,
	})
}

Directive Name

The name of your directive plugin is also the name of the directive. It must be unique! It should be one word, lowercased. This is an important simplicity and usability convention.

Server Type

Most directives apply only to a specific type of server. For example, directives for the "http" server type such as gzip and fastcgi configure and inject a middleware handler. These kinds of plugins typically need to import the package of the relevant server type.

Some directives don't pertain to a specific type of server. For example, tls is a directive that any server type can use to take advantage of Caddy's powerful TLS capabilities, and startup and shutdown run commands when a server starts/stops, no matter what type of server it is. In that case, the ServerType field can be left empty. In order to use these kinds of directives, server types must be coded to support them specifically.

Action (The "Setup Function")

The Action field of the caddy.Plugin struct is what makes a directive plugin unique. This is the function to run when Caddy is parsing and executing the Caddyfile.

The action is simply a function that takes a caddy.Controller and returns an error:

func setup(c *caddy.Controller) error {
	return nil
}

Next, we look at how to use this Controller to execute your directive.

2. Implement the Setup Function

After Caddy has parsed the Caddyfile, it iterates each directive name (in the order prescribed by the server type) and calls the directive's setup function every time it encounters the directive name. It is the responsibility of the setup function to parse the directive's tokens and configure itself.

The Controller struct makes this quite easy. Notice that the type definition embeds caddyfile.Dispenser. If we expect a line in the Caddyfile such as:

gizmo foobar

We can get the value of the first argument ("foobar") like so:

for c.Next() {              // skip the directive name
    if !c.NextArg() {       // expect at least one value
        return c.ArgErr()   // otherwise it's an error
    }
    value := c.Val()        // use the value
}

You parse the tokens present for your directive by iterating over c.Next() which is true as long as there are more tokens to parse. Since a directive may appear multiple times, you must iterate over c.Next() to get all the appearances of your directive and consume the first token (which is the directive name).

See the godoc for the caddyfile package to learn how to use the Dispenser more fully, and take a look at any other existing plugins for examples.

3. Order your Directive

The last thing you have to do is tell the server type where in the process to execute your directive. This is important because other directives may set up more primitive configuration that you rely on, so the order that the directives are executed cannot be arbitrary.

Each server type has a list of strings where each item is the name of a directive. For instance, see the HTTP server's list of supported directives. Add your directive to the list in the proper place.

4. Plug in your Plugin

Finally, don't forget to import your plugin's package! Caddy must import your plugin to register and execute it. This is usually done within run.go:

import _ "your/plugin/package/here"

That's it! Build caddy with your plugin, then write a Caddyfile with your new directive to see it in action.

If you are writing an HTTP middleware, continue to the next page.

Clone this wiki locally