About gemini markup and gmnisrv
Gemini is a simple protocol and markup for transmitting text pages on the internet. It is similar to http/html and improves on gopher.
With portal.mozz.us, one can surf gemini pages with a web browser.
I use gemini for the following reasons:
- the documents don't execute code
- there is minimal tracking (only ip address)
- the clients are lightweight and will that way
- the servers are lightweight
- I don't need to get a certificate from let's encrypt for my personal sites
- I can write my own server
Clients
On my phone, I tried:
- Elaho: iOS, good
- Deedum: iOS and Android, good
On the terminal, I used ncat:
apt-get install ncat
echo -ne 'gemini://gemini.circumlunar.space/\r\n'|ncat --ssl gemini.circumlunar.space 1965
The amfora tui client is also good.
Markdown to Gemini markup converter
I tried md2gemini, to install it, run:
apt-get install python3-pip
pip3 install md2gemini
To convert a markdown file, run:
md2gemini file.md > file.gmi
Setting up a Gemini server
I chose to run the gmnisrv gemini server, because it is lightweight and simple to build. It only depends on the openssl library.
I run the following commands:
git clone https://git.sr.ht/~sircmpwn/gmnisrv
sudo apt-get install libssl-dev
cd gmnisrv
mkdir build
cd build
../configure
make
sudo make install
I keep the default configuration, so everything is installed in /usr/local/
I create a home directory for gmnisrv:
mkdir -p /home/user/gemini/certs /home/user/gemini/root
I generate a gemtext file with md2gemini:
md2gemini README.md > ~/gemini/root/index.gmi
I copy the default configuration file:
sudo cp /usr/local/share/gmnisrv/gmnisrv.ini /usr/local/etc/gmnisrv.ini
I edit the config file:
sudo vi /usr/local/etc/gmnisrv.ini
The default config file looks like this:
# Space-separated list of hosts
listen=0.0.0.0:1965 [::]:1965
[:tls]
# Path to store certificates on disk
store=/var/lib/gemini/certs
# Optional details for new certificates
organization=gmnisrv user
[localhost]
root=/srv/gemini
I change the tls store path, the virtual server(to my local ip address) and the root for the virtual server:
# Space-separated list of hosts
listen=0.0.0.0:1965 [::]:1965
[:tls]
# Path to store certificates on disk
store=/home/user/gemini/certs
# Optional details for new certificates
organization=gmnisrv user
[192.168.0.2]
root=/home/user/gemini/root
gmnisrv sets the mine types looking at file extensions according to /etc/mime.types, I add JPG images:
image/jpeg jpeg jpg jpe jfif JPG
Then I start the server and test it:
gmnisrv
echo -ne 'gemini://192.168.0.2\r\n'|ncat --ssl 192.168.0.2 1965
I also tried the Moongem server, there is no need for a configuration file. The program takes certificate, key and document root in arguments.
Here is how to build it in debian bullseye:
apt-get install libmagic-dev libssl-dev liblua5.4-dev cmake
git clone https://git.sr.ht/~panda-roux/MoonGem
cd MoonGem && mkdir build && cd build
cmake ..
make
It doesn't generate a certificate automatically, so I generate one with the command (replace 'URL' with the server DNS address):
openssl req -new -x509 -days 365 -nodes -out cert -keyout key -subj "/CN=URL" -newkey rsa:4096 -addext "subjectAltName = DNS:URL"
To start the server, run:
./moongem cert key .
The gmid gemini server works fine but it doesn't send the images on my gemini pages.
Gemini markup: Gemtext
Here's the basics of how text works in Gemtext:
- Long lines get wrapped by the client to fit the screen
- Short lines don't get joined together
- Write paragraphs as single long lines
- Blank lines are rendered verbatim
You get three levels of heading:
# Heading
## Sub-heading
### Sub-subheading
You get one kind of list and you can't nest them:
* Mercury
* Gemini
* Apollo
Here's a quote from Maciej Cegłowski:
> I contend that text-based websites should not exceed in size the major works of Russian literature.
Lines which start with ``` will cause clients to toggle in and out of ordinary rendering mode and preformatted mode. In preformatted mode, Gemtext syntax is ignored so links etc. will not be rendered, and text will appear in a monospace font.
Write links like this:
=> URL Title
=> gemini://gmi.noulin.net Remy Noulin's Homepage
CGI configuration for gmnisrv
This section shows an example setup of cgi scripts, for more information read the man for gmnisrvini (install the scdoc package to convert gmnisrvini.scd to roff: scdoc < gmnisrvini.scd > gmnisrvini.roff && man -l gmnisrvini.roff)
- Create a route
example.comfor storing the gemtexts where cgi is off. The files in/srv/gemini/example.comare served according to their mime types. - Create a route
example.com/cgifor the executable programs where cgi is on. The files in/srv/gemini/example.com/cgiare executed and everyting printed to stdout is sent as a response to the client. - Start
gmnisrv
[example.com]
root=/srv/gemini/example.com
[example.com:/cgi]
root=/srv/gemini/example.com
cgi=on
Create the example.sh script and make the script executable with chmod 755 example.sh:
echo "20 text/gemini\r\n"
echo "PATH_INFO " $PATH_INFO
echo "QUERY_STRING " $QUERY_STRING
echo "SERVER_NAME " $SERVER_NAME
echo "REMOTE_USER " $REMOTE_USER
example.sh print the environment variables set by gmnisrv.
Now it is possible to call example.sh:
echo -ne 'gemini://example.com/cgi/example.sh\r\n'|ncat --ssl example.com 1965
echo -ne 'gemini://example.com/cgi/example.sh?Text%201024%20Bytes%20Max\r\n'|ncat --ssl example.com 1965
echo -ne 'gemini://example.com/cgi/example.sh/hello?world\r\n'|ncat --ssl example.com 1965
- On the first request,
PATH_INFOandQUERY_STRINGare empty strings - On the second request,
PATH_INFOis an empty strings andQUERY_STRINGequals toText 1024 Bytes Max. The%20strings in the query string are converted to space characters. - On the third request,
PATH_INFOis set tohelloandQUERY_STRINGis set toworld.
To receive an input from client, the script should respond with 10 Enter your text:\r\n instead of 20 text/gemini\r\n.
When the client sends the input, the script is called again and QUERY_STRING is the input from the client. Eventually the script responds with 20 text/gemini\r\n+gemtext to show the result of the client request.
To make a gemcall to an input endpoint (for example: example.com/cgi/submit), run this:
echo -ne 'gemini://example.com/cgi/submit?My%20input\r\n'|ncat --ssl example.com 1965
hashtags: #gemini