Skip to main content
xcaddy is the official build tool for Caddy that simplifies building custom binaries with plugins and proper version information.

What is xcaddy?

From README.md:145, xcaddy is our builder tool that automates the build process. It handles:
  • Creating proper project structure
  • Managing Go modules
  • Injecting version information
  • Adding custom plugins
  • Cross-compilation

Installation

Install xcaddy using Go:
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
Verify installation:
xcaddy version
Ensure $GOPATH/bin is in your PATH to run xcaddy from anywhere.

Basic Usage

Build Standard Caddy

From README.md:148:
xcaddy build
This creates a caddy binary in the current directory with:
  • Proper version information
  • All standard modules
  • Platform-specific optimizations

Build Specific Version

xcaddy build v2.8.0
Or use a commit hash:
xcaddy build abc123def456
Or a branch:
xcaddy build master

Building with Plugins

Add a Plugin from GitHub

xcaddy build \
    --with github.com/caddyserver/nginx-adapter

Add Multiple Plugins

xcaddy build \
    --with github.com/caddyserver/nginx-adapter \
    --with github.com/greenpau/caddy-security

Specify Plugin Version

xcaddy build \
    --with github.com/caddyserver/[email protected]

Local Plugin Development

For local plugin development, use a local path:
xcaddy build \
    --with github.com/example/caddy-plugin=../caddy-plugin
The local path is relative to where you run xcaddy. Use absolute paths to avoid confusion.

Output Control

Specify Output Path

xcaddy build --output /usr/local/bin/caddy

Cross-Platform Builds

# Linux AMD64
GOOS=linux GOARCH=amd64 xcaddy build

# Windows AMD64
GOOS=windows GOARCH=amd64 xcaddy build --output caddy.exe

# macOS ARM64 (Apple Silicon)
GOOS=darwin GOARCH=arm64 xcaddy build

# Linux ARM (Raspberry Pi)
GOOS=linux GOARCH=arm GOARM=7 xcaddy build

What xcaddy Automates

From README.md:151, xcaddy performs these steps automatically:
1

Create project folder

mkdir caddy
cd caddy
2

Copy main.go

Copies Caddy’s main.go and adds plugin imports:
import (
    _ "time/tzdata"
    caddycmd "github.com/caddyserver/caddy/v2/cmd"
    _ "github.com/caddyserver/caddy/v2/modules/standard"
    
    // Plugins added by xcaddy
    _ "github.com/example/plugin"
)
3

Initialize Go module

go mod init caddy
4

Pin Caddy version

go get github.com/caddyserver/caddy/v2@version
5

Add plugin dependencies

go get github.com/example/plugin@version
6

Build with proper flags

go build -tags=nobadger,nomysql,nopgx

Advanced Options

Replace Modules

Replace a dependency with a fork:
xcaddy build \
    --with github.com/caddyserver/caddy/v2=github.com/myuser/caddy/v2@mybranch

Build with Specific Go Version

go1.25.0 install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
go1.25.0 run github.com/caddyserver/xcaddy/cmd/xcaddy build

Disable Module Optimization

By default, xcaddy trims unused dependencies:
xcaddy build --with-trimpath=false

Development Workflow

Quick Iteration

For rapid plugin development:
# Build with local plugin
xcaddy build \
    --with github.com/myuser/caddy-plugin=./caddy-plugin

# Test
./caddy run --config test.Caddyfile

# Make changes to plugin...

# Rebuild
xcaddy build \
    --with github.com/myuser/caddy-plugin=./caddy-plugin

Using xcaddy run

Test without building:
xcaddy run \
    --with github.com/myuser/caddy-plugin=./caddy-plugin \
    --config Caddyfile
This builds a temporary binary and runs it immediately.

Build Caching

xcaddy leverages Go’s build cache. Subsequent builds are faster:
# First build (slow)
xcaddy build --with github.com/example/plugin

# Subsequent builds (fast, if plugin unchanged)
xcaddy build --with github.com/example/plugin
Clear the cache if needed:
go clean -cache

Environment Variables

Proxy Configuration

export GOPROXY=https://proxy.golang.org,direct
xcaddy build

Private Repositories

export GOPRIVATE=github.com/myorg/*
xcaddy build --with github.com/myorg/private-plugin

Custom Build Flags

export XCADDY_GO_BUILD_FLAGS="-ldflags='-s -w' -trimpath"
xcaddy build

Common Plugin Examples

Nginx Config Adapter

Convert Nginx configs to Caddy:
xcaddy build \
    --with github.com/caddyserver/nginx-adapter

./caddy adapt --config nginx.conf --adapter nginx

CloudFlare DNS Provider

For DNS-01 ACME challenges:
xcaddy build \
    --with github.com/caddy-dns/cloudflare

Rate Limiting

xcaddy build \
    --with github.com/mholt/caddy-ratelimit

Multiple Plugins Together

xcaddy build \
    --with github.com/caddyserver/nginx-adapter \
    --with github.com/caddy-dns/cloudflare \
    --with github.com/greenpau/caddy-security \
    --with github.com/mholt/caddy-ratelimit

Verification

After building, verify your binary includes plugins:
# List all modules
./caddy list-modules

# Check for specific module
./caddy list-modules | grep plugin_name

# Verify version
./caddy version

Troubleshooting

Module Not Found

Ensure the plugin path is correct and accessible:
# Check if module exists
go get -d github.com/example/plugin

# Then build
xcaddy build --with github.com/example/plugin

Version Conflicts

Specify exact versions:
xcaddy build v2.8.0 \
    --with github.com/example/[email protected]

Permission Denied

On Linux, set capabilities:
sudo setcap cap_net_bind_service=+ep ./caddy

Build Fails with Local Plugin

Ensure your plugin has a go.mod file:
cd caddy-plugin
go mod init github.com/myuser/caddy-plugin
go mod tidy

GOPROXY Timeout

Use direct mode:
GOPROXY=direct xcaddy build \
    --with github.com/example/plugin

Comparison with Manual Build

xcaddy build \
    --with github.com/example/plugin
xcaddy is:
  • ✅ Faster and less error-prone
  • ✅ Handles version information correctly
  • ✅ Manages all dependencies automatically
  • ✅ Supports quick iteration with local plugins

Next Steps

Custom Builds

Create production-ready custom builds

Plugin Tutorial

Develop your own plugin

Building from Source

Manual build process details

Module Development

Deep dive into module creation

Build docs developers (and LLMs) love