Build and Deploy a Custom Caddy 2 Server with Plugins, Docker, and Systemd

This guide introduces Caddy 2, explains its advantages over Nginx, walks through compiling it with xcaddy and third‑party plugins, shows host and Docker installation methods, and demonstrates modular Caddyfile configuration, TLS automation, and service management with systemd.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Build and Deploy a Custom Caddy 2 Server with Plugins, Docker, and Systemd

Overview

Caddy is a Go‑based web server that provides automatic HTTPS via ACME, built‑in TLS with strong defaults, a human‑readable configuration language (Caddyfile), an API for dynamic updates, HTTP/3 (QUIC) support, and a modular plugin architecture.

Automatic ACME HTTP/DNS certificate issuance and renewal with OCSP stapling

Memory‑safe Go codebase and sensible TLS defaults

Simple, declarative configuration files (Caddyfile) that are internally converted to JSON

Dynamic back‑ends (Consul, Kubernetes ingress, etc.) and multiple load‑balancing/health‑check strategies

Extensible via plugins compiled with

xcaddy

Compiling Caddy 2

1. Install Go (Ubuntu 20.04 example)

wget https://golang.org/dl/go1.15.6.linux-amd64.tar.gz
# Extract
 tar -zxvf go1.15.6.linux-amd64.tar.gz
# Move to a permanent location
 mkdir -p /opt/devtools
 mv go /opt/devtools/go
# Create GOPATH directories
 mkdir -p ${HOME}/gopath/{src,bin,pkg}
# Export environment variables (add to ~/.bashrc or ~/.zshrc)
export GOROOT='/opt/devtools/go'
export GOPATH="${HOME}/gopath"
export GOPROXY='https://goproxy.cn'
export PATH="${GOROOT}/bin:${GOPATH}/bin:${PATH}"
source ~/.zshrc

Verify the installation:

go version
# Expected output: go version go1.15.6 linux/amd64

2. Install xcaddy

go get -u github.com/caddyserver/xcaddy/cmd/xcaddy

After installation the xcaddy command should be available in ${GOPATH}/bin.

3. Build Caddy with desired plugins

# Install helper tools
apt install -y curl git jq
# Retrieve the latest release tag from GitHub
export version=$(curl -s "https://api.github.com/repos/caddyserver/caddy/releases/latest" | jq -r .tag_name)
# Build Caddy with selected plugins
xcaddy build ${version} --output ./caddy_${version} \
    --with github.com/abiosoft/caddy-exec \
    --with github.com/caddy-dns/cloudflare \
    --with github.com/caddy-dns/dnspod \
    --with github.com/caddy-dns/duckdns \
    --with github.com/caddy-dns/gandi \
    --with github.com/caddy-dns/route53 \
    --with github.com/greenpau/caddy-auth-jwt \
    --with github.com/greenpau/caddy-auth-portal \
    --with github.com/greenpau/caddy-trace \
    --with github.com/hairyhenderson/caddy-teapot-module \
    --with github.com/kirsch33/realip \
    --with github.com/porech/caddy-maxmind-geolocation \
    --with github.com/caddyserver/format-encoder \
    --with github.com/mholt/caddy-webdav

After a short build the binary caddy_${version} is produced.

Compilation log
Compilation log

Verify compiled modules:

./caddy_${version} list-modules
# Output includes admin.api, dns.providers.cloudflare, http, tls, etc.

Installing Caddy 2

Systemd installation (Debian/Ubuntu)

# Add Caddy repository and install the official package
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/cfg/gpg/gpg.155B6D79CA56EA34.key' | sudo apt-key add -
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/cfg/setup/config.deb.txt?distro=debian&version=any-version' | sudo tee -a /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
# Replace the binary with the custom build
systemctl stop caddy
sudo rm -f /usr/bin/caddy
sudo mv ./caddy_${version} /usr/bin/caddy

Docker installation

Build a Docker image from a Dockerfile that runs xcaddy build … with the required plugins, then push the image to a registry (e.g., mritd/caddy).

Configuring Caddy 2

Caddyfile is a concise, human‑readable configuration format that the server translates to JSON. The full syntax is documented at https://caddyserver.com/docs/caddyfile (refer to the URL as plain text).

Configuration snippets (reusable blocks)

# TLS snippet – defines protocols and cipher suites
(TLS) {
    protocols tls1.2 tls1.3
    ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 \
            TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 \
            TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
}

# Log snippet – parameterized log file path
(LOG) {
    log {
        output file "{args.0}" {
            roll_size 100mb
            roll_keep 3
            roll_keep_for 7d
        }
    }
}

Modular imports

# Import all Caddyfiles in a directory
import /etc/caddy/*.caddy

Site block example with automatic HTTPS, DNS‑01 challenge, reverse proxy and log import

example.com {
    # Automatic HTTPS using DNS‑01 via Gandi (token from environment variable)
    tls {
        dns gandi {env.GANDI_API_TOKEN}
    }
    # Import the log snippet, passing the log file path as argument
    import LOG "/var/log/caddy/example.com.log"
    # Simple reverse proxy to an upstream service
    reverse_proxy localhost:8080
}

Environment variables can be referenced directly with {env.VAR_NAME} (or {$VAR_NAME}) to keep secrets out of the file.

Running and Reloading

Start the service:

systemctl start caddy

After any configuration change, reload without stopping the process:

systemctl reload caddy

If the new Caddyfile contains errors, the reload fails and the existing instance continues serving traffic.

Example Directory Layout

caddy/
├── Caddyfile            # Global snippets and imports
├── example.com.caddy   # Site‑specific configuration
└── other-site.caddy    # Additional site configurations

Summary

Caddy 2 offers a modern, feature‑rich alternative to traditional web servers. With automatic TLS, HTTP/3, a flexible plugin system, and a concise Caddyfile syntax, it simplifies the deployment of secure web services. The steps above cover setting up the Go toolchain, compiling a custom Caddy binary with plugins, installing it via systemd or Docker, and configuring common scenarios such as TLS via DNS‑01, logging, and reverse proxying.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PluginsCaddy
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.