Caddy Cheatsheat

Server options

Serve requests only $CADDYHOST environment variable


Bind to IP address $CADDYBIND


Define the web server root

root /srv/caddy/{$CADDYROOT}

Log requests to stdout

log / stdout "{>X-Forwarded-For} {remote} - {user} [{when}] \"{method} {uri} {proto}\" {status} {size} \"{>Referer}\" \"{>User-Agent}\""

TLS options

Set up Lets Encrypt with email $CADDYEMAIL


Configure TLS with local certificate/key

tls cert.pem key.pem {
    protocols tls1.2 tls1.3

Configure TLS with client authentication

tls cert.pem key.pem {
    clients require ca.crt

Redirect HTTP to HTTPS

redir {
if {scheme} is http
/ https://{host}{uri}

Access & Authentication

HTTP Basic auth

basicauth /private {$BASICUSER} {$BASICPASS}

Allow directory browsing under /private

browse /private

Expose Caddy runtime stats at /private/stats

expvar /private/stats

Redirect HTTP to HTTPS

redir {
    if {scheme} is http
    / https://{host}{uri}

Github Oauth2 Login

redir 302 {
    if {path} is /
    / /login
login {
    github client_id={$GITHUB_CLIENT_ID},client_secret={$GITHUB_CLIENT_SECRET}
    redirect_check_referer false
    success_url /home.html
    logout_url /logout
jwt {
    path /
    redirect https://{host}/login
    allow sub {$GITHUB_ALLOWED_USERS}


Apply templating only to /private/templates

# See
templates /private/templates

Dynamically render /public/*.md as markdown (css optional)

markdown /public {
ext .md
css markdown.css

HTTP options

Add file extensions to unqualified requests - try until matched

ext .html .txt 

Add/Modify the response headers

header / X-Frame-Options "DENY"

Enable Compression

gzip {
level 4
not /proxy

Generate an error page

errors {
404 error/404.html
* error/catchall.html

Proxy Options

Simple reverse proxy

proxy /proxy

Reverse proxy with auth header

proxy /transmission http://localhost:9091 {
header_upstream Authorization "Basic dXNlcjpwYXNzd29yZAo="


Define a snippet

(snippet_name) {
import snippet_name