fcgi
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.