fcgi

Package Version Hex Docs

A FastCGI Responder server for Gleam, designed to sit behind a reverse proxy such as Caddy. Speaks the FastCGI Responder role over a Unix domain socket and exposes a gleam/http-shaped handler API.

Installation

gleam add fcgi

Usage with gleam/http

import fcgi
import gleam/erlang/process
import gleam/http/request.{type Request}
import gleam/http/response.{type Response}

pub fn main() {
  let assert Ok(_) =
    fcgi.new(handle_request)
    |> fcgi.listen_unix("/tmp/fcgi.sock")
    |> fcgi.start

  process.sleep_forever()
}

fn handle_request(
  _request: Request(fcgi.BodyReader),
  _ctx: fcgi.Context,
) -> Response(fcgi.ResponseData) {
  response.new(200)
  |> response.set_header("content-type", "text/plain; charset=utf-8")
  |> response.set_body(fcgi.string("hello, joe!"))
}

Usage with Wisp

A working Wisp adapter lives in examples/wisp_hello. Copy examples/wisp_hello/src/wisp_fcgi.gleam into your own project alongside the wisp dependency, then wire it up:

import fcgi
import gleam/erlang/process
import wisp
import wisp_fcgi

pub fn main() {
  let secret_key_base = wisp.random_string(64)

  let assert Ok(_) =
    handle_request
    |> wisp_fcgi.handler(secret_key_base)
    |> fcgi.new
    |> fcgi.listen_unix("/tmp/fcgi.sock")
    |> fcgi.start

  process.sleep_forever()
}

fn handle_request(_request: wisp.Request) -> wisp.Response {
  wisp.ok()
  |> wisp.string_body("hello, joe!")
}

The socket file is created when the server starts and removed on shutdown.

Reverse-proxy with Caddy

example.com {
    reverse_proxy unix//tmp/fcgi.sock {
        transport fastcgi {
            env PATH_INFO {http.request.uri.path}
        }
    }
}

HTTP-shaped FastCGI parameters become a gleam/http.Request. Trusted CGI metadata (client address, auth, script name, etc.) is passed separately as fcgi.Context, with anything unrecognized in extra.

Search Document