This is an application server which implements the Fast CGI protocol to receive requests from a web server. The server is written in Janet and allows arbitrary Janet programs to be loaded to respond to FCGI requests.
Based on the specification found at https://www.mit.edu/~yandros/doc/specs/fcgi-spec.html
The FCGI server script is started by a command line of the form:
janet fcgi-server.janet [-c configuration-file] &
An rc.d script is provided for OpenBSD. See below.
The FCGI server parameters are set via a configuration file. The
default configuration file locations are /etc/fcgi-server.cfg and
/usr/local/etc/fcgi-server.cfg. If neither of these files exist, a
default internal configuraton is used.
The default configuration file may be overridden by passing a configuration file name via the -c command option. Failure to read the specified configuration file, or syntax errors encountered while processing the file, will cause the server to terminate.
The FCGI server offers the following configuration capabilities. The settings shown are the defaults, if no configuration file is specified.
The FCGI server communicates with the Web server via a Unix socket. socket-file defines the pathname of the socket file:
socket-file: /tmp/fcgi.sock
If chroot is set, the socket-file path must be relative to the chroot.
If not nil, the FCGI server will use the UNIX chroot call to set the defined chroot path as the root of the processes filesystem. Uses osx/chroot; see osx below, for more details.
chroot: nil
Use of chroot requires that the FCGI server be invoked by root.
If not nil, the FCGI server will set the effective user id of the running janet process to user, using osx/setuid; see osx. The ownership of the socket-file is also changed to user. This facility should be used to drop privileges when the FCGI server is invoked by root.
user: nil
The route keyword introduces a route; each route is defined with a url and a Janet script to invoke when that url is encountered. See FCGI Scripts below. If chroot is set, script path names must be relative to the chroot location.
No routes are defined by default.
route: /fcgi/test : /fcgi/test.fcgi
route: /fcgi/list : /fcgi/list.janet
route-param defines which CGI environment parameter the FCGI server should consult to match route urls.
route-param: DOCUMENT_URI
log-file defines the pathname of the log file. The file must be writable by the effective user id of the Janet process running the FCGI server.
log-file: /tmp/fcgi.log
If chroot is set, the log-file pathname must be relative to the chroot.
Defines the logging level required. The default of 0 logs major actions and errors. Increasing the value of log-level increases the verbosity of the log file.
log-level: 3
Defines the maximum number of spawned threads to handle parallel requests from the web server. This value is passed to the web server as FCGI_MAX_REQS should it issue a FCGI_GET_VALUES request.
max-threads: 10
The osx module implements a number of specialist Unix OS calls. See https://github.com/mpwillson/osx.
To use the module, it must be installed system wide. Clone or download the repository. Navigate to the osx directory and install with:
doas jpm install
If the FCGI server cannot import the osx module, stub functions are defined to avoid compilation errors.
When a url defined in routes is encountered, the script specified is
invoked. A script must provide the function fcgi-main, which
takes two arguments. The first is a table containing the CGI names and
values passed by the web server; both keys and values of the table are
strings. The second argument is the string received as stdin.
The fcgi-main function returns a string representing an HTML
response to the request received. Any errors encounted while running
fcgi-main are trapped by the FCGI server and will be reported to
the web server.
Assuming an existing Janet script runs as a CGI program (via a main function), the following code will allow the script to run as an FCGI route program.
(defn fcgi-main
"Enable CGI program to operate as an FCGI route. Set required environment
variables from params and capture printed output using dynamic var."
[params in]
(each name ["DOCUMENT_ROOT" "REMOTE_ADDR" "QUERY_STRING"]
(os/setenv name (params name)))
(def output @"")
(with-dyns [:out output] (main))
output)Add a stanza of the following form to the relevant server section in
the /etc/httpd.conf file:
location "/fcgi/*" {
fastcgi {
socket "/run/fcgi.sock"
}
}
The socket file definition should match that provided to the fcgi-server via the configuration file.
To (minimally) test the FCGI server prior to installation, issue the command:
jpm -l install && jpm -l test
To install system-wide:
doas make install
This will run jpm install and copy the default configuration file to
/usr/local/etc/.
The FCGI server responds to the following signals:
- SIGTERM to terminate server
- SIGHUP to reload the route scripts
An rc.d script to control the FCGI server is provided for use on OpenBSD.
Add the following line to /etc/rc.conf.local:
fcgi_server_flags=""
In addition, the daemon name must be added to the pkg_scripts
variable in /etc/rc.conf.local, e.g.:
pkg_scripts=samba dovecot fcgi_server
The FCGI server can then be controlled by rcctl, for example:
doas rcctl restart fcgi_server
The rcctl reload verb is supported, which will cause the FCGI server
to re-load the route scripts.
Not recommended for high traffic environments (or, indeed, low traffic environments).