Linux VPS

Caddyfile examples: reverse proxy, PHP-FPM, redirects and headers

Practical Caddyfile recipes beyond the basics: multiple sites, reverse proxy with load balancing and health checks, PHP sites with php_fastcgi, redirects, headers, compression and logging.

IntermediateLinux VPS3 min read

Caddy's configuration file, the Caddyfile, is famously short: a site block with a domain gets automatic HTTPS with no extra lines. Once Caddy is installed, most real work is writing the right directives. This guide collects tested Caddyfile examples for the setups people actually run.

Before you start

  • Caddy installed as a service: install Caddy with automatic HTTPS.
  • Domains pointing to the server and ports 80 and 443 (TCP, plus UDP 443 for HTTP/3) open.
  • The file lives at /etc/caddy/Caddyfile. Apply changes with sudo systemctl reload caddy.

Several sites in one Caddyfile

example.com, www.example.com {
    root * /var/www/example.com
    file_server
    encode zstd gzip
}

blog.example.com {
    root * /var/www/blog
    file_server
}

Each site gets its own certificate automatically. encode zstd gzip turns on compression.

Redirect www to the bare domain

www.example.com {
    redir https://example.com{uri} permanent
}

example.com {
    root * /var/www/example.com
    file_server
}

HTTP to HTTPS redirects happen automatically; you never write them.

PHP sites with php_fastcgi

shop.example.com {
    root * /var/www/shop/public
    php_fastcgi unix//run/php/php8.3-fpm.sock
    file_server
    encode gzip
}

php_fastcgi is a shortcut that does what several Nginx blocks do: it passes .php files to PHP-FPM, sets the FastCGI parameters, and tries {path}, {path}/index.php and finally index.php, so WordPress and Laravel pretty URLs work out of the box. Make sure PHP-FPM's socket is readable by the caddy user (set listen.owner = caddy in the pool, or add caddy to the socket group).

Reverse proxy to an app

app.example.com {
    reverse_proxy 127.0.0.1:3000
}

Caddy sets X-Forwarded-For, X-Forwarded-Proto and X-Forwarded-Host for you, and proxies WebSockets without extra config.

Load balancing with health checks

api.example.com {
    reverse_proxy 10.0.0.11:8080 10.0.0.12:8080 {
        lb_policy least_conn
        health_uri /health
        health_interval 10s
        fail_duration 30s
    }
}

Proxy only part of a site

example.com {
    handle_path /api/* {
        reverse_proxy 127.0.0.1:4000
    }
    handle {
        root * /var/www/example.com
        file_server
    }
}

handle_path strips /api before proxying; use handle to keep the prefix. Blocks are mutually exclusive, like Nginx locations.

Security headers

(security) {
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options nosniff
        X-Frame-Options SAMEORIGIN
        Referrer-Policy strict-origin-when-cross-origin
        -Server
    }
}

example.com {
    import security
    root * /var/www/example.com
    file_server
}

The parenthesised block is a reusable snippet; -Server removes the Server header.

Protect a folder with a password

  1. Hash a password: caddy hash-password.
  2. Add:
    basic_auth /admin/* {
        admin $2a$14$REPLACE_WITH_HASH
    }

(Older Caddy versions spell it basicauth.)

Access logs

example.com {
    log {
        output file /var/log/caddy/example.log {
            roll_size 50mb
            roll_keep 10
        }
        format json
    }
}

Caddy rotates the file itself.

Validate before reloading

caddy validate --config /etc/caddy/Caddyfile
caddy fmt --overwrite /etc/caddy/Caddyfile

Troubleshooting

  • Certificate not issued: DNS does not point here yet, or port 80/443 is blocked. Check journalctl -u caddy.
  • PHP downloads instead of running: php_fastcgi missing or socket path wrong.
  • 502 from reverse_proxy: the backend is not listening on that address.

FAQ: Caddyfile

Can Caddy read Nginx or Apache configs?

No. Rules must be rewritten in Caddyfile syntax, usually far shorter.

Does Caddy support .htaccess?

No. Put redirects and rules in the Caddyfile.

Is Caddy fast enough for production?

Yes, for most sites. Very high-traffic PHP sites may still prefer LiteSpeed with LSCache or Nginx with FastCGI cache.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.