Skip to main content
xcaddy is the official tool for building custom Caddy binaries with plugins. This guide shows you how to compile Caddy with the Defender plugin from source.

Prerequisites

You need Go 1.21 or later installed on your system. Check your version with go version.

Installation Steps

1

Install xcaddy

Install xcaddy using Go:
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
Verify the installation:
xcaddy version
Make sure your $GOPATH/bin directory is in your $PATH. On most systems, this is ~/go/bin.
2

Build Caddy with Defender Plugin

Run the build command to compile Caddy with the Defender plugin:
xcaddy build --with pkg.jsn.cam/caddy-defender
This command:
  • Downloads the latest Caddy source
  • Fetches the Defender plugin from pkg.jsn.cam/caddy-defender
  • Compiles everything into a single caddy binary
The build process may take a few minutes depending on your system.
3

Verify the Build

Check that the Defender plugin is included:
./caddy list-modules | grep defender
You should see output like:
http.handlers.defender
4

Run Your Custom Caddy

Create a Caddyfile with Defender configuration:
localhost:8080 {
    defender block {
        ranges openai aws
    }
    respond "Protected by Caddy Defender!"
}
Run Caddy with your configuration:
./caddy run --config Caddyfile

Build Options

Building a Specific Version

Build Caddy v2.8.4 with the Defender plugin:
xcaddy build v2.8.4 --with pkg.jsn.cam/caddy-defender

Building from Local Source

If you’ve cloned the Defender repository locally and want to build from your local copy:
xcaddy build --with pkg.jsn.cam/caddy-defender=/path/to/local/caddy-defender
This is useful for:
  • Testing local modifications
  • Development and debugging
  • Using unreleased features

Building with Multiple Plugins

Add additional Caddy plugins to your build:
xcaddy build \
  --with pkg.jsn.cam/caddy-defender \
  --with github.com/mholt/caddy-ratelimit \
  --with github.com/caddy-dns/cloudflare

Installing System-Wide

Installing system-wide will replace any existing Caddy installation. Back up your current binary if needed.
After building, install the binary to your system:

Linux/macOS

sudo mv caddy /usr/local/bin/
sudo chmod +x /usr/local/bin/caddy
Verify the installation:
caddy version

Windows

Move caddy.exe to a directory in your PATH, such as C:\Windows\System32\.

Setting Up as a Service

systemd (Linux)

Create a systemd service file at /etc/systemd/system/caddy.service:
[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/local/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable caddy
sudo systemctl start caddy

Custom Build Tips

Build for different architectures: Use Go’s cross-compilation to build for other platforms:
GOOS=linux GOARCH=amd64 xcaddy build --with pkg.jsn.cam/caddy-defender

Optimizing Binary Size

Reduce the binary size by stripping debug information:
xcaddy build --with pkg.jsn.cam/caddy-defender
strip caddy

Development Builds

For faster builds during development, disable optimizations:
go build -gcflags="all=-N -l" -o caddy

Updating Your Build

To update to the latest version of Caddy and the Defender plugin:
1

Clean Previous Build

rm caddy
2

Rebuild with Latest Versions

xcaddy build --with pkg.jsn.cam/caddy-defender
3

Replace Existing Binary

sudo systemctl stop caddy
sudo mv caddy /usr/local/bin/
sudo systemctl start caddy

Troubleshooting

xcaddy Not Found

Ensure $GOPATH/bin is in your PATH:
export PATH=$PATH:$(go env GOPATH)/bin
Add this to your ~/.bashrc or ~/.zshrc to make it permanent.

Build Failures

If the build fails with module errors:
# Clear Go module cache
go clean -modcache

# Retry the build
xcaddy build --with pkg.jsn.cam/caddy-defender

Permission Errors When Running

On Linux, allow Caddy to bind to privileged ports:
sudo setcap CAP_NET_BIND_SERVICE=+eip ./caddy

Next Steps

Advanced Build

Build with custom IP range fetchers

Configuration

Configure the Defender plugin

Build docs developers (and LLMs) love