Configuration: FastCGI support

This page documents the fcgi directive, which configures FastCGI support in Ferron. FastCGI enables dynamic content by forwarding requests to external application servers over TCP or Unix sockets. It also supports connection pooling and keepalive.

fcgi⁠#

example.com {
    fcgi {
        backend tcp://127.0.0.1:4000
        environment "APP_ENV" "production"
    }
}

The fcgi directive enables FastCGI protocol support. You can write it as a boolean flag to enable with defaults. You can write a backend URL to set the target. You can also write it as a block with nested directives to customize behavior. Ferron supports configuring multiple FastCGI backends using multiple fcgi or fcgi_php directives.

FormDescription
fcgiEnables FastCGI with all defaults. Set the backend URL with the backend nested directive.
fcgi trueExplicitly enables FastCGI. Set the backend URL with the backend nested directive.
fcgi falseDisables FastCGI for the current scope.
fcgi <url: string>Enables FastCGI and sets the backend URL directly.
fcgi <url: string> { ... }Enables FastCGI, sets the backend URL, and configures nested directives.
fcgi { ... }Enables FastCGI and configures nested directives.

backend⁠#

Nested directiveArgumentsDescriptionDefault
backend<url: string>This directive specifies the FastCGI backend server URL. Supports TCP URLs (tcp://host:port) and Unix socket URLs (unix:///path/to/socket). The URL supports interpolation syntax for dynamic values.none

Configuration example:

example.com {
    fcgi {
        backend tcp://127.0.0.1:9000
    }
}

Configuration example with Unix socket:

example.com {
    fcgi {
        backend unix:///run/php/php8.4-fpm.sock
    }
}
Note
  • TCP URLs must include both host and port (for example, tcp://127.0.0.1:9000).
  • Unix socket paths must be absolute paths.
  • When a connection failure occurs (connection refused, host unreachable, and so on), Ferron logs an error and returns a 503 Service Unavailable response.
  • If a FastCGI server returns a non-zero status, Ferron logs a WARN message and returns a 500 Internal Server Error response. Ferron trims stderr output before logging it as a warning.

extension⁠#

Nested directiveArgumentsDescriptionDefault
extension<string>This directive registers a file extension that the FastCGI backend should process. The FastCGI backend handles files with these extensions when pass is false. You can specify this directive multiple times. Each invocation can accept multiple extensions.none

Configuration example:

example.com {
    fcgi {
        backend tcp://127.0.0.1:9000
        extension ".php"
        extension ".php5" ".php7"
    }
}
Note
  • Ferron matches extensions case-insensitively.
  • The FastCGI backend processes files with these extensions, regardless of their location in the document root.
  • When you use fcgi_php instead, Ferron registers .php automatically.

environment⁠#

Nested directiveArgumentsDescriptionDefault
environment<name: string> <value: string>This directive sets a FastCGI environment variable passed to the backend server. The server resolves values with the same interpolation syntax as other directives. You can specify this directive multiple times.none

Configuration example:

example.com {
    fcgi {
        backend tcp://127.0.0.1:9000
        environment "APP_ENV" "production"
        environment "APP_SECRET" "{{env.APP_SECRET}}"
        environment "RUBY_VERSION" "3.3"
    }
}
Note
  • Environment variables take precedence over any existing variables with the same name.
  • The Proxy header is automatically removed from the request to prevent the httpoxy vulnerability.
  • Ferron always sets SERVER_SOFTWARE, SERVER_NAME, SERVER_ADDR, SERVER_PORT, REQUEST_URI, QUERY_STRING, PATH_INFO, SCRIPT_NAME, AUTH_TYPE, REMOTE_USER, and SERVER_ADMIN automatically.
  • Ferron sets the working directory to the directory containing the script file.

pass⁠#

Nested directiveArgumentsDescriptionDefault
pass<boolean: optional>This directive controls whether Ferron passes all requests to the FastCGI backend. When true, Ferron forwards all requests. When false, Ferron passes requests to the file-processing pipeline. This allows the extension directive to match files.true

Configuration example:

example.com {
    fcgi {
        backend tcp://127.0.0.1:9000
        pass false
        extension ".php"
    }
}
Note
  • When pass is false, Ferron only invokes the FastCGI backend for files matching a registered extension.
  • This is useful for routing specific file types to the FastCGI backend while serving other files statically.

keepalive⁠#

Nested directiveArgumentsDescriptionDefault
keepalive<boolean: optional>This directive enables connection keepalive to the FastCGI backend. When enabled, Ferron reuses connections across requests. This reduces connection setup overhead.false

Configuration example:

example.com {
    fcgi {
        backend tcp://127.0.0.1:9000
        keepalive
    }
}
Note
  • Ferron manages keepalive connections in a connection pool.
  • When you combine this with the limit directive, each upstream can have its own pool limit.
  • This is useful for high-traffic sites where connection setup overhead is significant.

fcgi_php⁠#

example.com {
    fcgi_php "unix:///run/php/php8.4-fpm.sock"
}

The fcgi_php directive is an alias for PHP FastCGI backends. It enables FastCGI and automatically registers the .php file extension. This is the recommended way to host PHP applications with PHP-FPM.

FormDescription
fcgi_php <url: string>Enables PHP FastCGI with the specified backend URL.
fcgi_php falseDisables PHP FastCGI for the current scope.
fcgi_php { ... }Configures PHP FastCGI with a custom backend URL and other options (same as fcgi, but without extension and pass subdirectives).

This directive would be (roughly) equivalent to the following configuration:

example.com {
    root /var/www/html
    fcgi {
        backend tcp://php:9000/ # <-- Backend URL
        pass false
        extension ".php"
        # Other subdirectives...
    }
    index index.php index.html index.htm
}

Configuration example with TCP:

example.com {
    root /var/www/html
    fcgi_php "tcp://127.0.0.1:9000"
}

Configuration example with Unix socket:

example.com {
    root /var/www/html
    fcgi_php "unix:///run/php/php8.4-fpm.sock"
}
Note
  • fcgi_php automatically registers .php as a file extension.
  • Use fcgi_php false to disable PHP FastCGI for a specific scope.
  • For PHP-FPM over Unix sockets, make sure the Ferron process can access the socket. Check the owner, group, and mode in your PHP-FPM pool configuration.

Connection pooling⁠#

Ferron manages FastCGI backend connections using a connection pool. This reduces the overhead of establishing new connections for each request.

fcgi_concurrent_conns⁠#

DirectiveArgumentsDescriptionDefault
fcgi_concurrent_conns<number: positive> or falseThis directive sets the global maximum number of concurrent FastCGI connections across all backends. Set to false for no limit.16384

Configuration example:

fcgi_concurrent_conns 8192

Configuration example with no limit:

fcgi_concurrent_conns false
Note
  • This is a global setting that applies to all FastCGI backends.
  • Individual backends can also have their own per-upstream limits via the limit nested directive inside fcgi.
  • When the pool runs out of connections, new requests wait for a connection to become available.
  • Setting to false disables the global limit (unlimited concurrent connections).

Per-upstream connection limits⁠#

When using multiple FastCGI backends, you can set individual connection limits for each:

example.com {
    fcgi {
        backend tcp://127.0.0.1:9000
        limit 64
    }
}

The limit directive sets the maximum number of concurrent connections for that specific backend.

Environment variables⁠#

Ferron automatically sets the following FastCGI environment variables:

VariableDescription
SERVER_SOFTWAREAlways Ferron.
SERVER_NAMEServer hostname.
SERVER_ADDRLocal server address.
SERVER_PORTServer port.
REQUEST_METHODHTTP method.
REQUEST_URIOriginal request URI.
QUERY_STRINGQuery string (empty string if none).
PATH_INFOPath info extracted from the request.
SCRIPT_NAMEThe script path relative to the document root.
AUTH_TYPEAuthentication type from the Authorization header.
REMOTE_USERAuthenticated username, if available.
SERVER_ADMINServer administrator email (from admin_email configuration).
HTTPSSet to on for encrypted connections.

Additional variables that environment directives define override any variables with the same name.

Tip

FastCGI applications receive REMOTE_USER and AUTH_TYPE only when used alongside http-basicauth. For related configuration, see Static file serving, URL rewriting, and HTTP headers and CORS.

Authentication⁠#

When used alongside an authentication module (for example, http-basicauth), Ferron automatically populates the AUTH_TYPE and REMOTE_USER environment variables in the FastCGI request. Ferron extracts the authentication type from the Authorization header (for example, Basic or Bearer).

Trace context injection⁠#

When a trace context exists for the request, Ferron automatically injects W3C Trace Context headers (traceparent, tracestate, and baggage) into the FastCGI request. Ferron maps these headers to standard CGI environment variables:

HeaderFastCGI environment variable
traceparentHTTP_TRACEPARENT
tracestateHTTP_TRACESTATE
baggageHTTP_BAGGAGE

This works in both pass true and pass false modes. The FastCGI backend application can read the trace context headers. This enables end-to-end distributed tracing. For example, a PHP application can use the official OpenTelemetry SDK for PHP to read these headers. The application creates child spans automatically.

Info

You do not need per-module configuration. The system controls trace context injection globally based on whether a trace context exists. See Tracing configuration for details on trace generation and sampling.

Observability⁠#

Logs⁠#

  • ERROR: logged when a connection to the FastCGI backend fails. The message includes the connection error details.
  • WARN: logged when a FastCGI backend produces output on stderr. The message includes the trimmed stderr content.

Structured logs⁠#

Description (summary)LevelAttributes
FastCGI service unavailableERRORupstream.address (string): backend server URL
FastCGI errors on stderrWARNerror.message (string): trimmed stderr output from the FastCGI process

Metrics⁠#

MetricTypeAttributesDescription
ferron.fcgi.requestsCounterNoneNumber of FastCGI requests processed
ferron.fcgi.failuresCountererror.type ("service_unavailable"), ferron.fcgi.backend_urlNumber of FastCGI requests that failed before the backend returned a response
ferron.fcgi.upstream.durationHistogramferron.fcgi.backend_urlFastCGI upstream request processing time
ferron.fcgi.stderr_errorsCounterNoneNumber of FastCGI requests that produced non-empty stderr output

Access log fields⁠#

The FastCGI module contributes the following fields to the HTTP access log line:

FieldTypeDescription
ferron.fcgi.backend_urlstringFastCGI backend URL.
ferron.fcgi.script_filenamestringScript filename (file mode).

Trace spans⁠#

The FastCGI stage sets the following attributes on its ferron.stage.fcgi_pass span:

AttributeTypeDescription
http.response.status_codeintHTTP status code returned by the FastCGI backend.
ferron.fcgi.backend_urlstringURL of the FastCGI backend.
ferron.fcgi.script_filenamestringAbsolute path to the script on the backend filesystem, when available.
error.typestringError type on failure (for example, service_unavailable). This enables trace UI highlighting.

Examples⁠#

PHP with PHP-FPM over a Unix socket⁠#

example.com {
    root /var/www/html
    fcgi_php "unix:///run/php/php8.4-fpm.sock"
}

PHP with PHP-FPM over TCP⁠#

example.com {
    root /var/www/html
    fcgi_php "tcp://127.0.0.1:9000"
}

FastCGI with environment variables⁠#

example.com {
    fcgi {
        backend tcp://127.0.0.1:9000
        environment "APP_ENV" "production"
        environment "APP_SECRET" "{{env.APP_SECRET}}"
    }
}

FastCGI with keepalive and connection limits⁠#

example.com {
    fcgi {
        backend tcp://127.0.0.1:9000
        keepalive
        limit 64
        extension ".php"
    }
}

FastCGI with selective file routing⁠#

example.com {
    root /var/www/html

    # Only .php files are processed by the FastCGI backend
    fcgi {
        backend tcp://127.0.0.1:9000
        pass false
        extension ".php"
    }

    # Other files are served statically
}