geminid

## Name

geminid — UCSPI-TCP GEMINI server for static content

## Synopsis

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

### Warning

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.

### Note

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.

### Note

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.