Concepts
The Raddexfile is the heart of raddex: a plain-text configuration in a
Caddyfile-style syntax, validated with raddex check and served with
raddex run. This page gives you the mental model. The directive
reference has the complete syntax, and Sites, ports &
HTTPS covers how a request is matched to a site.
A configuration at a glance
Section titled “A configuration at a glance”A Raddexfile is an optional global block followed by one or more site blocks:
{ acme_email ops@example.com}
api.example.com { reverse_proxy 127.0.0.1:8080}
static.example.com { root /var/www/html file_server}- The global block — a bare
{ ... }at the top of the file — carries site-wide settings such as your ACME email. - Each site block maps a host (optionally with a port) to behavior.
Two kinds of directive
Section titled “Two kinds of directive”Once a request is matched to a site, raddex executes the site’s lines strictly in write order. Every line is one of three kinds:
- Terminal directives decide who serves the request:
reverse_proxy,file_server,redir,respond,error. The first terminal that matches ends the site — later lines never run. A terminal may carry an inline matcher; one that does not match is a no-op and execution continues. - Modifier directives describe how to serve, regardless of position:
header_up,header_down,encode,rewrite. They apply to whichever terminal serves the block, even if written after it. - Guard directives decide who may be served:
rate_limit,basic_auth,forward_auth. They act like modifiers — applying to whichever terminal serves the block — and reject the request (429,401) when the guard fails.
Caddy users: Caddy reorders directives behind the scenes; raddex does not. You control the order, and the first match wins.
Matchers select which requests a directive serves
Section titled “Matchers select which requests a directive serves”A matcher is a set of terms — path, host, method,
header, query, remote_ip, protocol — all of which must match. Matchers
attach to handle blocks and, inline, to terminals:
handle path /status method GET { respond 200 ok}Terms are space-separated and ANDed; there are no parentheses or &&.
handle /static/* is shorthand for handle path /static/*.
handle groups a matcher with a terminal
Section titled “handle groups a matcher with a terminal”handle <matcher> { ... } is a scoped block: if the matcher matches, its lines
run and matching stops; otherwise execution continues past it. Think of it as
“for these requests, use this terminal.” handle_path is the same, except it
strips the matched path prefix before the block’s terminal runs.
A request, traced
Section titled “A request, traced”Put the model together on a concrete site:
api.example.com { handle /static/* { root /var/www/html file_server encode zstd gzip }
reverse_proxy 127.0.0.1:8080 rate_limit remote_ip 100r/s header_up X-Real-IP {remote_host}}Request: GET /static/app.js
handle /static/*matches the path, so its lines run in order.rootsets the directory;file_serverserves/var/www/html/static/app.jsand ends site execution.encode zstd gzip— a modifier inside the block — compresses the response when the client accepts it.- The site-level modifiers (
rate_limit,header_up) also apply to this terminal, because site-level modifiers apply to whichever terminal serves the block.rate_limitchecks the client’s bucket;header_uptargets the upstream request, so it has no effect on a local file.
Request: GET /api/users
handle /static/*does not match, so execution continues.reverse_proxyhas no matcher, so it always matches and serves the request — proxied to127.0.0.1:8080, ending the site.rate_limit remote_ip 100r/sguards this terminal too (it is a site-level modifier). If the bucket is empty you get429 Too Many Requests.header_up X-Real-IP {remote_host}adds the client’s IP to the upstream request headers.
Write order matters only between terminals. Modifiers apply wherever they are written, within their scope: site-level modifiers apply to every terminal in the site; modifiers inside a
handleblock apply only to that block’s terminal.
The full language
Section titled “The full language”- Directive reference — every directive, syntax, and example
- Routing & matchers — matchers,
rewrite,handle_path,respond,error - Sites, ports & HTTPS — matching, catch-alls, certificates
- Trusted proxies — where the “real” client IP comes from