Configuration: static file serving

This page documents directives that configure static file serving, directory listings, compression, caching behavior, and custom error pages for requests resolved to the filesystem (via root).

Info

Static file serving is handled by the http-static module. For related features, see Routing and URL processing, HTTP cache, HTTP response control, URL rewriting, and HTTP compression.

Directives

Index and directory listings

  • index <filename: string>...
    • This directive specifies one or more filenames to try when a request path resolves to a directory. Files are tried in order; the first existing file replaces the directory path in the file context. Only applies when the resolved path is a directory and no path_info is present. Default: index index.html index.htm index.xhtml
  • directory_listing [bool: boolean] (http-static)
    • This directive specifies whether auto-generated HTML directory listings are enabled when a request path resolves to a directory and no index file is found. Default: directory_listing false

Configuration example:

example.com {
    root /srv/www/example
    index index.html index.htm
    directory_listing
}
Note
  • Only generates a listing if no index file was found for the directory.
  • Dotfiles (names starting with .) are excluded from the listing, except .maindesc which is read as a description.
  • A .maindesc file in the directory, if present, is displayed as a <pre> block below the file table.

Caching headers

  • etag [bool: boolean] (http-static)
    • This directive specifies whether ETag generation for static file responses is enabled. ETags are weak ETags (W/"...") generated from an xxHash3 hash of the file path, size, and modification time. Default: etag true
  • file_cache_control <value: string> (http-static)
    • This directive specifies the Cache-Control response header for all static file responses. The value is passed through as-is. Default: not set

Configuration example:

example.com {
    root /srv/www/example
    etag
    file_cache_control "public, max-age=3600"
}
Note
  • When compression is used, a suffix is appended to the ETag (e.g. W/"abc123-br" for Brotli).
  • If-None-Match requests that match the current ETag return 304 Not Modified.
  • Pre-compressed sidecar files receive their own ETag based on the sidecar file’s own metadata.

MIME types

  • mime_type <extension: string> <mime-type: string> (http-static)
    • This directive maps a file extension (with or without leading dot) to a MIME type. Custom MIME type mappings override the built-in database for matching extensions. Multiple mime_type directives can be used to map different extensions. Default: built-in MIME database

Configuration example:

example.com {
    root /srv/www/example
    mime_type ".wasm" "application/wasm"
    mime_type ".webmanifest" "application/manifest+json"
}
Note
  • If the extension is not found in custom mappings, the built-in database is used as a fallback.
  • If neither custom nor built-in mappings match, the response is sent with no Content-Type header.

Error pages

  • error_page <status-code: integer>... <file-path: string>
    • This directive specifies one or more HTTP status codes followed by a file path to serve as the error response body. The last argument is always the file path; all preceding arguments are status codes. Default: built-in error pages

Configuration example:

example.com {
    root /srv/www/example
    error_page 404 /custom/404.html
    error_page 500 502 503 504 /custom/50x.html
}
Note
  • Only applies when an error response is being generated and no custom response has already been set.
  • The file path is absolute or relative to the current working directory.
  • If the specified error page file does not exist, the directive is skipped and the built-in error page is used.
  • Multiple status codes can be mapped to the same error page in a single directive.

Observability

Metrics

Static file serving

MetricTypeAttributesDescription
ferron.static.files_servedCounterferron.compression ("identity", "gzip", "br", "deflate", "zstd"), ferron.cache_hit ("true" or "false")Number of static files served
ferron.static.bytes_sentHistogramferron.compression ("identity", "gzip", "br", "deflate", "zstd"), ferron.cache_hit ("true" or "false")Bytes sent for static file responses. Buckets: 1KB, 10KB, 100KB, 1MB, 10MB, 100MB
ferron.static.responsesCounterhttp.response.status.code (HTTP response status code), ferron.static.outcome (static file serving outcome)Static-file responses across normal, conditional, range, and error paths

Logs

  • WARN: logged when an error_page file cannot be opened. The directive is skipped and the built-in error page is used instead.

Best practices

The following best-practice check is reported by ferron doctor for directives on this page.

  • directory_listing enabled — Auto-generated directory indexes expose file structure. Enable only for intentionally public file listings.