Learning Caddy - Caddy Plugins & Modules
Episode 29 of 31

Learning Caddy - Caddy Plugins & Modules

This episode covers Caddy's extensibility: the module system, popular plugins like caddy-dns and caddy-rate-limit, custom builds with xcaddy, and the basics of plugin development in Go.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Episode 2 introduced Caddy's modular architecture. Episode 29 puts it to full use: plugins. Nearly every Caddy feature is a module that can be replaced or added, and the community has built hundreds of plugins for DNS, rate limiting, authentication, and more.

You'll learn Caddy's module system, popular plugins worth knowing, how to build a custom binary with xcaddy, and a basic overview of plugin development in Go for those interested in contributing.

This is the episode that makes Caddy infinitely customizable — from a simple reverse proxy to a highly specialized edge proxy.

The Caddy Module System

Core, Standard, and Third-Party

Caddy modules fall into categories:

  • Core: the parts that can't be removed.
  • Standard: built-in modules in the default build.
  • Third-party: community modules that need to be added via a custom build.

caddy list-modules shows all modules available in your binary:

List modules
caddy list-modules

Every module has a type and name, e.g. http.handlers.reverse_proxy. This helps you understand the structure when writing JSON configuration.

Plugin Architecture

Plugins implement specific interfaces:

  • Handler: processes requests (http.handlers.*).
  • Matcher: matches requests (http.matchers.*).
  • DNS provider: solves DNS challenges (dns.providers.*).
  • Storage: certificate storage backends.

Plugins are registered at compile time. Adding a plugin means rebuilding the Caddy binary — which is where xcaddy comes in.

caddy-dns and Rate Limiting

Some of the most used plugins:

  • caddy-dns/cloudflare: DNS challenges for Cloudflare (episode 9).
  • caddy-rate-limit: rate limiting per IP or endpoint (episode 19).
  • caddy-security: an authentication, GeoIP, and CORS suite.
  • caddy-git: auto-deploy from a Git repository.
  • caddy-docker-proxy: manage Caddy from Docker labels.
  • caddy-cloudflare: full Cloudflare integration.

We already saw the rate limit plugin example in episode 19. The common theme: adding capabilities that don't exist in the default build.

Choosing Plugins

Before adding a plugin:

  • Check whether the feature already exists in a standard module.
  • Make sure the plugin is actively maintained and compatible with your Caddy version.
  • Consider the license and the developer's reputation.

A plugin is code running at the edge — choose carefully.

Custom Builds with xcaddy

Installing xcaddy

xcaddy is the official tool for building Caddy with plugins:

Install xcaddy
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

xcaddy requires Go to be installed. go install ...@latest places the xcaddy binary in $GOBIN.

Building with Plugins

The basic command:

Build with one plugin
xcaddy build v2.8.0 \
  --with github.com/caddy-dns/cloudflare

xcaddy build v2.8.0 builds a specific Caddy version with the given plugin. If no version is written, the latest is used.

Many Plugins and Specific Versions

Combine several plugins and pin their versions:

Build with many plugins
xcaddy build \
  --with github.com/caddy-dns/cloudflare \
  --with github.com/mholt/caddy-l4 \
  --with github.com/caddyserver/caddy/v2@v2.8.0

--with module@version allows pinning module versions. Store this build command in your documentation or a script — builds must be reproducible.

Verifying the Build

After the build finishes, a binary named caddy sits in the working directory. Verify:

Verify compiled modules
./caddy list-modules | grep dns.providers

./caddy list-modules | grep dns.providers confirms the DNS module was compiled in. Replace your system binary with this build and run it as usual.

Plugin Development

Plugin Basics in Go

To write your own plugin, you create a Go module that implements Caddy's interfaces:

Basic plugin structure
package main
 
import "github.com/caddyserver/caddy/v2"
 
type myHandler struct{}
 
func (m *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) error {
    // handler logic
    return nil
}
 
func init() {
    caddy.RegisterModule(myHandler{})
}
 
func main() {
    caddycmd.Main()
}

A plugin is registered via init() with caddy.RegisterModule. The full structure includes the CaddyModule, Provision, and Validate interfaces.

HTTP Handlers and Caddyfile Unmarshal

A good handler plugin also supports the Caddyfile:

Caddyfile unmarshal
func (m *myHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
    for d.Next() {
        if !d.NextArg() {
            return d.ArgErr()
        }
        m.option = d.Val()
    }
    return nil
}

UnmarshalCaddyfile reads arguments from the Caddyfile. With this method, your plugin can be used through a regular Caddyfile, not just JSON.

Registration and Building

  1. Create a Go module with the plugin.
  2. Build it together with Caddy using xcaddy, with --with pointing at your repository.
  3. Test the plugin with caddy run and caddy list-modules.

Conclusion

Episode 29 opened up Caddy's extensibility: the module system with core, standard, and third-party categories, popular plugins like caddy-dns and caddy-rate-limit, custom builds with xcaddy, and the basics of Go plugin development with registration and Caddyfile unmarshal.

Key takeaways:

  • Every Caddy feature is a module; plugins add capabilities.
  • caddy list-modules shows the compiled modules.
  • xcaddy build --with module creates a custom binary.
  • Plugins must be compatible with your Caddy version.
  • Plugins are written in Go and registered via RegisterModule.
  • Verify the build with list-modules | grep when done.

In the next episode, episode 30 — the final episode of the series — we'll cover production deployment & best practices — a pre-production checklist, Caddyfile best practices, security hardening, performance tuning, operations with graceful reloads, high availability, common pitfalls, troubleshooting, and migrating from NGINX.

Learning Caddy - Caddy Plugins & Modules | Learning Caddy