Mastering Caddy 2: Installation, Configuration, and Advanced Features

This guide introduces Caddy 2, an enterprise‑grade Go‑based web server, outlines its key features and advantages over Nginx, provides step‑by‑step installation commands for various Linux distributions and macOS, and demonstrates comprehensive Caddyfile configurations including site blocks, global options, logging, TLS, reverse proxy, and modular snippets.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Mastering Caddy 2: Installation, Configuration, and Advanced Features

Overview

Caddy 2 is an open‑source, enterprise‑grade web server written in Go. It provides built‑in HTTP/2, automatic HTTPS via ACME, optional HTTP/3 (QUIC), IPv6, WebSocket handling, and a modular plugin system that can be extended with Go code.

Caddy features diagram
Caddy features diagram

Key capabilities

Automatic HTTP/2 without configuration.

Zero‑configuration HTTPS with automatic certificate issuance and renewal (ACME HTTP/DNS challenges, OCSP stapling).

Multi‑core utilization and IPv6 support.

Native WebSocket proxying.

Built‑in Markdown‑to‑HTML conversion.

Simple log format definition and log rotation.

Dependency‑free binary deployment (single static executable).

Reverse‑proxy with active/passive health checks, load balancing, circuit breaking, and caching.

Cross‑platform binaries for Windows, Linux, and macOS.

Installation

Official download page: https://caddyserver.com/download

Fedora / RHEL / CentOS 8

$ dnf install 'dnf-command(copr)'
$ dnf copr enable @caddy/caddy
$ dnf install caddy

macOS (Homebrew)

$ brew install caddy

RHEL / CentOS 7

$ yum install yum-plugin-copr
$ yum copr enable @caddy/caddy
$ yum install caddy

Debian / Ubuntu / Raspbian

$ sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
$ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/caddy-stable.asc
$ curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
$ sudo apt update
$ sudo apt install caddy

Common systemd commands

$ systemctl start caddy      # start the service
$ systemctl reload caddy     # reload configuration without downtime
$ systemctl status caddy    # view service status

Configuration basics

Caddy’s core configuration format is JSON, but most users write a Caddyfile – a concise, line‑oriented syntax that the server compiles to JSON. The Caddyfile supports:

Site blocks that define a domain or address.

Global options wrapped in { ... }.

Reusable snippets (named blocks in parentheses) that can be imported elsewhere.

Wildcard imports and glob patterns for modular configuration files.

Site block example

(site_option) {
  encode zstd gzip
  file_server
  handle_errors {
    rewrite * /{http.error.status_code}.html
    file_server
  }
  import acme_https
  import log_file
  root * /www/{host}
}

Global options

{
  debug               # enable debug output
  default_sni domain.com
  admin off           # disable the admin endpoint
}

Error page handling

www.example.com {
  root * /web/example.com/
  file_server
  handle_errors {
    rewrite * /{http.error.status_code}.html
    file_server
  }
}

Logging snippet

(log_file) {
  log {
    format logfmt
    output file /var/log/caddy/{host}.access.log {
      roll_keep 7
    }
  }
}

Headers and cache control

www.example.com {
  header Access-Control-Allow-Origin *
  header Cache-Control max-age=3600
  header /css/* Cache-Control max-age=604800
}
(cachecontrol) {
  header /css/* Cache-Control max-age=3600
  header /img/* Cache-Control max-age=3600
  header /js/*  Cache-Control max-age=3600
}

Reverse proxy

https://www.example.com {
  gzip
  tls [email protected]
  reverse_proxy / https://backend.example.com
}

Quick static site command

$ caddy file-server --website ./index --listen :8088 --domain www.example.com

Parameters:

file-server      # starts a production‑ready static file server
--website DIR   # directory containing index.html and other assets
--listen :PORT  # listening address (e.g., :8088)
--domain HOST   # domain name to bind the site to

Snippet definition and import

# TLS snippet
(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
}
# Use the snippet elsewhere
import TLS

Modular imports

# Import all Caddyfiles under /etc/caddy
import /etc/caddy/*.caddy

Full modular configuration example

The example below combines logging, TLS, HSTS, and an ACME DNS challenge (Gandi) into reusable snippets, enables experimental HTTP/3, and applies the common configuration to two sites.

(LOG) {
  log {
    format "[{ts}] {request>remote_addr} {request>proto} {request>method} <- {status} -> {request>host} {request>uri} {request>headers>User-Agent>[0]" {
      time_format "iso8601"
    }
    output file "{args.0}" {
      roll_size 100mb
      roll_keep 3
      roll_keep_for 7d
    }
  }
}

(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
}

(HSTS) {
  header / Strict-Transport-Security "max-age=63072000"
}

(ACME_GANDI) {
  dns gandi {$GANDI_API_TOKEN}
}

(COMMON_CONFIG) {
  encode zstd gzip
  tls {
    import TLS
    import ACME_GANDI
  }
  import HSTS
}

# Enable experimental HTTP/3 on port 443
{
  servers :443 {
    protocol {
      experimental_http3
    }
  }
}

import /etc/caddy/*.caddy

www.example.com {
  redir https://example.com{uri}
  import LOG "/data/logs/example.com.log"
  import COMMON_CONFIG
}

example.com {
  route /* {
    reverse_proxy backend:80
  }
  import LOG "/data/logs/example.com.log"
  import COMMON_CONFIG
}

Running and reloading

$ systemctl start caddy      # start the server
$ systemctl reload caddy     # apply configuration changes without stopping
$ systemctl status caddy    # check service health

These commands behave similarly to the traditional nginx service management commands.

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.

ConfigurationLinuxreverse proxyWeb serverHTTPSCaddy
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.