Configuration: SCGI support

This page documents the scgi directive for configuring Ferron’s SCGI (Simple Common Gateway Interface) support. SCGI is a protocol for interfacing external application servers with web servers. It is similar to CGI but with binary framing for better performance.

scgi⁠#

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

The scgi directive enables SCGI protocol support. When specified, Ferron forwards requests to the configured SCGI backend using the SCGI protocol instead of spawning local processes.

FormDescription
scgi { ... }Enables SCGI and configures nested directives.
scgi <url: string> { ... }Enables SCGI and sets the backend URL directly.

backend⁠#

Nested directiveArgumentsDescriptionDefault
backend<url: string>This directive specifies the SCGI backend server URL. Supports TCP URLs (tcp://host:port) and Unix socket URLs (unix:///path/to/socket).none

Configuration example:

example.com {
    scgi {
        backend tcp://127.0.0.1:4000
    }
}

Configuration example with Unix socket:

example.com {
    scgi {
        backend unix:///var/run/app.sock
    }
}
Note
  • TCP URLs must include both host and port (for example, tcp://127.0.0.1:4000).
  • 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.

environment⁠#

Nested directiveArgumentsDescriptionDefault
environment<name: string> <value: string>This directive sets an SCGI environment variable passed to the backend server. Values use the same interpolation syntax as other directives. You can specify this directive multiple times.none

Configuration example:

example.com {
    scgi {
        backend tcp://127.0.0.1:4000
        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.

Environment variables⁠#

Ferron automatically sets the following SCGI 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 (for example, Basic, Bearer).
REMOTE_USERAuthenticated username, if available.
SERVER_ADMINServer administrator email (from admin_email configuration).
HTTPSSet to on when the connection uses encryption.

Additional variables set by environment directives override any automatically set variables with the same name.

Tip

For authentication integration, SCGI scripts receive REMOTE_USER and AUTH_TYPE only when used alongside a module like http-basicauth that sets ctx.auth_user.

Authentication⁠#

When used alongside an authentication module (for example, http-basicauth), Ferron automatically populates the AUTH_TYPE and REMOTE_USER environment variables in the SCGI 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 SCGI request. The server maps these headers to standard CGI environment variables:

HeaderSCGI environment variable
traceparentHTTP_TRACEPARENT
tracestateHTTP_TRACESTATE
baggageHTTP_BAGGAGE

This enables end-to-end distributed tracing with SCGI backend applications.

Info

No per-module configuration is necessary. The server controls trace context injection globally based on 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 SCGI backend fails. The message includes the connection error details.

Structured logs⁠#

Description (summary)LevelAttributes
SCGI service unavailableERRORupstream.address (string): backend server URL

Metrics⁠#

MetricTypeAttributesDescription
ferron.scgi.requestsCounterNoneNumber of SCGI requests processed
ferron.scgi.failuresCountererror.type ("service_unavailable"), ferron.scgi.backend_urlNumber of SCGI requests that failed before the backend returned a response
ferron.scgi.upstream.durationHistogramferron.scgi.backend_urlDuration of SCGI upstream request processing

Access log fields⁠#

The SCGI module contributes the following field to the HTTP access log line:

FieldTypeDescription
ferron.scgi.backend_urlstringSCGI backend URL.

Trace spans⁠#

The SCGI stage sets the following attributes on its ferron.stage.scgi span:

AttributeTypeDescription
http.response.status_codeintHTTP status code returned by the SCGI backend.
ferron.scgi.backend_urlstringURL of the SCGI backend.
error.typestringError type on failure, enabling trace UI highlighting.

Examples⁠#

Basic SCGI backend⁠#

example.com {
    scgi tcp://127.0.0.1:4000
}

SCGI with Unix socket⁠#

example.com {
    scgi unix:///var/run/app.sock
}

SCGI with environment variables⁠#

example.com {
    scgi {
        backend "tcp://127.0.0.1:4000"
        environment "APP_ENV" "production"
        environment "APP_SECRET" "{{env.APP_SECRET}}"
        environment "RUBY_VERSION" "3.3"
    }
}

SCGI with authentication⁠#

example.com {
    root /var/www/html

    basic_auth {
        users {
            admin "$argon2id$v=19$m=19456,t=2,p=1$..."
        }
    }

    scgi tcp://127.0.0.1:4000
}