2020-10-02 19:39:00 +02:00
|
|
|
|
|
|
|
# NAME
|
|
|
|
|
2020-10-03 17:49:09 +02:00
|
|
|
**gmid** - dead simple zero configuration gemini server
|
2020-10-02 19:39:00 +02:00
|
|
|
|
|
|
|
# SYNOPSIS
|
|
|
|
|
|
|
|
**gmid**
|
2020-12-02 21:18:01 +01:00
|
|
|
\[**-fh**]
|
2020-10-02 19:39:00 +02:00
|
|
|
\[**-c** *cert.pem*]
|
|
|
|
\[**-d** *docs*]
|
|
|
|
\[**-k** *key.pem*]
|
2020-11-18 09:12:27 +01:00
|
|
|
\[**-p** *port*]
|
2020-11-06 18:12:57 +01:00
|
|
|
\[**-x** *cgi-bin*]
|
2020-10-02 19:39:00 +02:00
|
|
|
|
|
|
|
# DESCRIPTION
|
|
|
|
|
|
|
|
**gmid**
|
2020-11-06 18:12:57 +01:00
|
|
|
is a very simple and minimal gemini server that can serve static files
|
|
|
|
and execute CGI scripts.
|
2020-10-02 19:39:00 +02:00
|
|
|
|
|
|
|
**gmid**
|
2020-12-26 00:33:11 +01:00
|
|
|
won't serve files outside the given directory and won't follow
|
|
|
|
symlinks.
|
2020-10-02 19:44:32 +02:00
|
|
|
Furthermore, on
|
|
|
|
OpenBSD,
|
|
|
|
pledge(2)
|
2020-10-02 19:39:00 +02:00
|
|
|
and
|
2020-10-02 19:44:32 +02:00
|
|
|
unveil(2)
|
2020-10-02 19:39:00 +02:00
|
|
|
are used to ensure that
|
|
|
|
**gmid**
|
2020-11-06 18:12:57 +01:00
|
|
|
dosen't do anything else than read files from the given directory,
|
|
|
|
accept network connections and, optionally, execute CGI scripts.
|
2020-10-02 19:39:00 +02:00
|
|
|
|
2020-12-26 00:33:11 +01:00
|
|
|
**gmid**
|
|
|
|
fully supports IRIs (Internationalized Resource Identifiers, see
|
|
|
|
RFC3987).
|
|
|
|
|
2020-10-02 19:39:00 +02:00
|
|
|
It should be noted that
|
|
|
|
**gmid**
|
|
|
|
is very simple in its implementation, and so it may not be appropriate
|
2020-11-06 18:12:57 +01:00
|
|
|
for serving sites with lots of users.
|
|
|
|
After all, the code is single threaded and use a single process,
|
2020-12-21 15:51:09 +01:00
|
|
|
although it can handle multiple clients at the same time.
|
2020-10-02 19:39:00 +02:00
|
|
|
|
2020-10-03 17:49:09 +02:00
|
|
|
If a user request path is a directory,
|
|
|
|
**gmid**
|
|
|
|
will try to serve a
|
|
|
|
*index.gmi*
|
|
|
|
file inside that directory.
|
|
|
|
|
2020-10-02 19:39:00 +02:00
|
|
|
The options are as follows:
|
|
|
|
|
|
|
|
**-c** *cert.pem*
|
|
|
|
|
|
|
|
> The certificate to use, by default is
|
2020-10-03 17:49:09 +02:00
|
|
|
> *cert.pem*.
|
2020-10-02 19:39:00 +02:00
|
|
|
|
|
|
|
**-d** *docs*
|
|
|
|
|
|
|
|
> The root directory to serve.
|
|
|
|
> **gmid**
|
2020-11-10 14:07:36 +01:00
|
|
|
> won't serve any file that is outside that directory.
|
|
|
|
> By default is
|
2020-11-06 18:12:57 +01:00
|
|
|
> *docs*.
|
2020-10-02 19:39:00 +02:00
|
|
|
|
2020-12-02 21:18:01 +01:00
|
|
|
**-f**
|
|
|
|
|
|
|
|
> stays and log in the foreground, do not daemonize the process.
|
|
|
|
|
2020-10-02 19:39:00 +02:00
|
|
|
**-h**
|
|
|
|
|
2020-10-03 17:49:09 +02:00
|
|
|
> Print the usage and exit.
|
2020-10-02 19:39:00 +02:00
|
|
|
|
|
|
|
**-k** *key.pem*
|
|
|
|
|
|
|
|
> The key for the certificate, by default is
|
2020-10-03 17:49:09 +02:00
|
|
|
> *key.pem*.
|
2020-10-02 19:39:00 +02:00
|
|
|
|
2020-11-18 09:12:27 +01:00
|
|
|
**-p** *port*
|
|
|
|
|
|
|
|
> The port to bind to, by default 1965.
|
|
|
|
|
2020-11-06 18:11:45 +01:00
|
|
|
**-x** *dir*
|
2020-11-06 13:01:31 +01:00
|
|
|
|
2020-11-06 18:11:45 +01:00
|
|
|
> Enable execution of CGI scripts inside the given directory (relative
|
|
|
|
> to the document root.) Cannot be provided more than once.
|
2020-11-06 13:01:31 +01:00
|
|
|
|
|
|
|
# CGI
|
|
|
|
|
2020-11-06 18:11:45 +01:00
|
|
|
When CGI scripts are enabled for a directory, a request for an
|
|
|
|
executable file will execute it and fed its output to the client.
|
2020-11-06 13:01:31 +01:00
|
|
|
|
2020-11-06 18:12:57 +01:00
|
|
|
The CGI scripts will inherit the environment from
|
|
|
|
**gmid**
|
|
|
|
with these additional variables set:
|
|
|
|
|
|
|
|
`SERVER_SOFTWARE`
|
|
|
|
|
|
|
|
> "gmid"
|
|
|
|
|
|
|
|
`SERVER_PORT`
|
|
|
|
|
|
|
|
> "1965"
|
|
|
|
|
2020-11-10 14:07:36 +01:00
|
|
|
`SCRIPT_NAME`
|
|
|
|
|
|
|
|
> The (public) path to the script.
|
|
|
|
|
|
|
|
`SCRIPT_EXECUTABLE`
|
|
|
|
|
|
|
|
> The full path to the executable.
|
|
|
|
|
|
|
|
`REQUEST_URI`
|
2020-11-06 18:12:57 +01:00
|
|
|
|
2020-11-10 14:07:36 +01:00
|
|
|
> The user request (without the query parameters.)
|
2020-11-06 18:12:57 +01:00
|
|
|
|
2020-11-10 14:07:36 +01:00
|
|
|
`REQUEST_RELATIVE`
|
2020-11-06 18:12:57 +01:00
|
|
|
|
2020-11-10 14:07:36 +01:00
|
|
|
> The request relative to the script.
|
2020-11-06 18:12:57 +01:00
|
|
|
|
|
|
|
`QUERY_STRING`
|
|
|
|
|
2020-11-10 14:07:36 +01:00
|
|
|
> The query parameters.
|
2020-11-06 18:12:57 +01:00
|
|
|
|
2020-11-10 14:07:36 +01:00
|
|
|
`REMOTE_HOST`
|
2020-11-06 18:12:57 +01:00
|
|
|
|
2020-11-10 14:07:36 +01:00
|
|
|
> The remote IP address.
|
|
|
|
|
2020-12-02 15:17:19 +01:00
|
|
|
`REMOTE_ADDR`
|
|
|
|
|
|
|
|
> The remote IP address.
|
|
|
|
|
2020-11-10 14:07:36 +01:00
|
|
|
`DOCUMENT_ROOT`
|
|
|
|
|
|
|
|
> The root directory being served, the one provided with the
|
|
|
|
> *d*
|
|
|
|
> parameter to
|
|
|
|
> **gmid**
|
|
|
|
|
2020-12-02 15:17:19 +01:00
|
|
|
`AUTH_TYPE`
|
|
|
|
|
|
|
|
> The string "Certificate" if the client used a certificate, otherwise unset.
|
|
|
|
|
|
|
|
`REMOTE_USER`
|
|
|
|
|
|
|
|
> The subject of the client certificate if provided, otherwise unset.
|
|
|
|
|
|
|
|
`TLS_CLIENT_ISSUER`
|
|
|
|
|
|
|
|
> The is the issuer of the client certificate if provided, otherwise unset.
|
|
|
|
|
|
|
|
`TLS_CLIENT_HASH`
|
|
|
|
|
|
|
|
> The hash of the client certificate if provided, otherwise unset.
|
|
|
|
> The format is "ALGO:HASH".
|
|
|
|
|
2020-11-10 14:07:36 +01:00
|
|
|
Let's say you have a script in
|
|
|
|
*/cgi-bin/script*
|
|
|
|
and the user request is
|
|
|
|
*/cgi-bin/script/foo/bar?quux*.
|
|
|
|
Then
|
|
|
|
`SCRIPT_NAME`
|
|
|
|
will be
|
|
|
|
*/cgi-bin/script*,
|
|
|
|
`SCRIPT_EXECUTABLE`
|
|
|
|
will be
|
|
|
|
*$DOCUMENT\_ROOT/cgi-bin/script*,
|
|
|
|
`REQUEST_URI`
|
|
|
|
will be
|
|
|
|
*/cgi-bin/script/foo/bar*,
|
|
|
|
`REQUEST_RELATIVE`
|
|
|
|
will be
|
|
|
|
*foo/bar and*
|
|
|
|
`QUERY_STRING`
|
|
|
|
will be
|
|
|
|
*quux*.
|
2020-11-06 18:12:57 +01:00
|
|
|
|
2020-10-02 19:39:00 +02:00
|
|
|
# EXAMPLES
|
|
|
|
|
|
|
|
To quickly getting started
|
|
|
|
|
|
|
|
$ # generate a cert and a key
|
|
|
|
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem \
|
|
|
|
-out cert.pem -days 365 -nodes
|
|
|
|
$ mkdir docs
|
|
|
|
$ cat <<EOF > docs/index.gmi
|
|
|
|
# Hello world
|
|
|
|
test paragraph...
|
|
|
|
EOF
|
|
|
|
$ gmid -c cert.pem -k key.pem -d docs
|
|
|
|
|
2020-11-06 18:12:57 +01:00
|
|
|
Now you can visit gemini://localhost/ with your preferred gemini
|
2020-11-06 18:11:45 +01:00
|
|
|
client.
|
|
|
|
|
|
|
|
To add some CGI scripts, assuming a setup similar to the previous
|
2020-11-06 18:12:57 +01:00
|
|
|
example, you can
|
2020-11-06 18:11:45 +01:00
|
|
|
|
|
|
|
$ mkdir docs/cgi-bin
|
|
|
|
$ cat <<EOF > docs/cgi-bin/hello-world
|
|
|
|
#!/bin/sh
|
2020-11-06 18:12:57 +01:00
|
|
|
printf "20 text/plain\r\n"
|
2020-11-06 18:11:45 +01:00
|
|
|
echo "hello world!"
|
|
|
|
EOF
|
2020-11-06 18:12:57 +01:00
|
|
|
$ gmid -x cgi-bin
|
2020-11-06 18:11:45 +01:00
|
|
|
|
2020-11-06 18:12:57 +01:00
|
|
|
Note that the argument to the
|
2020-11-06 18:11:45 +01:00
|
|
|
**-x**
|
|
|
|
option is
|
|
|
|
*cgi-bin*
|
|
|
|
and not
|
|
|
|
*docs/cgi-bin*,
|
2020-11-10 14:07:36 +01:00
|
|
|
since it's relative to the document root.
|
2020-10-02 19:39:00 +02:00
|
|
|
|
2021-01-09 21:32:23 +01:00
|
|
|
# ACKNOWLEDGEMENTS
|
|
|
|
|
|
|
|
**gmid**
|
|
|
|
uses the "Flexible and Economical" UTF-8 decoder written by
|
|
|
|
Bjoern Hoehrmann.
|
|
|
|
|
2020-10-02 19:39:00 +02:00
|
|
|
# CAVEATS
|
|
|
|
|
2020-10-03 17:49:09 +02:00
|
|
|
* it doesn't support virtual hosts: the host part of the request URL is
|
2020-10-02 19:39:00 +02:00
|
|
|
completely ignored.
|
|
|
|
|
2020-12-25 13:15:15 +01:00
|
|
|
* a %2F sequence in the path part is indistinguishable from a literal
|
|
|
|
slash: this is not RFC3986-compliant.
|
|
|
|
|
2020-12-26 00:37:43 +01:00
|
|
|
* a %00 sequence either in the path or in the query part is treated as
|
|
|
|
invalid character and thus rejected.
|
|
|
|
|