Configuration: CGI support
This page documents the cgi directive for configuring Ferron’s CGI (Common Gateway Interface) support. CGI enables dynamic content by spawning external interpreters for scripts matched by file extension or placed under a cgi-bin directory.
cgi
example.com {
cgi {
extension ".php"
interpreter ".php" php-cgi -c /etc/php/cgi.ini
environment "APP_ENV" "production"
}
}The cgi block can be written as a boolean flag to enable CGI with all defaults, or as a block with nested directives to customize behavior.
| Form | Description |
|---|---|
cgi | Enables CGI with all defaults. |
cgi true | Explicitly enables CGI. |
cgi false | Disables CGI for the current scope. |
cgi { ... } | Enables CGI and configures nested directives. |
extension
| Nested directive | Arguments | Description | Default |
|---|---|---|---|
extension | <string> | This directive registers an additional file extension that should be treated as a CGI script. Unlike cgi-bin directory matching, the file does not need to be executable. This directive can be specified multiple times. | — |
Configuration example:
example.com {
cgi {
extension ".php"
extension ".rb"
}
}Notes:
- Extensions are matched case-insensitively.
- Files with these extensions are treated as CGI scripts regardless of their location in the file tree.
- This is complementary to
cgi-bindirectory matching — files insidecgi-binare always treated as CGI scripts.
interpreter
| Nested directive | Arguments | Description | Default |
|---|---|---|---|
interpreter | <extension: string> <arg: string>... | This directive maps a file extension to a custom interpreter command. The first argument is the extension (with a leading dot, e.g. .php). Subsequent arguments form the interpreter command line. Pass false as the second argument to disable the interpreter for that extension. This directive can be specified multiple times. | built-in defaults |
Configuration example:
example.com {
cgi {
interpreter ".php" php-cgi -c /etc/php/cgi.ini
interpreter ".pl" perl
interpreter ".py" python3
interpreter ".php" false
}
}Notes:
- The file path is automatically appended as the final argument.
- When
falseis used as the second argument, the interpreter list is cleared, meaning the file must be directly executable (e.g., via a shebang line or native executable). - For Unix systems, files without a matching interpreter must have the executable permission bit set.
- On Unix systems, scripts with a shebang line (e.g.,
#!/usr/bin/env python3) are parsed and the interpreter is derived from the shebang. - On Windows,
.exefiles are executed directly,.bat/.cmdfiles usecmd /c, and scripts with shebangs are parsed similarly to Unix.
environment
| Nested directive | Arguments | Description | Default |
|---|---|---|---|
environment | <name: string> <value: string> | This directive sets a CGI environment variable passed to the interpreter process. Values are resolved with the same interpolation syntax as other directives. This directive can be specified multiple times. | — |
Configuration example:
example.com {
cgi {
environment "APP_ENV" "production"
environment "APP_SECRET" "{{env.APP_SECRET}}"
environment "RUBY_VERSION" "3.3"
}
}Notes:
- Environment variables take precedence over any existing variables with the same name.
- The
Proxyheader is automatically removed from the request to prevent the httpoxy vulnerability. - Ferron always sets
SERVER_SOFTWARE,SERVER_NAME,SERVER_PORT,REQUEST_URI,QUERY_STRING,PATH_INFO,SCRIPT_NAME,AUTH_TYPE,REMOTE_USER, andSERVER_ADMINautomatically.
Default interpreters
The following built-in interpreters are available when no custom interpreter directive matches:
| Extension | Default interpreter |
|---|---|
.pl | perl |
.py | python |
.sh | bash |
.ksh | ksh |
.csh | csh |
.rb | ruby |
.php | php-cgi |
.exe (Windows) | (direct execution) |
.bat (Windows) | cmd /c |
.vbs (Windows) | cscript |
Default index files
When CGI is enabled and no explicit index directive is configured, Ferron automatically injects default index file names. By default, the following files are checked in order: index.html, index.htm, index.xhtml.
If you register additional extensions via the extension directive, Ferron also prepends corresponding index files to the front of the list:
| Registered extension | Prepend to index list |
|---|---|
.cgi | index.cgi |
.php | index.php |
For example, with extension ".php" configured, the injection order becomes: index.php, index.html, index.htm, index.xhtml.
This injection only applies when no explicit index directive is set. If you configure your own index directive, Ferron will use that instead.
CGI script locations
A request is handled as a CGI script when:
- The resolved path is inside a
cgi-bindirectory (case-insensitive match on the first path component after the document root), or - The file extension matches one registered via the
extensiondirective.
When a matching file is found, Ferron checks for an interpreter using the following priority:
- Custom
interpreterdirective matching the file extension. - Built-in default interpreter for the extension.
- If the file is directly executable (has the executable bit on Unix, or is a native
.exeon Windows), it is run directly. - If the file has a shebang line, the interpreter is parsed from the shebang.
Environment variables
Ferron automatically sets the following CGI environment variables:
| Variable | Description |
|---|---|
SERVER_SOFTWARE | Always Ferron. |
SERVER_NAME | Server hostname. |
SERVER_ADDR | Local server address. |
SERVER_PORT | Server port. |
REQUEST_METHOD | HTTP method. |
REQUEST_URI | Original request URI. |
QUERY_STRING | Query string (empty string if none). |
PATH_INFO | Path info extracted from the request. |
SCRIPT_NAME | The script path relative to the document root. |
AUTH_TYPE | Authentication type from the Authorization header (e.g., Basic, Bearer). |
REMOTE_USER | Authenticated username, if available. |
SERVER_ADMIN | Server administrator email (from admin_email configuration). |
HTTPS | Set to on when the connection is encrypted. |
Additional variables set by environment directives override any automatically set variables with the same name.
Observability
Logs
WARN: logged when a CGI script exits with a non-zero status and produces output on stderr. The message includes the trimmed stderr content.
Examples
PHP with a custom PHP-CGI binary
example.com {
root /srv/www/example
cgi {
extension ".php"
interpreter ".php" php-cgi -c /etc/php/8.2/cgi/php.ini
}
}Multiple interpreters with environment variables
example.com {
root /srv/www/app
cgi {
extension ".rb"
interpreter ".rb" ruby
interpreter ".py" python3
environment "RUBY_VERSION" "3.3"
environment "PYTHONUNBUFFERED" "1"
}
}Disabling the default PHP interpreter
example.com {
root /srv/www/example
cgi {
interpreter ".php" false
}
}This allows PHP files to be handled via shebang lines or direct execution instead.
Using cgi-bin with additional extensions
example.com {
root /srv/www/example
cgi {
extension ".php"
environment "APP_ENV" "production"
}
# /srv/www/example/cgi-bin/handler.py is treated as CGI
# /srv/www/example/scripts/script.php is also treated as CGI
# (because of the ".php" extension directive)
}Notes and troubleshooting
- CGI scripts must be inside a
cgi-bindirectory or have an extension registered via theextensiondirective. - On Unix, scripts without a matching
interpreterdirective must have the executable permission bit set (chmod +x). - On Windows, shebang lines are supported for
.bat,.cmd, and other script files. Native.exefiles are executed directly. - The
Proxyheader is always removed to prevent the httpoxy vulnerability. - If a CGI script exits with a non-zero status, Ferron logs a
WARNmessage and returns a500 Internal Server Errorresponse. - For CGI stderr output, Ferron logs warnings when the script produces output on stderr. The output is trimmed before logging.
- The working directory for a CGI script is set to the directory containing the script file.
- For authentication integration, CGI scripts receive
REMOTE_USERandAUTH_TYPEonly when used alongside a module likehttp-basicauththat setsctx.auth_user. - For static file serving alongside CGI, see Static file serving.
- For URL rewriting, see URL rewriting.
- For response headers and CORS, see HTTP headers and CORS.