author

Minimalism, Linux, Self-Hosting, .NET, Go, Python, Philosophy, Psychology, Privacy, Security.

Join us on XMPP!
Her.st Propaganda Stream

the atlas launch rocket for gemini capsules.
the atlas launch rocket for gemini capsules.

introducing: atlas - my gemini server

Atlas is a gemini server without any dependencies. It works on x86, x64 and ARM64. Linux is supported and Windows/MacOS should work fine too - but I don’t know since I don’t use either. The name refers to the launch rocket used to launch the gemini capsules into space.

Features

  • C#/net7
  • gemini://
  • titan://
  • spartan://
  • CGI
  • VHOST
  • Simple configuration
  • Docker

gemini://

After a week of trial and error with the occasional look at the documentation, I’ve finished the first version of atlas. The gemini protocol is super easy to understand and implement but the other features I wanted were not :D

There’s no way to upload anything using gemini. The best you can do is to use the INPUT request to pass query strings to the server.

titan://

So there’s a companion protocol called Titan which allows you to upload files. The Titan protocol uses the same status codes as gemini and works just fine in-band.

gemini:// and titan:// are pretty much the same, titan just adds a filename and size parameter inside the META section of the request. Very easy to parse.

spartan://

Spartan was a bit more involved, as it’s not compatible with gemini. It uses a different default port and no encryption. Also the status codes are not identical to those of gemini. I’ve had to open another socket for spartan and write custom handlers for all the different requests. Although the protocol itself is very similar to gemini - simpler really - it is different enough to require a second codepath for parsing requests and sending responses.

vhosts

Gemini Virtual-Hosts can be easily implemented by looking at the SNI parameter in the TLS handshake, spartan doesn’t use TLS, so they put the hostname into the request header - no problems there.

cgi-bin

CGI scripting was super easy too, just a bunch of different environment variables that get passed to the script and its output redirected to the user’s browser. Authorisation and authentication can be done using the client certificate when the request comes from gemini. If the request comes from spartan however, the script has to do the heavy lifting. Maybe there shouldn’t be any authorization or authentication with spartan since its a plaintext protocol and passwords or tokens would be suseptible to MITM attacks.

directory index

Directory Listing was implemented directly in the server and creates a nicely spaced list of files. I’ve not done directory navigation yet though. That shouldn’t be too hard though.

config

For configuring atlas, i’ve settled on a simple JSON file.

{
  "Port": 1965,
  "Capsules": {
    "sallsave.net": {
      "AbsoluteRootPath": "/srv/gemini/sallsave.net/",
      "AbsoluteTlsCertPath": "/srv/gemini/sallsave.net/sallsave.net.pfx",
      "FQDN": "sallsave.net",
      "Index": "index.gmi",
      "Locations": [
        {
          "AbsoluteRootPath": "/srv/gemini/sallsave.net/",
          "Index": "index.gmi",
        }
      ]
    },
    "evilcorp.net": {
      "AbsoluteRootPath": "/srv/gemini/evilcorp.net/",
      "AbsoluteTlsCertPath": "/srv/gemini/evilcorp.net/evilcorp.net.pfx",
      "FQDN": "evilcorp.net",
      "Index": "index.gmi",
      "MaxUploadSize": 4194304,
      "Locations": [
        {
          "AbsoluteRootPath": "/srv/gemini/evilcorp.net/",
          "Index": "index.gmi",
        },
        {
          "AbsoluteRootPath": "/srv/gemini/evilcorp.net/cgi/",
          "Index": "script.csx",
          "CGI": true,
          "RequireClientCert": true,
        },
        {
          "AbsoluteRootPath": "/srv/gemini/evilcorp.net/files/",
          "Index": "index.gmi",
          "DirectoryListing": true,
          "AllowFileUploads": true,
          "AllowedMimeTypes": {
            "text/*": {
              "MaxSizeBytes": 1048576
            },
            "image/*": {},
            "audio/mpeg": {},
            "audio/ogg": {},
            "audio/wave": {}
          }
        }
      ]
    }
  }
}

I took some inspiration from nginx there and since gemini, spartan and titan rely heavily on mimetypes, I’ve added a TSV file of mimetypes that can be easily edited by hand.

docker

To make deployment easy, I’ve added docker support. you can pull it from dockerhub

docker pull herstfortress/atlas:latest

make sure you mount two volumes, one for /srv and one for /etc the config belongs in /etc/atlas/config.json and the capsules in /srv/gemini/my.capsule.com/

code

The code can be found on github

That’s basically it for now.

You can check out a demo at:

gemini://ec.her.st/

spartan://ec.her.st/

author

trbl

I love simplicity and minimalism. I'm an autodidact and taught myself everything I know. I hate the 'educational system' and never did my homework. I have no tolerance for stupid.

> ./mail > ./feed