Go to file
Omar Polo 8f543d941e add a note regarding the usage of the bundled libtls
See https://codeberg.org/op/gmid/issues/2
2024-02-02 08:24:28 +00:00
compat mark private function as static 2024-01-07 18:59:10 +00:00
contrib contrib/vim: fix indent 2024-01-30 09:35:37 +00:00
have update imsg test: gmid now requires the new API too 2024-01-21 12:35:46 +00:00
keys rename gmid-1.9.pub -> gmid-2.0.pub; next version will be 2.0 2024-01-10 17:45:12 +00:00
regress rename the @common_opt macro back to @common 2024-01-30 09:31:09 +00:00
site prepare release 2.0.1 2024-01-24 15:06:08 +00:00
.cirrus.yml tweak and update freebsd task 2024-01-26 17:02:08 +00:00
.dockerignore contrib/Dockerfile: fix the build and improve the usage 2024-01-11 15:42:02 +00:00
.gitignore contrib/vim: add ALE linter 2024-01-09 08:41:08 +00:00
ChangeLog sync changelog 2024-01-30 09:39:07 +00:00
LICENSE copyright years 2022-07-04 09:48:39 +00:00
Makefile change the default PUBKEY for the verify-release target 2024-01-24 15:21:19 +00:00
README.md update/fix description of the subprocess and what they do 2024-01-11 10:43:03 +00:00
config.c convert remaining code to the imsg getters 2024-01-21 19:40:06 +00:00
configure add a note regarding the usage of the bundled libtls 2024-02-02 08:24:28 +00:00
crypto.c convert remaining code to the imsg getters 2024-01-21 19:40:06 +00:00
dirs.c don't set d_reclen 2022-07-07 08:54:26 +00:00
fcgi.c send all the params as per RFC3875 (CGI) and sync documentation 2023-08-18 12:40:10 +00:00
ge.c fix ge^W gemexp version string 2024-01-08 08:34:36 +00:00
gemexp.1 add a few Xr in SEE ALSO 2023-10-18 19:29:53 +00:00
gg.1 minor semplifications to some sentences 2023-10-19 21:33:38 +00:00
gg.c gg: prepend "Server says" to the reply code 2023-10-18 17:15:03 +00:00
gmid.8 gmid.8: use a more on-point description 2023-10-20 15:46:42 +00:00
gmid.c convert remaining code to the imsg getters 2024-01-21 19:40:06 +00:00
gmid.conf.5 prepare release 2.0.1 2024-01-24 15:06:08 +00:00
gmid.h fix configtest with chroot 2024-01-09 14:15:58 +00:00
iri.c more is*() unsigned char cast 2022-11-29 23:03:55 +00:00
iri.h split out iri.h from gmid.h 2023-07-22 13:49:07 +00:00
log.c add missing include of gmid.h 2023-06-06 11:57:33 +00:00
log.h switch to the more usual log.c 2023-06-06 11:46:40 +00:00
logger.c convert remaining code to the imsg getters 2024-01-21 19:40:06 +00:00
mime.c copyright years++ 2023-06-24 10:07:17 +00:00
parse.y turn log styles into strings from yacc point of view 2024-01-30 09:30:50 +00:00
proc.c remove proc_forward_imsg since it's unused 2024-01-21 12:23:28 +00:00
proc.h remove proc_forward_imsg since it's unused 2024-01-21 12:23:28 +00:00
proxy.c copyright++ 2023-10-18 17:15:47 +00:00
puny.c remove not so useful starts_with() 2023-08-11 10:38:34 +00:00
sandbox.c resurrect landlock support 2023-08-23 20:18:59 +00:00
server.c convert remaining code to the imsg getters 2024-01-21 19:40:06 +00:00
titan.1 capitalize Titan in .Nd 2023-10-20 15:48:16 +00:00
titan.c titan: accept either one or two positional arguments 2024-01-08 08:39:18 +00:00
utf8.c fmt 2021-10-18 10:05:55 +00:00
utils.c tweak certificate generation log messages 2023-10-18 18:07:28 +00:00



gmid is a full-featured Gemini server written with security in mind. It can serve static files, has optional FastCGI and proxying support, and a rich configuration syntax.

A few helper programs are shipped as part of gmid:

  • gg is a simple command-line Gemini client.

  • gemexp is a stripped-down config-less version of gmid to quickly serve a directory from the command line.

  • titan is a command-line titan client.

Internationalisation (IRIs, UNICODE, punycode, all that stuff)

Even thought the current Gemini specification doesn't mention anything in this regard, I do think these are important things and so I tried to implement them in the most user-friendly way I could think of.

For starters, gmid has full support for IRI (RFC3987 — Internationalized Resource Identifiers). IRIs are a superset of URIs, so there aren't incompatibilities with URI-only clients.

There is full support also for punycode. In theory, the user doesn't even need to know that punycode is a thing. The hostname in the configuration file can (and must be) in the decoded form (e.g. naïve and not xn--nave-6pa), gmid will do the rest.

The only missing piece is UNICODE normalisation of the IRI path: gmid doesn't do that (yet).


gmid has a rich configuration file, heavily inspired by OpenBSD' httpd(8), with every detail carefully documented in the manpage. Here's a minimal example of a config file:

server "example.com" {
	listen on * port 1965
	cert "/path/to/cert.pem"
	key  "/path/to/key.pem"
	root "/var/gemini/example.com"

and a slightly more complex one

cert_root = "/path/to/keys"

server "example.com" {
	listen on * port 1965

	alias "foobar.com"

	cert $cert_root "/example.com.crt"
	key  $cert_root "/example.com.pem"
	root "/var/gemini/example.com"

	# lang for text/gemini files
	lang "en"

	# only for locations that matches /files/*
	location "/files/*" {
		# generate directory listings
		auto index on

	location "/repo/*" {
		# change the index file name
		index "README.gmi"
		lang "it"


gmid depends on libevent2, LibreSSL or OpenSSL, and yacc or GNU bison.

The build is as simple as

$ ./configure
$ make

If the configure scripts fails to pick up something, please open an issue or notify me via email.

To install execute:

# make install

Please keep in mind that the master branch, from time to time, may be accidentally broken on some platforms. gmid is developed primarily on OpenBSD/amd64 and commits on the master branch don't get always tested in other OSes. Before tagging a release however, a comprehensive testing on various platform is done to ensure that everything is working as intended.



$ make regress

to start the suite. Keep in mind that the regression tests needs to create a few file inside the regress directory and bind the 10965 port.


Any form of contribution is welcome, not only patches or bug reports. If you have a sample configuration for some specific use-case, a script or anything that could be useful to others, consider adding it to the contrib directory.

Architecture/Security considerations

The internal architecture was revisited for the 2.0 release. For earlier releases, please refer to previous revision of this file.

gmid has a privsep design, where the operations done by the daemon are splitted into multiple processes:

  • main: the main process is the only one that keeps the original privileges. It opens the TLS certificates on the behalf of the server and crypto processes, reloads the configuration upon SIGHUP and re-opens the log files upon SIGUSR1.

  • logger: handles the logging with syslog and/or local files.

  • server: listens for connections and serves the request. It also speaks FastCGI and do the proxying.

  • crypto: holds the TLS private keys to avoid a compromised server process to disclose them.