-- Leo's gemini proxy

-- Connecting to skyjake.fi:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini;charset=utf-8;lang=en

GmCapsule: Extensible Gemini/Titan Server


skyjake.fi:1965 now runs on GmCapsule, a Python-based Gemini server that I recently started working on.


I've been relying on Agate since the beginning, but now I increasingly want to serve dynamic content and handle more advanced requests, so it was time to upgrade instead of running little ad-hoc servers on side ports.

Agate: Simple Gemini server for static files


During the past several months I've been working on two such servers:

Gemlog Booster (Titan uploads)

GmGitView: Git Repository Viewer

These both were written in Python, and together they provided a nice basis on which to construct a more full-featured server.


Modular


Using Python means things can get very flexible and dynamic. The design is modular: the core part of the server just receives incoming connections and hands them off to worker threads, and one of the loaded extension modules gets to actually process each request.


The two default modules handle serving static files from disk and executing CGI programs:


The static file module behaves pretty much like Agate. It serves files from a content directory and tries to autodetect MIME types using Python's "mimetypes" and the system `file` utility. It also supports ".meta" files with special instructions for given path wildcards. With that you can define redirects, "Gone" responses, and customized media types.

The CGI module is quite powerful: it supports both Gemini and Titan and can run arbitrary shell commands and external programs to generate dynamic content and process data uploaded from the client. As there is no spec for Gemini CGI variables, I used RFC 3875 section 4.1 as a reference. With Titan, the uploaded content is provided via stdin and additional environment variables provide the MIME type and token.


With the CGI module alone you could already do all kinds of fancy services, but GmCapsule can also load user-provided Python modules for more tightly-integrated functionality. These are useful particularly when it's beneficial to keep some state live in RAM between serving requests, or to define more advanced server behavior like caching some subset of pages.


Other features


Virtual hosts can be defined, although each instance of GmCapsule runs on a single port and uses a single server certificate. The certificate therefore needs a SAN field for each virtual host. My virtual hosts are currently skyjake.fi and git.skyjake.fi.

Information about client certificates is provided to CGI scripts, and includes two fingerprints: one for the full certificate and another for its public key. This enables the script to authorize usage based on either as appropriate, providing a way for users to switch certificates if they keep their old key pair.

Caching is a core feature, meaning that individual extension modules don't have to implement it separately. When processing a request, all the registered caches are checked to see if they provide a valid copy of the content.

GmGitView's Markdown-to-Gemini converter is incorporated into the server, although currently not applied to anything in the static file module. Extension modules (like GmGitView itself) are free to use it when appropriate.


Porting the old services


As part of the migration process, the old Gemlog Booster and GmGitView servers became a CGI script and an extension module, respectively. In both cases, the code was rather nicely simplified as they no longer need to worry about listening to and parsing incoming requests.


Currently these are available in the "capsule" branches of their respective Git repositories. These will eventually replace the original implementations. The code can be seen here if interested:

Gemlog Booster CGI script

GmGitView module


Of particular interest may be the `init(capsule)` function at the end of 50_gmgitview.py, where the module initializes its cache and URL entrypoints.


Next steps


GmCapsule is still nascent so it isn't ready for a public release.


The current plan is to release GmCapsule as a Python package installable via `pip`. However, I do have earlier experience packaging Python applications as standalone executables, so that is also an option. On some platforms (looking at you, Windows), this might be the preferable distribution method.


I'm planning to include a convenient setup script that handles generating a certificate and the basic configuration file, to make things a little easier. Before this, though, I need to observe how the server holds up over a longer period of time and see if there are any serious bugs that need fixing.


skyjake

📅 2022-01-25

🏷 GmCapsule

🏷 Gemini

CC-BY-SA 4.0


skyjake's Gemlog

-- Response ended

-- Page fetched on Tue Apr 23 11:19:20 2024