Here I explain how to set up a gemini:// server, which is known as a capsule.
If you don’t know what gemini:// is, essentially it is a text-only https:// alternative.
It allows you to browse text only feeds, and is a welcome escape from ads and javascript and bloat.
Gemini in general does not support anything except for pure text. There is no CSS, no JavaScript, nothing, except for text and sometimes images (but not in-line, you have to click them).
It is considered an alternative to the web, seen as “better/superior” because it forces minimalism, however it is a bad comparison.
The issue with modern web is the invasiveness, not the CSS or JS (although JS sucks); in this regard, I prefer my site being static and served over the web where I can use CSS, than gemini, where in the name of “minimalism” I have to give up expressive liberty.
Be that as it may, it’s nice to have options, plus the minimalism might appeal to some, or might enable a “rehab” sentiment.
setup #
The nixos configuration is a bit more difficult because of how simple gemini servers are. This simplicity means that we need to set up our own user, open the port (since nginx is a web server, it can’t work with gemini://), and set up autosync so we don’t need to sync files manually with git.
specs #
There are many servers to host; the gemini:// protocol is extremely simple, and so servers can take ~200-500 lines of code, and are extremely lightweight.
This guide sets up agate since it’s a service in nixos.
We start by making a folder gemini and gemini/default.nix
$ mkdir gemini && touch gemini/default.nix(or use the file explorer of your choice)
nix declaration #
Open gemini/default.nix in any text editor, and copy the following
{ config, pkgs, lib, ... }:
{
services.agate = {
enable = true;
hostnames = [ "<YOUR-DOMAIN>" ];
addresses = [ "0.0.0.0:1965" ];
language = "en";
contentDir = "/srv/gemini";
};
networking.firewall.allowedTCPPorts = [ 1965 ];
users = {
groups.agate = { };
users = {
agate = {
isSystemUser = true;
description = "gemini user";
group = "agate";
home = "/srv/gemini";
createHome = true;
shell = "${pkgs.git}/bin/git-shell";
};
};
};
systemd = {
# set service
services."gemini" = {
description = "Update Gemini site from repo";
script = ''
if [ -d /srv/gemini/.git ]; then
${pkgs.git}/bin/git -C /srv/gemini pull
else
${pkgs.git}/bin/git clone https://<YOUR-GEMINI-REPOSITORY> /srv/gemini
fi
'';
serviceConfig = {
Type = "oneshot";
User = "agate";
};
};
timers."gemini" = {
description = "Hourly Gemini-site update";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "hourly";
Persistent = true;
};
};
};
}Then to enable it, just include it in the server config file:
imports = [
# ... other services
./gemini
# ... other services
];and you’re done.
Make sure to replace
<YOUR-GEMINI-REPO>with your actual gemini repo above
Let’s break the config file down.
explanation #
- We declare the
agateservice as enabled. - We define the hostname for the
gemini://network, set the address(es) to serve from, and declare the language we will be writing in. Finally we declare the content directory - We open port 1965 to the internet
- We declare a group
agate - We declare a user
agate, in groupagate, with the home folder being atsrv/gemini, having access only to the git shell, for security. - We declare a
systemdservice,gemini, that checks if/srv/geminiis a git repo; if it isn’t itgit cloneat a specified repository, if it is, it runsgit pull. This service is set to run once (not continuously), and to be run by useragate - We declare a timer that runs the
geminiservice we just declared, once per hour. This automates the setup
adding content #
In order to add content to your new capsule, simply go to the content/ folder and start writing.
By default gemini:// serves the index.gmi at <YOUR-DOMAIN>/, so make that file first.
.gmiis the markup flavour that gemini reads/serves.
It is a stripped down version of markdown (.mdfiles).
You can find out more about it here
Since servers simply serve .gmi files, you don’t need to do any update/reload or anything. It happens automatically.
Personally, I use git to keep files synced (as in, the content folder is a git repo).
client #
In order to browse gemini:// you need a dedicated client.
Use Lagrange.