removing incorrect usage of errno from error logging
got get_path and get_raw_path, don't read the path if the URI is null
show the Lua version in help text
MoonGem is a Gemini protocol server written in C. It supports serving static files as well as Gemtext (.gmi) files with inline Lua scripting.
An example page might look like this:
# Example 1
Lua scripts are enclosed by double curly-braces.
{{ for i = 1, 10 do mg.line(i) end }}
# Example 2
If a script returns a string, that string will be written to the page verbatim.
{{ return "Meow!" }}
# Example 3
{{
mg.head("Script blocks may span multiple lines", 2)
mg.line("There are several methods that modify response headers")
mg.set_language("en-US")
}}
git clone https://git.panda-roux.dev/MoonGem
cd MoonGem && git submodule update --init
cmake -B build . && cd build
make && sudo make install
Usage: moongem [options] --cert=cert.pem --key=key.pem
or: moongem [options] -c cert.pem -k key.pem
A Gemini server with inline Lua scripting for generating dynamic content
-h, --help show this help message and exit
Cryptography
-c, --cert=<str> (required) certificate file path (.pem)
-k, --key=<str> (required) key file path (.pem)
Network
-p, --port=<int> port to listen for Gemini requests on (default: 1965)
Content
-r, --root=<str> root directory from which to serve content (default: current)
-c, --chunk=<int> size in bytes of the chunks loaded into memory while serving static files (default: 16384)
Middleware
-b, --before=<str> script to be run before each request is handled
-a, --after=<str> script to be run after a request has resulted in a success response code (20)
-e, --error=<str> script to be run after a request has resulted in an error response code (40 thru 59)
# clone the repository
git clone https://git.panda-roux.dev/MoonGem && cd MoonGem
# generate a self-signed certificate
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -nodes -subj "/CN=localhost"
# create a document
echo "Hi you!" > index.gmi
# allow the container to read files
chmod 644 *.pem
chmod 644 index.gmi
# start the container
docker-compose up
The start and end of script sections are indicated with a double curly-braces.
{{
}}
All of the MoonGem-defined functionality is contained within a table called mg
.
These methods are only accessible from pre-request scripts.
mg.set_path([new-path])
/
if one is not providedmg.set_input([new-input])
mg.interrupt()
MoonGem implements an in-memory key/value store accessed via the mg.store
table. This feature is useful for establishing state that's persistent across multiple requests.
#mg.store
mg.store.dump([path])
path
, or stdout if path
is ommittedmg.store.get_info()
length
: The number of stored key/value pairscapacity
: The total number of slots allocateddata_size
: The combined length of all of the stored values, in bytesThese methods modify the body of the Gemini page.
mg.include(<file-path>)
mg.write(<text>)
text
to the pagemg.line([text])
text
to the page followed by a line breakmg.link(<url>, [text])
url
on the page, and optionally includes the alt-text text
mg.head(<text>, [level])
text
to the page, with an optional header levelmg.quote(<text>)
text
in a quotation line to the pagemg.block(<text>)
text
in a preformatted block to the pagemg.begin_block([alt-text])
alt-text
mg.end_block()
mg.begin_block
These methods modify the response header.
If a method is called which modifies the response's status code (which all but the first of these do), then no further scripts will be run and the server will send the response immediately.
mg.set_language(<language>)
lang
portion of the response header, indicating the language(s) that the page is written inmg.set_mimetype(<mimetype>)
text/gemini; charset=utf-8
.mg.success()
mg.temp_redirect(<url>)
url
mg.redirect(<url>)
url
The following methods each causes the server to respond with one of the status codes in the 40 to 60 range. An optional meta
string may be appended to the response in order to provide the client with more information.
mg.temp_failure([meta])
mg.unavailable([meta])
mg.cgi_error([meta])
mg.proxy_error([meta])
mg.slow_down([meta])
mg.failure([meta])
mg.not_found([meta])
mg.gone([meta])
mg.proxy_refused([meta])
mg.bad_request([meta])
mg.cert_required([meta])
mg.unauthorized([meta])
These methods are concerned with handling user-input.
mg.get_path()
mg.get_raw_path()
mg.get_input([meta])
meta
stringmg.get_sensitive_input([meta])
mg.get_input
, but uses status code 11mg.has_input()
true
if there was an input argument included in the requestfalse
mg.get_cert([meta])
fingerprint
: a string representing an SHA256 hash of the certificate's modulus in hexadecimal formatnot_after
: a unix timestamp representing the expiration time of the certificatemeta
string
mg.has_cert
to check whether one exists before calling this method in order to avoid the code-60 responsemg.has_cert()
true
if a client certificate was included along with the requestfalse