Blob


1 # gmid
3 gmid is a fast Gemini server written with security in mind. I
4 initially wrote it to serve static files, but it has grown into a
5 featureful server that can be used from either the command line to
6 serve local directories
8 gmid docs # serve the directory docs over gemini
10 or as a traditional daemon
12 gmid -c /etc/gmid.conf
15 ## Features
17 (random order)
19 - reconfiguration: reload the running configuration without interruption
20 - sandboxed by default on OpenBSD, Linux and FreeBSD
21 - IRI support (RFC3987)
22 - punycode support
23 - dual stack (IPv4 and IPv6)
24 - automatic certificate generation for config-less mode
25 - CGI scripts
26 - (very) low memory footprint
27 - event-based asynchronous I/O model
28 - small codebase, easily hackable
29 - virtual hosts
30 - per-location rules
31 - optional directory listings
32 - configurable mime types
33 - chroot support
36 ## Internationalisation (IRIs, UNICODE, punycode, all that stuff)
38 Even thought the current Gemini specification doesn't mention anything
39 in this regard, I do think these are important things and so I tried
40 to implement them in the most user-friendly way I could think of.
42 For starters, gmid has full support for IRI (RFC3987 —
43 Internationalized Resource Identifiers). IRIs are a superset of URIs,
44 so there aren't incompatibilities with URI-only clients.
46 There is full support also for punycode. In theory, the user doesn't
47 even need to know that punycode is a thing. The hostname in the
48 configuration file can (and must be) in the decoded form (e.g. `naïve`
49 and not `xn--nave-6pa`), gmid will do the rest.
51 The only missing piece is UNICODE normalisation of the IRI path: gmid
52 doesn't do that (yet).
55 ## Configuration
57 gmid has a rich configuration file, heavily inspired by OpenBSD'
58 httpd. While you should definitely check the manpage because it
59 documents every option in depth, here's an example of what gmid can
60 do.
62 ```conf
63 ipv6 on # enable ipv6
65 server "example.com" {
66 cert "/path/to/cert.pem"
67 key "/path/to/key.pem"
68 root "/var/gemini/example.com"
69 lang "it"
70 cgi "/cgi/*"
72 location "/files/*" {
73 auto index on
74 }
76 location "/repo/*" {
77 # change the index file name
78 index "README.gmi"
79 }
81 # redirect /cgi/man/... to man.example.com/...
82 location "/cgi/man*" {
83 strip 2
84 block return 31 "gemini://man.example.com%p"
85 }
86 }
88 server "man.example.com" {
89 cert "..."
90 key "..."
91 root "/var/gemini/man.example.com"
93 # handle every request with the CGI script `man'
94 entrypoint "man"
95 }
96 ```
99 ## Building
101 gmid depends on a POSIX libc, libevent2, OpenSSL/LibreSSL and libtls
102 (provided either by LibreSSL or libretls). At build time, flex and
103 yacc (or GNU bison) are also needed.
105 The build is as simple as
107 ./configure
108 make
110 If the configure scripts fails to pick up something, please open an
111 issue or notify me via email.
113 To install execute:
115 make install
117 ### Docker
119 If you have trouble installing LibreSSL or libretls, you can use
120 Docker to build a `gmid` image with:
122 docker build -t gmid .
124 and then run it with something along the lines of
126 docker run --rm -it -p 1965:1965 \
127 -v /path/to/gmid.conf:...:ro \
128 -v /path/to/docs:/var/gemini \
129 gmid -c .../gmid.conf
131 (ellipses used for brevity)
133 ### Local libretls
135 This is **NOT** recommended, please try to port LibreSSL/LibreTLS to
136 your distribution of choice or use docker instead.
138 However, it's possible to statically-link `gmid` to locally-installed
139 libretls quite easily. (It's how I test gmid on Fedora, for instance)
141 Let's say you have compiled and installed libretls in `$LIBRETLS`,
142 then you can build `gmid` with
144 ./configure CFLAGS="-I$LIBRETLS/include" \
145 LDFLAGS="$LIBRETLS/lib/libtls.a -lssl -lcrypto -lpthread"
146 make
148 ### Testing
150 Execute
152 make regress
154 to start the suite. Keep in mind that the regression tests will
155 create files inside the `regress` directory and bind the 10965 port.
158 ## Architecture/Security considerations
160 gmid is composed by two processes: a listener and an executor. The
161 listener process is the only one that needs internet access and is
162 sandboxed. When a CGI script needs to be executed, the executor
163 (outside of the sandbox) sets up a pipe and gives one end to the
164 listener, while the other is bound to the CGI script standard output.
165 This way, is still possible to execute CGI scripts without
166 restrictions even in the presence of a sandboxed network process.
168 On OpenBSD, the listener runs with the `stdio recvfd rpath inet`
169 pledges, while the executor has `stdio sendfd proc exec`; both have
170 unveiled only the served directories.
172 On FreeBSD, the executor process is sandboxed with `capsicum(4)`.
174 On Linux, a `seccomp(2)` filter is installed in the listener to allow
175 only certain syscalls, see [sandbox.c](sandbox.c) for more information
176 on the BPF program.
178 In any case, you are invited to run gmid inside some sort of
179 container/jail/chroot.