Skip to content

atnplex/caddy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

93 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Caddy Logo

atnplex/caddy

A hardened, multi-arch custom Caddy image for homelab and VPS reverse proxy deployments.

Docker Hub GHCR Architectures Build

Last Run Next Run


Overview

This repository builds and publishes a custom hardened multi-arch Caddy image compiled with xcaddy. Designed for Docker-based homelab and VPS deployments using label-driven reverse proxying, Cloudflare DNS automation, and a fully automated weekly rebuild pipeline.

Published to:

  • GHCR: ghcr.io/atnplex/caddy
  • DockerHub: atnplex/caddy

Architectures: linux/amd64 · linux/arm64


Quick Start

Use latest for automatic updates via Watchtower or Diun. Use a digest-pinned tag for fully reproducible deployments — see Releases.

Docker Run

docker run -d \
    --name caddy \
    --restart unless-stopped \
    -v /var/run/docker.sock:/var/run/docker.sock \
    --group-add $(stat -c '%g' /var/run/docker.sock) \
    -p 80:80 \
    -p 443:443 \
    ghcr.io/atnplex/caddy:latest

Docker Compose

services:
    caddy:
        image: ghcr.io/atnplex/caddy:latest
        container_name: caddy
        restart: unless-stopped
        ports:
            - "80:80"
            - "443:443"
            - "443:443/udp"
        environment:
            - TZ=America/Los_Angeles
        env_file:
            - /etc/caddy/.env
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock:ro
            - caddy_data:/data
            - caddy_config:/config
        group_add:
            - "${DOCKER_GID:-999}"
        networks:
            - atn_bridge

volumes:
    caddy_data:
    caddy_config:

networks:
    atn_bridge:
        external: true

Set DOCKER_GID to your host's docker group GID: stat -c '%g' /var/run/docker.sock


Included Modules

Module Purpose
caddy-docker-proxy Builds Caddy config dynamically from Docker container labels
caddy-dns/cloudflare Cloudflare DNS-01 ACME certificate automation
caddy-cloudflare-ip Restores real client IPs from Cloudflare CDN headers
cache-handler HTTP response caching
transform-encoder Custom log format transformation
caddy-security Authentication and authorization portal

Example Labels

labels:
    caddy: myapp.example.com
    caddy.reverse_proxy: "{{upstreams 8080}}"
    caddy.tls.dns: cloudflare {$CLOUDFLARE_API_TOKEN}
    caddy.tls.resolvers: 1.1.1.1

Tag Strategy

Tag Registry Description
latest GHCR · DockerHub Always points to the most recent successful build
2 · 2.11 GHCR only Floating semver major / minor tags — updated on every build
2.11.2 GHCR · DockerHub Patch-level version pin
2.11.2-2026.03.28 GHCR · DockerHub Version + build date for fully reproducible deployments
sha-abc1234 GHCR · DockerHub Git SHA of the Dockerfile at build time

Note: Floating major/minor tags (2, 2.11) are only pushed to GHCR. DockerHub receives only immutable tags (patch version, date-stamped, and SHA) to prevent silent overwrites for users who may have pinned these tags in compose files expecting stability.

For production deployments requiring full immutability, pin to a digest from the Releases page.


OCI Image Labels

Every image is stamped with the following OCI-compliant labels at build time:

Label Description
org.opencontainers.image.version Caddy version (e.g. 2.11.2)
org.opencontainers.image.created Build date in YYYY.MM.DD format
org.opencontainers.image.revision Short Git SHA of the Dockerfile commit
org.opencontainers.image.source Link to this repository
org.atnplex.build.fingerprint Pipe-delimited string of all resolved component versions — used by the build pipeline to detect changes and skip unnecessary rebuilds

Inspect labels on any pulled image:

docker inspect ghcr.io/atnplex/caddy:latest \
    --format '{{ json .Config.Labels }}' | jq

Automatic Updates on Your Servers

This image is designed for a pull-based GitOps pattern.

Watchtower — automatic pull and restart:

services:
    watchtower:
        image: containrrr/watchtower
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
        command: --interval 86400 --cleanup

Diun — notification only, no auto-restart: Monitors ghcr.io/atnplex/caddy:latest and notifies when a new digest is published.


Build Pipeline

Builds run automatically every Monday at 02:00 PST or on manual trigger.

The workflow:

  1. Resolves latest stable versions of Caddy and all 6 modules from upstream
  2. Compares resolved versions against the fingerprint on the currently published image
  3. Skips if nothing meaningful changed — idempotent, no redundant rebuilds
  4. Builds multi-arch image (amd64 + arm64)
  5. Runs smoke tests and verifies all 6 modules are present
  6. Scans with Docker Scout — advisory only, does not block the build; CVE summary appears in the workflow step summary
  7. Pushes to GHCR and DockerHub simultaneously with SBOM and provenance attestation
  8. Signs with cosign keyless OIDC
  9. Creates a GitHub Release with full component versions and image digests

Repository Setup (First-Time)

Complete these one-time setup steps before the workflow can run:

1. GitHub Secrets

In Settings → Secrets and variables → Actions, add one secret:

  • BWS_ACCESS_TOKEN — your Bitwarden Secrets Manager access token

DockerHub credentials are fetched from Bitwarden at runtime. GITHUB_TOKEN is provided automatically by GitHub Actions. Cosign uses keyless OIDC signing — no key secrets needed.

2. Renovate GitHub App

Install the Renovate GitHub App on this repository. Renovate automatically opens pull requests when new stable versions of base images or Go modules are detected. Patch and minor PRs are configured to automerge. The next scheduled workflow run detects the updated Dockerfile fingerprint and triggers a rebuild automatically.

3. DockerHub Org Access

Confirm your personal DockerHub PAT stored in Bitwarden has write access to the atnplex org namespace. The workflow pushes to atnplex/caddy using your personal account credentials.

4. Branch Protection (recommended)

In Settings → Branches, protect the main branch and allow the Renovate bot to bypass protection rules for automerge to work.

5. Repository About Section (GitHub UI — one-time)

Set the repository About section via Settings → General → Description (or the gear icon on the repo homepage):

  • Description: Hardened multi-arch custom Caddy image with docker-proxy, Cloudflare DNS/IP, cache-handler, transform-encoder, and caddy-security modules
  • Website: https://hub.docker.com/r/atnplex/caddy
  • Topics: caddy, docker, reverse-proxy, cloudflare, homelab, xcaddy, github-actions

Releases

Each successful build creates a GitHub Release containing full component version details, image digests for both architectures, digest-pinned pull commands, and a Docker Scout security summary.

About

Hardened multi-arch custom Caddy image with docker-proxy, Cloudflare DNS/IP, cache-handler, transform-encoder, and caddy-security modules

Topics

Resources

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors