What Makes a Module

As mentioned in the index page of this chapter, modules implement the caddy.Module interface, which is defined as:

type Module interface {
	// This method indicates that the type is a Caddy
	// module. The returned ModuleInfo must have both
	// a name and a constructor function. This method
	// must not have any side-effects.
	CaddyModule() ModuleInfo
}

The type caddy.ModuleInfo is defined as:

type ModuleInfo struct {
	// ID is the "full name" of the module. It
	// must be unique and properly namespaced.
	ID ModuleID

	// New returns a pointer to a new, empty
	// instance of the module's type. This
	// method must not have any side-effects,
	// and no other initialization should
	// occur within it. Any initialization
	// of the returned value should be done
	// in a Provision() method (see the
	// Provisioner interface).
	New func() Module
}
type ModuleID string

This makes the simplest way to impelement a (rather non-functional) module is:

type MyModule struct{}

func(MyModule) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID: "namespace.of.my_module",
		New: func() caddy.Module {
			new(MyModule)
		},
	}
}

// optional but recommended
var _ caddy.Module = (*MyModule)(nil)

However, you must also tell Caddy about the module, which is typically done by registering it in an init() func as such:

import "github.com/caddyserver/caddy/v2"

func init(){
	caddy.RegisterModule(MyModule{})
}