Learning Caddy - Caddyfile Fundamentals
Episode 4 of 31

Learning Caddy - Caddyfile Fundamentals

This episode dissects the Caddyfile syntax from scratch: basic structure, comments, indentation, and environment variables. You'll also learn site block variations and essential directives like root, file_server, respond, reverse_proxy, redir, and encode.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

The Caddyfile is Caddy's main configuration file — and possibly the biggest reason so many developers fall in love with Caddy. Its human-friendly format makes tasks that are complicated on other web servers extremely concise. Episode 4 is the foundation: syntax, site blocks, and essential directives.

You'll learn to read and write a Caddyfile with confidence. From file structure, how to write comments, correct indentation, to using environment variables so your configuration doesn't contain sensitive data in plain text.

By the end of this episode, you'll have a set of ready-to-use Caddyfile blocks: a static site, simple responses, reverse proxy, and multiple sites in a single file. This is essential preparation before moving to advanced material.

Caddyfile Basic Syntax

Structure and Comments

The Caddyfile is made up of global options at the top, followed by site blocks. Comments are written with # and ignored by the parser:

Caddyfile with comments
# Global options
email admin@example.com
 
# Site block
example.com {
    root * /var/www/example
    file_server
}

Indentation uses spaces or tabs consistently. Caddy tolerates both as long as they're consistent within a block. Empty lines are fine and actually make the file easier to read.

Environment Variables

The Caddyfile can read environment variables with the {$NAME} syntax — the right way to store secrets and values that differ between environments:

Using environment variables
{$SITE_DOMAIN} {
    reverse_proxy localhost:{$APP_PORT}
}

Replace the {$SITE_DOMAIN} placeholder with the environment value when running Caddy:

Run Caddy with env vars
SITE_DOMAIN=app.example.com APP_PORT=8080 caddy run --config Caddyfile

Site Blocks: Variations and Rules

One File, Many Sites

A single Caddyfile can contain many site blocks — one per address:

Multiple site blocks
a.example.com {
    respond "Site A"
}
 
b.example.com {
    respond "Site B"
}
 
localhost:8080 {
    respond "Local"
}

If several addresses share the same configuration, list the addresses separated by commas:

One block for many addresses
example.com, www.example.com {
    root * /var/www
    file_server
}

Wildcards and Ports

A site address can be a wildcard subdomain. For local development, specify the port explicitly:

Localhost with a port
*.example.com {
    respond "Any subdomain"
}
 
localhost:3000 {
    reverse_proxy 127.0.0.1:8080
}

Note: addresses that are localhost or IP addresses won't trigger automatic HTTPS; only public domain names will get certificates.

Essential Directives

respond, root, and file_server

respond returns a static response. To serve files, set root then enable file_server:

Respond and static files
localhost {
    respond "Welcome to Caddy!"
    respond /health 200 "OK"
}
 
localhost {
    root * /var/www/mysite
    file_server
}

root * /var/www/mysite sets the document directory for all paths (marked by the asterisk), and file_server serves files from that directory. File serving details are covered in episode 5.

reverse_proxy, redir, and encode

A reverse proxy forwards requests to another application; a redirect moves a request; encode compresses responses:

Proxy, redirect, and compression
api.example.com {
    reverse_proxy localhost:8080
}
 
old.example.com {
    redir https://new.example.com{uri} permanent
}
 
example.com {
    encode zstd gzip
    root * /var/www
    file_server
}

redir ... with the permanent status produces HTTP 301 — important for SEO when moving domains. encode zstd gzip compresses responses according to browser capabilities. Details for each are in episodes 6, 13, and 21.

Global Options

email, admin, and trusted proxies

Global options are written before the site block, without indentation:

Global options
{
    email admin@example.com
    admin 127.0.0.1:2019
    servers {
        trusted_proxies static 10.0.0.0/8
    }
}
 
example.com {
    root * /var/www
    file_server
}
  • email is used for ACME notifications (episode 7).
  • admin sets the admin API address, default localhost:2019.
  • servers holds global HTTP server settings, including trusted proxies (episode 19).

The global block opens with an empty pair of curly braces on the first line. These options affect every site in a single Caddy process.

Conclusion

Episode 4 equipped you with the Caddyfile foundation: basic syntax with comments and indentation, environment variables for dynamic values, site block variations from a single site to wildcards, essential directives like respond, root, file_server, reverse_proxy, redir, and encode, plus global options.

Key takeaways:

  • Comments are written with #, and indentation must be consistent.
  • Environment variables use {$NAME} for dynamic values.
  • A single Caddyfile can hold many site blocks.
  • file_server needs root; respond is for static responses.
  • redir ... permanent produces HTTP 301.
  • Localhost and IP addresses don't trigger automatic HTTPS.

In the next episode, episode 5, we'll dive into static file serving — the file_server and root directives in depth, directory browsing, index files, try_files for SPA routing, plus precompressed files and ETags. You'll be able to serve production-ready static sites.

Learning Caddy - Caddyfile Fundamentals | Learning Caddy