Troubleshooting & How-Tos

Quick Start: Setting up Gemini on a VPS Without Root


Update April 2021:

  1. Agate now manages the TLS certificates for you.
  2. How to launch on boot using cron

To start experimenting with Gemini, I decided I wanted to use the same domain as my website, and I wanted to keep things simple to start with. I have my website on a VPS at DreamHost. It’s still managed, so I don’t have root access like I would on a DreamCompute instance, but I have more control than I would on shared hosting. In particular, they don’t put time limits on processes on a VPS.

After looking around a bit I decided on Agate for simplicity. Agate only serves static files, but that’s certainly fine not a problem to start with! So I created a new user on the VPS, gave it SSH access, and set up Agate on it.

Installing Agate on DreamHost

The Agate home page and Chris Were’s guide to setting up a gemini server (as a systemd service) helped me get started:

First, download the latest pre-built binary from Github for x86_64 Linux. (DreamHost doesn’t have Rust on their VPSes, but they do have wget.)

wget (full URL to latest version of agate.x86_64-unknown-linux-gnu.gz)

It’s a gzipped executable, so you need to decompress it:

gunzip agate.x86_64-unknown-linux-gnu.gz

You don’t have to rename it, but it’s convenient to rename the file as just “agate”. Ready for launch? Well…not quite.

Launch Prep

Creating a systemd service would be cleaner, and if you have root or sudo access, I’d recommend looking at Chris Were’s guide (linked above) to do that. But if you can’t do that, you can create a shell script with Agate’s config options:

(/path/to/)agate --content /home/(username)/content/ \
--addr [::]:1965 \
--addr \
--certs /home/(username)/.certificates/ \
--hostname ( \
--lang en-US

Then run “./ &” to run it in the background and let it stay running after you log out.

Now, you can place an index.gmi Gemtext file in the content directory, and you have liftoff!

Configuration Notes

For multiple hostnames sharing the same content, leave out the --hostname option.

For multiple hostnames with different content, specify more than one --hostname option and create a directory for each inside the content directory.

(Side note: Agate 3.0 and 3.0.1 used a certificate signature method that wasn’t compatible with Android clients like Ariane or Deedum. The --ecdsa option would choose a more widely compatible signature scheme. Since Agate 3.0.2, it’s the default, so you don’t need to include the option anymore.)

Also, be sure you specify a certificates directory. Otherwise it will look for .certificates inside the current working directory you’re at when you launch Agate, which is not likely to be consistent, and you’ll end up with multiple different certificates scattered around your account!


Now you have a working Gemini capsule! But you probably don’t want to log in and relaunch it the next time your server reboots. What to do without root access? Cron to the rescue! You can use cron to launch your shell script on boot (Thanks, FiXato, for pointing me to this technique) by putting this in your crontab file:

@reboot (/path/to/) &

On DreamHost, you’ll have to use the control panel to create the crontab entry. Look in the “More” section for “Cron Jobs” and choose “Server Reboot” for the “When to run” option.

Managing the Capsule

So now I have sites available at both:

Relative links work just like they do on a website, so linking to “some-file-in-the-same-folder.gmi” or “./” or “../” or “/” or “/some-file-in-the-root-folder.gmi” work as expected. (Mostly. Some client software still gets confused with “./”, but that’ll settle out over time.)

At this point it’s basically the same as managing a website. You can use SFTP or any other method for uploading files. I decided to automate the uploads with rsync over SSH. I created this script on my local computer:

rsync -avzhe ssh ~/gemini/ (username)@(hostname):content/ --delete

The trailing slashes on both the source and target path mean that they don’t have to have the same name. Otherwise it would try to create a “gemini” folder inside the “content” folder. The --delete option means that it will remove any remote files that I’ve removed from the local copy.

Downside: I can only manage my Gemini capsule from one computer for now, unless I make the effort to remember to download any changes I’ve made on the server before I sync it again. It really is like the old days of the web!