-- Leo's gemini proxy

-- Connecting to alexey.shpakovsky.ru:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

Gemini server in bash

> Originally posted: 2022-01-28 ~ Last updated: 2022-02-07


As a follow-up to my previous post which mentioned writing a simple 1-line HTTP server in bash, @ruario later mentioned that someone already implemented a Gemini server in bash:

Ad-hoc served gemini file by tomasino

@ruario


Preserved here for future reference, here is the simplest Gemini server which just "echoes" your request back:


ncat --ssl --ssl-cert cert.pem --ssl-key key.pem -lk 1965 -c 'read -r req; echo -e "20 text/gemini\r\n$req";'

And just to confirm Ainent's words on how simple it is to make a gemini server, I've created my own one. Just in two evening, based on the one-liner above, bash (actually plain shell) server, serving static files!



Decoding of percent-encoded request - so, say, your request for `a%20story.gmi` will return content of the file named `a story.gmi`.

Mime-type detection either via file extension or with help of `file` utility - so, say, images will be rendered correctly.

Redirecting user browser to URL with slash at the end when a directory is requested without trailing slash - this is needed for relative links to work correctly. Otherwise, when a page `/some/stuff` has a link to `other` page, browser will assume it's a link to `/some/other` instead of `/some/stuff/other`.

Reading `index.gmi` files when a directory is requested.

virtual hosts


it

It's hosted on github in my "containers" repo, but you can also get it by direct HTTP link.

containers repo on Guthub

direct link to plain server.sh


To run the server in "proper gemini" mode (with encryption), use ncat like this:


ncat --ssl --ssl-cert cert.pem --ssl-key key.pem --listen 1965 -c ./server.sh --keep-open

To run it in "insecure gemini" mode (talking gemini protocol over unencrypted connection), busybox nc is enough:


busybox nc -lk -p 1964 -e ./server.sh

In my setup, the server is running in its own separate Docker container, which has nothing else apart from Alpine Linux installation, the server itself, and directory with public gmi files. It doesn't even have certificate and key for the ssl encryption - this part is managed by nginx proxy server, running in another container.


Testing


I assume that there might be deficiencies or vulnerabilities in this server, so I welcome everyone to test it and share your findings - privately or publicly. Just please try to avoid DDoSing it for long periods of time (in order not to annoy my VPS provider), and if you find something serious - give me some time to fix it before announcing it publicly, please ;)


If it helps, the OS is vanilla Alpine Linux, and you can get into a similar one just by running `docker run --rm -it alpine` on your own machine.


Changelog

This article was updated serveral times.


Update 2

Initially this server was shipped with a known path traversal vulnerability. Since I'm running it in a separate container, this server can read only files from vanilla Alpine Linux installation, publicly available *.gmi files, and itself.


Update 1

However later Martin Bays and @ruario pointed out that it's not a good idea to have access logs (containing potentially private information) available to everyone. So I've moved the logging part to a separate container, which now sits between nginx and gemini server. This article was updated accordingly.


Update 2

Following common trend in the beginning of February 2022, I've decided to close the path traversal vulnerability. This article was updated accordingly.


Update 3

After previous update, server was configured to print its own source code when a path traversal attempt was detected. Now that it's available on github, it doesn't need to do so. This article was update accordingly.


-- Response ended

-- Page fetched on Wed May 22 02:13:59 2024