caddyserver/caddy
File server
http.handlers.file_server serves static files from disk. Lives in modules/caddyhttp/fileserver/ (~30 KB across staticfiles.go).
Purpose
Take a request URI, map it to a path on disk under a configured root, and respond with the file contents — with proper Content-Type, conditional GETs, range requests, precompressed-asset support, and an optional HTML directory listing.
Directory layout
| Path | Role |
|---|---|
modules/caddyhttp/fileserver/staticfiles.go |
The handler itself (~30 KB) |
modules/caddyhttp/fileserver/browse.go |
Directory-listing rendering |
modules/caddyhttp/fileserver/browse.html |
Embedded HTML template (~58 KB; includes CSS and JS) |
modules/caddyhttp/fileserver/browsetplcontext.go |
Template context for browse.html |
modules/caddyhttp/fileserver/matcher.go |
http.matchers.file — exists/doesn't-exist match |
modules/caddyhttp/fileserver/caddyfile.go |
file_server directive parser |
modules/caddyhttp/fileserver/command.go |
caddy file-server standalone subcommand |
modules/caddyhttp/fileserver/testdata/ |
Fixtures used by the tests |
Key abstractions
| Type | Where | Description |
|---|---|---|
FileServer |
staticfiles.go |
The handler module |
Browse |
staticfiles.go |
Directory-listing config (sort key, sort direction, template path) |
MatchFile |
matcher.go |
The file matcher — checks file existence on disk |
How it works
graph TD
Req[Request: /path/to/file.html] --> Handler[FileServer.ServeHTTP]
Handler -->|join with root| Resolve[full filesystem path]
Resolve --> Stat
Stat -->|not found| Notfound[404 / pass-through]
Stat -->|directory| Browse[browse.html / index.html]
Stat -->|file| Cond[conditional GET checks]
Cond -->|If-None-Match etc.| NotModified[304]
Cond -->|range| Range[partial 206]
Cond -->|full| Send[send body]
Send --> Precompressed[try .gz/.br/.zst sibling]
Precompressed --> RespPath resolution
- Take the URI path, strip any leading slash, join with
root. - Run it through
filepath.Cleanto defeat../traversal. - Apply
index_names(defaults:index.html,index.htm) when the resolved path is a directory. - Apply
try_filesif configured (rewrites the URI to the first match — used for SPA fallbacks).
The filesystem is whatever caddy.Filesystems resolves; by default the OS filesystem, but a virtual filesystem (e.g. embedded files) can replace it via caddy.filesystems.*.
Range and conditional GETs
staticfiles.go uses http.ServeContent from the standard library, which handles If-Modified-Since, If-None-Match, Range, and If-Range correctly out of the box.
Precompressed assets
If the client signals Accept-Encoding: br and a sibling file index.html.br exists, the server serves the brotli file with an appropriate Content-Encoding header. This is registered via http.precompressed.* modules:
http.precompressed.gziphttp.precompressed.brhttp.precompressed.zstd
Each is a tiny module that knows the file extension and the encoding name. staticfiles.go checks for them in the order configured.
Directory listing
If browse is enabled and the resolved path is a directory with no index file:
browsetplcontext.gobuilds a context (entries, sort, breadcrumb).browse.html(embedded) renders. It is a single file that includes inline CSS and a small JS for sorting, search, and per-page state.
file matcher
matcher.go registers http.matchers.file. The matcher checks whether one of the listed files exists; with try_policy: first_exist, it returns the first hit and stores it in the replacer for downstream handlers (the canonical "Try files in this order" pattern, often used with php_fastcgi).
Standalone subcommand
command.go registers caddy file-server, which lets you run a quick file server from the CLI without writing a Caddyfile:
caddy file-server --listen :8080 --root ./public --browseIntegration points
- HTTP app: standard handler.
- Caddyfile:
file_serverdirective (parsed bycaddyfile.go). try_files: uses thefilematcher under the hood; it's a Caddyfile shorthand for setting up the matcher and a rewrite.
Entry points for modification
- Change directory listing UX? Edit
browse.htmlandbrowsetplcontext.go. - Add a precompressed encoding? Add a small module registering
http.precompressed.<name>. - Tweak path-resolution rules?
staticfiles.go: ServeHTTP.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.