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