Configuration: FastCGI support

This page documents the fcgi directive for configuring Ferron’s FastCGI support. FastCGI enables dynamic content by forwarding requests to external application servers over TCP or Unix sockets, with support for connection pooling and keepalive for improved performance.

fcgi

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

The fcgi directive enables FastCGI protocol support. It can be written as a boolean flag to enable with defaults, with a backend URL to set the target, or as a block with nested directives to customize behavior.

FormDescription
fcgiEnables FastCGI with all defaults. Backend URL must be set via the backend nested directive.
fcgi trueExplicitly enables FastCGI. Backend URL must be set via 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.

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 (e.g., tcp://127.0.0.1:9000).
  • Unix socket paths must be absolute paths.
  • When a connection failure occurs (connection refused, host unreachable, etc.), 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 — stderr output is logged as a warning (trimmed before logging).

extension

Nested directiveArgumentsDescriptionDefault
extension<string>This directive registers a file extension that should be processed by the FastCGI backend. Files with these extensions are handled by the FastCGI backend when pass is false. This directive can be specified multiple times, and each invocation can accept multiple extensions.

Configuration example:

example.com {
    fcgi {
        backend tcp://127.0.0.1:9000
        extension ".php"
        extension ".php5" ".php7"
    }
}
Note
  • Extensions are matched case-insensitively.
  • Files with these extensions are processed by the FastCGI backend regardless of their location in the document root.
  • When fcgi_php is used instead, .php is registered automatically.

environment

Nested directiveArgumentsDescriptionDefault
environment<name: string> <value: string>This directive sets a FastCGI environment variable passed to the backend server. Values are resolved with the same interpolation syntax as other directives. This directive can be specified multiple times.

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.
  • The working directory is set to the directory containing the script file.

pass

Nested directiveArgumentsDescriptionDefault
pass<boolean: optional>This directive controls whether all requests are passed to the FastCGI backend. When true, all requests are forwarded. When false, requests are passed to the file-processing pipeline, allowing 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, the FastCGI backend is only invoked 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, connections are reused across requests, reducing connection setup overhead.false

Configuration example:

example.com {
    fcgi {
        backend tcp://127.0.0.1:9000
        keepalive
    }
}
Note
  • Keepalive connections are managed in a connection pool.
  • When combined with the limit directive, each upstream can have its own pool limit.
  • 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 a convenience 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.

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.
  • fcgi_php false can be used to disable PHP FastCGI for a specific scope.
  • For PHP-FPM over Unix sockets, ensure the socket is accessible by the Ferron process (check owner/group/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 is exhausted, 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 when the connection is encrypted.

Additional variables set by environment directives override any automatically set 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 (e.g., http-basicauth), Ferron automatically populates the AUTH_TYPE and REMOTE_USER environment variables in the FastCGI request. The authentication type is extracted from the Authorization header (e.g., 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. These headers are mapped 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 trace context headers are available to the FastCGI backend application, enabling end-to-end distributed tracing. For example, a PHP application running with the official OpenTelemetry SDK for PHP can read these headers to create child spans automatically.

Info

No per-module configuration is needed. Trace context injection is controlled globally by whether a trace context exists — see Tracing configuration for details on enabling 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.requestsCounterNumber of FastCGI requests processed
ferron.fcgi.failuresCountererror.type ("service_unavailable"), ferron.fcgi.backend_urlNumber of FastCGI requests that failed before a backend response was returned
ferron.fcgi.upstream.durationHistogramferron.fcgi.backend_urlDuration of FastCGI upstream request processing
ferron.fcgi.stderr_errorsCounterNumber of FastCGI requests that produced non-empty stderr output

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
}