geminid 1 user commands djbwares
geminid UCSPI-TCP GEMINI server for static content
`geminid` root

## Description

geminid prints requested public files from the root directory hierarchy. The Bernstein convention is for root to be `/public/file`, but it can use other conventional locations such as `/home/publicfile/public` or `/var/www`.

`geminid` accepts a request on standard input, and responds on standard output, printing the requested file and exiting.

If the file is unopenable or if `geminid` does not like the request, `geminid` prints an error message and exits. If the URL length exceeds the pathconf 3 `_PC_PATH_MAX` value for the root directory, `geminid` prints an error message and exits. If `geminid` runs out of memory, encounters an I/O error, or does not receive an input packet within 60 seconds, it exits silently.

`geminid` also prints local log information on standard error.

Normally `geminid` is run under a UCSPI-SSL server program to handle GEMINI connections from hosts around the Internet.

There is no unencrypted version of the GEMINI protocol, and `geminid` is not supposed to be the direct server on the GEMINI port. `geminid` is a UCSPI tool for composing a GEMINI server, not an entire server.

As an extension, the `gemini:` schema prefix can be omitted from requests. Because of this, `geminid` can be used under a UCSPI-TCP server program to provide static FINGER and NICNAME/WHOIS service (of a kind) that does not consult the system account database or user home directories.

Both FINGER and NICNAME are pretty much free-form queries that (de facto) have taken many forms over the years, so a schema-less `//host/path` request is a valid FINGER or NICNAME lookup.

### File handling

A request for `gemini://v/f`, where f does not end with a slash, refers to the file named `./v/f` inside the root directory hierarchy. A request for `gemini://v/f/`, ending in a slash, refers to the file named `./v/f/index.gemini`. `geminid` always converts the host name `v` to lowercase.

If it successfully opens the file, `geminid` uses the file name to select a file type.

### Unsupported features

In addition to the GEMINI protocol's restrictions, `geminid` rejects requests with URLs containing query parts.

`geminid` does not generate its own directory listings, even if `index.gemini` does not exist. `geminid` rejects requests for directory names without terminating slashes; it does not redirect the requests.

`geminid` is purely a static content server. It provides no protocol translation from GOPHER or anything else, and only supports the `gemini:` schema. It does not act as a proxy.

`geminid` is purely an anonymous content server. It has no access controls, and everything that it can publish should be considered public.

## Security

`geminid` chroots to root when it starts. It then sets its group id and user id to the numbers given in environment variables `GID` and `UID`, as set by `envuidgid` (or equivalent). `geminid` does not allow dots immediately after slashes in file names. It changes these dots to colons before attempting to open the file.

`geminid` reads the `/etc/leapsecs.dat` file before the chroot, and does not require it to be copied under root.

`geminid` will refuse to read a file if the file

- is unreadable to user;

- is unreadable to group;

- is unreadable to world;

- is world-executable without being user-executable; or

- is anything other than a regular file: a directory, socket, device, etc.

## History

`geminid` was added to djbwares in 2025.

## Author

Derived from original code by Daniel J. Bernstein. Documentation by Jonathan de Boyne Pollard.