A fully integrated Caddy Docker image featuring Namecheap DNS-01 ACME validation
Automated, multi-platform Docker builds of Caddy with the Namecheap DNS module baked in.
- Features
- Quick Start
- Included Modules
- Usage
- Configuration
- Tags
- Platform Support
- Troubleshooting
- How It Works
- Building Your Own Image
- Contributing
- License
- Automated Builds -- Daily checks for new Caddy releases with automatic image builds.
- Module Update Detection -- Tracks upstream module commits and rebuilds when they change.
- Base Image Tracking -- Rebuilds when the base image is republished with OS or Go toolchain fixes.
- Namecheap DNS-01 Integration -- Automatic SSL certificate management via DNS challenges.
- Multi-Platform -- Supports
amd64,arm64,arm/v7(Raspberry Pi),ppc64le, ands390x. - Alpine-Based -- Built on the official Caddy image, which uses Alpine Linux. A
slimvariant drops the stock binary. - Fork-Friendly -- Image names derived automatically from your GitHub repository.
Pull the image and set up a docker-compose.yml:
services:
caddy:
image: ghcr.io/caddybuilds/caddy-namecheap:latest
restart: unless-stopped
cap_add:
- NET_ADMIN
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- $PWD/Caddyfile:/etc/caddy/Caddyfile
- $PWD/site:/srv
- caddy_data:/data
- caddy_config:/config
environment:
- NAMECHEAP_API_KEY=your_namecheap_api_key
- NAMECHEAP_API_USER=your_namecheap_username
- NAMECHEAP_CLIENT_IP=your_public_ip
volumes:
caddy_data:
external: true
caddy_config:Defining the data volume as external ensures
docker-compose downdoes not delete it. Create it manually withdocker volume create caddy_data.
Replace the three values with your Namecheap API key, username and the public IP you whitelisted. See Creating Namecheap API Credentials for setup instructions, and Caddyfile Examples for configuration samples.
This module is compiled into Caddy at build time using xcaddy. No additional installation is needed.
| Module | Purpose | Repository |
|---|---|---|
caddy-dns/namecheap |
DNS-01 ACME challenge provider for Namecheap | caddy-dns/namecheap |
docker pull ghcr.io/caddybuilds/caddy-namecheap:latest
docker pull caddybuilds/caddy-namecheap:latest
# slim
docker pull ghcr.io/caddybuilds/caddy-namecheap:slim
docker pull caddybuilds/caddy-namecheap:slimSee Quick Start for a full docker-compose setup and Tags for every tag.
Set the ACME DNS challenge provider globally so it applies to all sites:
{
acme_dns namecheap {
api_key {env.NAMECHEAP_API_KEY}
user {env.NAMECHEAP_API_USER}
api_endpoint https://api.namecheap.com/xml.response
client_ip {env.NAMECHEAP_CLIENT_IP}
}
}
example.com {
root * /usr/share/caddy
file_server
encode gzip
}
another-example.com {
reverse_proxy localhost:8080
}
Configure the DNS challenge individually per site:
example.com {
root * /usr/share/caddy
file_server
encode gzip
tls {
dns namecheap {
api_key {env.NAMECHEAP_API_KEY}
user {env.NAMECHEAP_API_USER}
api_endpoint https://api.namecheap.com/xml.response
client_ip {env.NAMECHEAP_CLIENT_IP}
}
}
}
The Namecheap DNS provider needs API access on your account:
-
Log in to Namecheap at namecheap.com.
-
Enable API access:
- Go to "Account" > "Profile" > "Tools" > "API Access" and turn it on. Namecheap only enables API access for accounts that meet its API requirements.
-
Whitelist your public IP:
- Add the public IP address of the machine running Caddy to the API whitelist. Requests from other addresses are rejected.
-
Collect the credentials:
- API key: shown on the API Access page.
- Username: your Namecheap username.
- Client IP: the whitelisted public IP.
-
Set the environment variables:
NAMECHEAP_API_KEY,NAMECHEAP_API_USERandNAMECHEAP_CLIENT_IP. See Quick Start for the docker-compose example. Ifclient_ipis left out of the Caddyfile, the module detects the public IP itself.
To configure the ACME DNS challenge provider for all ACME transactions, add the following to your Caddyfile:
{
acme_dns namecheap {
api_key {env.NAMECHEAP_API_KEY}
user {env.NAMECHEAP_API_USER}
api_endpoint https://api.namecheap.com/xml.response
client_ip {env.NAMECHEAP_CLIENT_IP}
}
}
This is equivalent to specifying the provider in the tls directive's ACME issuer configuration. See Caddyfile Examples for full samples.
The image is available on GitHub Container Registry and Docker Hub. There are two images, default and slim, each under a few tags:
| Tags | Image |
|---|---|
latest, <version>, <major>.<minor>, <major> |
Default |
alpine, <version>-alpine, <major>.<minor>-alpine, <major>-alpine |
Default (same image, see below) |
slim, <version>-slim, <major>.<minor>-slim, <major>-slim |
Slim |
<version> pins a release (e.g. docker pull ghcr.io/caddybuilds/caddy-namecheap:2.11.7), <major>.<minor> follows the latest patch (e.g. 2.11) and <major> the latest release (e.g. 2). Slim tags exist from 2.11.7 onward.
Both run the same Caddy binary with the same modules. They differ only in the image underneath.
| Default | Slim | |
|---|---|---|
| Built on | The official Caddy image | caddy-base: the official image without its Caddy binary |
| Download size (amd64) | about 43 MB | about 24 MB |
| Caddy binaries inside | Two: the stock one stays in a lower layer, ours replaces it on top | One: ours |
| Rebuilt for base fixes when | The official Caddy image is republished | Alpine is republished (caddy-base rebuilds, then slim follows) |
Everything else is the same: Alpine, packages, default Caddyfile, /data and /config, ports, command, platforms, and permission to bind ports 80 and 443 as a non-root user.
Use slim for a smaller image. Use default if you want to stay on the Docker Official Image exactly as Caddy ships it.
This follows the official Caddy image. On Linux, caddy:latest, caddy:2.11.7 and caddy:2.11.7-alpine are all the same Alpine image. The plain tags also include Windows builds, which is the only reason both exist. We only build Linux images, so the -alpine tags are aliases: a setup that uses caddy:2.11.7-alpine can switch to caddy-namecheap:2.11.7-alpine without changing anything else.
Images are rebuilt without a new Caddy version when the module gets new commits or a base image is republished with OS or Go fixes (the official Caddy image for the default tags, caddy-base for slim). Each rebuild is logged under Rebuilds in that version's GitHub Release, and the reason is stored in the image labels:
docker inspect --format '{{ index .Config.Labels "caddy-build.reason" }}: {{ index .Config.Labels "caddy-build.details" }}' ghcr.io/caddybuilds/caddy-namecheap:latestThe image is built for the following platforms:
- linux/amd64 -- Standard x86_64 (desktops, servers)
- linux/arm64 -- ARM 64-bit (modern ARM servers, Apple Silicon via emulation)
- linux/arm/v7 -- ARM 32-bit (Raspberry Pi 3+)
- linux/ppc64le -- 64-bit PowerPC Little Endian
- linux/s390x -- 64-bit IBM System z
Both images are built on Alpine Linux: the default through the official Caddy image, slim through caddy-base. Alpine uses musl libc instead of glibc, which may cause compatibility issues with some software. Additional tools (git, bash, etc.) are not included by default.
The linux/arm/v7 build supports Raspberry Pi 3 and later. No special configuration is needed beyond having Docker installed on a compatible OS (such as Raspberry Pi OS).
If certificate requests fail with an authentication or IP error from Namecheap:
- Check that the IP Caddy sends as
client_ipis on your API whitelist. Behind NAT or a changing IP, the public IP may differ from what you expect. - Check that API access is still enabled on your account.
Namecheap recommends testing against its sandbox first. Use a sandbox account and point the module at the sandbox endpoint:
api_endpoint https://api.sandbox.namecheap.com/xml.response
To confirm the Namecheap module is loaded:
docker run --rm ghcr.io/caddybuilds/caddy-namecheap:latest caddy list-modules | grep dns.providers.namecheapThe build pipeline is fully automated via GitHub Actions and shared with the other CaddyBuilds images through caddy-base. This repo holds only what is specific to this image: the Dockerfile (module list), caddy-image.json (title, description, verified module) and two thin workflows that call the shared ones.
-
Daily release check -- A scheduled workflow queries the GitHub API for new Caddy releases and verifies the official Docker image is available with all required platforms before triggering a build.
-
Module update detection -- The pipeline reads the module list from the
Dockerfileand tracks each module's latest commit SHA inmodule-versions.json. If any module has new commits, a rebuild is triggered even without a new Caddy release. -
Base image tracking -- Docker Official Images republish existing Caddy versions for base OS and Go toolchain fixes, and caddy-base is rebuilt when Alpine is republished. The check compares each base image with when ours was built, and rebuilds if the base is newer.
-
Multi-platform build -- The shared workflow builds the default and slim images for all supported architectures. Images are pushed to GitHub Container Registry (primary) and optionally Docker Hub.
-
Fork-friendly -- Image names are derived from the
GITHUB_REPOSITORYenvironment variable, so forks produce correctly named images without any configuration changes. -
Failure notifications -- If a build fails, a GitHub issue is automatically created for visibility.
- GitHub account
- Docker Hub account (optional, for pushing to Docker Hub)
- GitHub Secrets configured:
GITHUB_TOKEN(automatically available in GitHub Actions)DOCKERHUB_USERNAME(optional)DOCKERHUB_TOKEN(optional)DOCKERHUB_REPOSITORY_NAME(optional, to customize the Docker Hub repository name)
-
Fork this repository to your GitHub account.
-
Set up GitHub Secrets (optional, for Docker Hub):
- Navigate to
Settings>Secrets and variables>Actions. - Add
DOCKERHUB_USERNAME,DOCKERHUB_TOKEN, and optionallyDOCKERHUB_REPOSITORY_NAME.
- Navigate to
-
Enable GitHub Actions:
- Go to the
Actionstab. If prompted, click "I understand my workflows, go ahead and enable them".
- Go to the
-
Customize the modules (optional):
- Add or change
--withlines in theDockerfile; the daily check follows the list from there. Adjust the title and description incaddy-image.jsonif you like.
- Add or change
-
Trigger a build (optional):
- In the
Actionstab, selectBuild and Push Docker Imageand clickRun workflow. The optional note is recorded in the release notes.
- In the
-
Pull your image:
docker pull ghcr.io/YOUR_GITHUB_USERNAME/YOUR_REPOSITORY_NAME:latest
Use the image in your docker-compose setup as shown in the Quick Start, replacing the image name with your own.
Feel free to open issues or submit pull requests if you have any improvements or bug fixes.
This project is licensed under the MIT License. See the LICENSE file for details.