gmnisrv.ini(5)
π¦ NAME π¦
Okay bestie, this is gmnisrv.ini(5) from the File Formats Manual β and gmnisrv.ini is literally the configuration file for gmnisrv(1). That's the whole NAME moment. Short, iconic, done. π
β¨ SYNTAX β¨
gmnisrv.ini is an INI file, no cap. Each line is either a key/value pair, or a section heading. Key/value pairs are specified as key=value, and sections as [section]. That's the vibe check. π«Ά
πΈ CONFIGURATION KEYS πΈ
The meaning of the key depends on the section. Anonymous keys (prior to the first [section] directive) are used to specify parameters for the daemon itself. Sections whose name is prefixed with : β e.g. [:tls] β are sub-categories of the daemon configuration. Otherwise, section names refer to the hostnames of domains serviced by the gmnisrv daemon. π
π ANONYMOUS KEYS π
listenβ A space-separated list of addresses that the daemon shall bind to. Each address shall take the formataddress:port. If:portis omitted,1965(the default Gemini port) is presumed. To specify an IPv6 address, enclose it in[], e.g.[::].
π TLS KEYS π
The following keys are accepted under the [:tls] section:
storeβ Path to the certificate store on disk. This should be a persistent directory writable by the daemon. The daemon manages its own certificates β no user intervention is required, except in the case of moving the daemon to another host, in which case the certificate store must be copied to the new host.organizationβ An optional key used during certificate generation. Fill this in with the name of the organization responsible for the host and it will be filled in as the X.509/Oname.
π£οΈ ROUTING KEYS π£οΈ
To configure gmnisrv to service requests, routing keys must be defined. The name of the configuration section is used to determine what kinds of requests it configures. This is where the main character energy lives. π
The format of the section name is the hostname to be serviced, followed by a token which defines the routing strategy, and a string whose format is specific to each routing strategy. The token and match string may be omitted (i.e. [hostname] alone), which implies path routing against "/".
:β Route by path prefix. The URL path is compared to"string/".=β Exact match. The URL path must exactly match the string.~β Regular expression routing. The string is a JavaScript-compatible regular expression which is tested against the URL path.
See ECMAScript 2018 (ECMA-282, 9th Edition), section 21.2 for a definition of the regular expression syntax and features, or an informative reference on MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
Some example section names and examples of matching paths:
[example.org:/foo] /foo, /foo/bar, /foo/bar/baz
[example.org=/foo.txt] /foo.txt
[example.org~/[a- /foo.png, /bar.webp
z]+\.(png|jpg|webp)
Routes should be ordered from least to most specific. The matching algorithm attempts to match the URL against each route in reverse order, and chooses the first route which matches. Lowkey important, fr fr. π₯
Within each routing section, the following keys are used to configure how gmnisrv will respond to matching requests:
rootβ Configures the path on disk from which files shall be served for this host. The path component of the URL will be appended to this value to form the path to files on disk to serve.
If example.org/foo/bar.txt is requested, and a route is configured for [example.org:/foo] with the root set to /srv/gemini, /srv/gemini/foo/bar.txt will be served.
rewriteβ If regular expression routing is used, therewritedirective may be used to rewrite the URL path component before proceeding. The URL will be set to the value of the rewrite expression. If\Nappears in the rewrite value, where N is a number, that capture group will be substituted for\N. If\{name}appears, where name is a named capture group, it will be substituted.
Example:
[localhost~^/([a-zA-Z]+).(?<extension>png|jpg)$]
root=./root
rewrite=/images/1.{extension}
This will rewrite a request for /example.png to /images/example.png.
indexβ Configures the name of the index file which shall be served in the event that a request for this host does not include the filename part. Defaults to"index.gmi".autoindexβ"on"to enable the auto-index feature, which presents clients with a list of files in the requested directory when an index file cannot be found. Off by default.cgiβ"on"to enable CGI support.rootmust also be configured. See "CGI Support" for details.
π CGI Support π
gmnisrv supports a limited version of CGI, compatible with the Jetforce server. It is not a faithful implementation of RFC 3875, but is sufficient for most of the needs of Gemini servers. π
Set cgi=on for a route configuration to enable CGI for that route and set root to the path where the CGI scripts are found. If a client requests a script, it will be executed, and must print a Gemini response (including status code and meta) to stdout.
The following environment variables will be set:
Okay bestie, this is the part where gmnisrv hands your CGI script a whole little gift bag of environment variables π every single one of them, no skips:
GATEWAY_INTERFACEβ the CGI version. Example:CGI/1.1β¨SERVER_PROTOCOLβ the protocol the server speaks. Example:GEMINIπSERVER_SOFTWAREβ the gmnisrv server name and version, together, cute. Example:gmnisrv/0.0.0GEMINI_URLβ the URL the client requested. Example:See [1](yes that's literally what the table says, don't come for me π)SCRIPT_NAMEβ the chunk of the URL that points at the script name. Example:/cgi-bin/foo.shPATH_INFOβ whatever path is left over afterSCRIPT_NAME. Example:/barQUERY_STRINGβ the query-string part of the URL. Example:hello=worldSERVER_NAME,HOSTNAMEβ the server host name. Example:example.orgSERVER_PORTβ the server port number. Example:1965REMOTE_HOST,REMOTE_ADDRβ the client's IP address. Example:10.10.0.2TLS_CIPHERβ the TLS cipher that got negotiated. Example:TLS_AES_256_GCM_SHA384πTLS_VERSIONβ the TLS version that got negotiated. Example:TLSv1.3AUTH_TYPEβ there for compatibility with RFC 3785. Example:CERTIFICATETLS_CLIENT_HASHβ a unique fingerprint of the client certificate, like a lil ID badge for the cert πͺͺ Example:SHA256:BD3A388021A92017B781504A3D24F324BF9DE11CE72606AB445D98A8EB00C5A8TLS_CLIENT_SERIAL_NUMBERβ the serial number. Example:717823108622037499122666796829184010024179612962
ngl some of these are doing a lot of heavy lifting in one line of key=value and I respect it π
^(okay bestie we are picking this table back up mid-wrap, no cap β the row right above finishes its value column with (decimal) β¦ of the client certificate, and then there's exactly one row left, and it's the one everybody actually cares about π)
REMOTE_USERβ the gemini user, and its value is the Subject common name of the client certificate. yep, that's it, that's the whole row π
so the table's full vibe is: name β what it is β the value it gets, and REMOTE_USER is the last one to make its little debut β¨
and don't forget the footnote hanging off that table, bestie β it's giving very "iykyk" but here it is in full, exactly as written:
[1]: gemini://example.org/cgi-bin/foo.sh/bar?hello=world
lowkey iconic that a CGI URL gets its own footnote, but that's the whole point: look at how the path and query ride along after the script name π¦
π«Ά one last thing about that script
The exit status of the script is ignored.
like β fr fr ignored. the script does its thing, prints its response, and whatever number it hands back on the way out? nobody is checking it π so don't go relying on your exit code to signal anything to gmnisrv, 'cause gmnisrv is not listening to that part. periodt.
and that's the whole page, bestie π you made it to the end of gmnisrv.ini(5), and this one's dated 2025-08-08 β that's the source/version stamp and date from the footer, which i have now lovingly narrated instead of copy-pasting π go write your config, go run your CGI scripts, and go slay ππβ¨
π¦ where this page comes from
- alpine 3.24: gmnisrv-doc 1.0-r3 Β· GPL-3.0-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms