blog | notes | apps

Set up a server for a static Web site and a Gemini capsule

This is how I set up the site/capsule you are on right now. There are hosting providers that specialize in static sites, and there are docker containers for popular servers, but I prefer to set everything up myself, natively, and as simple as possible. Perhaps someone might find this guide useful, too.

Obtain hosting

I lease a small VPS (virtual private server) from Linode - Nanode (1 shared CPU, 1 GB RAM, 25 GB storage, 1 TB transfer total per month) for $5 a month


DigitalOcean is another popular hosting provider


It is possible to host from home, even using a residential internet connection. This might be against the service agreement, but I did not find anything about it with my ISP. Although your residential IP can change, in my experience, it stayed the same for months if not years.

Create a server

Log into your hosting provider (Linode) and request a new VPS instance (Nanode). Choose an OS you prefer. Ubuntu 22.04 LTS is probably the most well-known and supported, and Debian 11 is probably the most stable. Set a strong password since it gives you root access.

Your hosting provider will assign you a VPS with a unique IP address.

(I will refer to your server's IP address as your.server.ip.address)

Register a domain

If you want your site/capsule to be accessible by name (yaky.dev) and not just the IP (, and to obtain proper security certificates, you need to register a domain and point it at your.server.ip.address.

I purchased my domain name from Porkbun.


(I will refer to your registered domain as your.domain)

Log into your server

Assuming you are on a Linux machine:

ssh root@your.server.ip.address


ssh root@your.domain

On Windows, you can use PuTTY

PuTTY for Windows

This login method will work for now. However, a good security practice would be:

- Change SSH port (bots will try to log in on port 22 all the time)

- Set up login using an SSH key (it's more convenient, too)

- Disable password-based login

- Create a user with limited privileges and disable root login altogether

NOTE: All further commands on this page are assumed to be run as root (whether you are logged in as root, or use sudo)

Update the system

Good idea to update everything before installing additional software.

Assuming you are logged in as root on Debian or Ubuntu:

apt update
apt upgrade

If you want a text editor with more familiar Windows-like shortcuts (Ctrl-Z to undo, Ctrl+X/C/V for clipboard), install micro:

apt install micro

And then use micro instead of nano in further commands.

Obtain certificates

Let's Encrypt is a great, popular, and free certificate authority

Install certbot

apt install certbot

Tell certbot to obtain a certificate. There is an option for different web servers, but I prefer the certificate-only option, which will place the certificates in a shared directory such that they can be used by multiple services at once.

certbot certonly

Choose "1: Spin up a temporary webserver (standalone)" and follow prompts. Certificates will be saved to


Let's Encrypt certificates are valid for 90 days, and have to be renewed after 75 days. To renew:

certbot renew

Installing a static site server

For serving static web pages I use... nginx. Odd choice since it's primarily a reverse proxy, but it works well with other hosted services that use HTTP/HTTPS.

First, install nginx:

apt install nginx

Then, create a separate config for your server:

nano /etc/nginx/conf.d/your.domain.conf

This is how my nginx config looks

# HTTP site
# Redirect HTTP to HTTPS
server {
        server_name your.domain;

        listen 80;
        listen [::]:80;

        return 301 http://$host$request_uri;

# HTTPS site
server {
        server_name your.domain;

        listen 443 ssl;
        listen [::]:443 ssl;

        ssl_certificate         /etc/letsencrypt/live/your.domain/fullchain.pem;
        ssl_certificate_key     /etc/letsencrypt/live/your.domain/privkey.pem;

        # Default website hosting directory is /var/www
        # I use /srv/www for static web pages
        # so Gemini content can go into /srv/gemini
        location / {
                root /srv/www;

        # Logs for troubleshooting
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log error;

Now you can put your web content into /srv/www and it should be available on https://your.domain

If you run into issues, restart nginx

systemctl restart nginx

Installing a Gemini capsule server

There are many Gemini servers out there. I have used gmnisrv and Agate, both of which are simple to set up and work well.

Gemini software



I will use Agate as it has a few more features and has been reliable for me in the past.

Get the pre-compiled binary (thank you, Matt Brubeck), unzip it, move to the proper directory and set the executable flags

wget https://github.com/mbrubeck/agate/releases/download/v3.2.4%2Bbuild/agate.x86_64-unknown-linux-gnu.gz
gunzip agate.x86_64-unknown-linux-gnu.gz
mv agate.x86_64-unknown-linux-gnu /usr/local/bin/agate
chmod +x /usr/local/bin/agate 

To make life easier, set up Agate to run as a systemd service, which will automatically launch Agate when server starts and automatically restart it if it fails.

First, create the service:

nano /etc/systemd/system/agate.service

Define the service:

Description=Agate Gemini Server

ExecStart=agate --hostname your.domain --content /srv/gemini --certs /etc/letsencrypt/live/your.domain --lang en-US


Reload the system service definitions and enable the new service

systemctl daemon-reload
systemctl enable agate
systemctl start agate

Now you can place your Gemini content in /srv/gemini and it should be available on gemini://your.domain

Building content

If you like Gemini markup and want to create a static web site along with your Gemini capsule, consider using my Cosmodrome tool. It takes pages in .gmi syntax, builds HTML pages and wraps them in header/footer.

Cosmodrome on GitHub

Other useful tools and services


Remote sync utility to incrementally sync files between two machines. Needs to be installed on both your local machine and the server. As an a example, run this command on your local machine to sync the 'srv' directory on your local machine to the '/srv' directory on the server:

rsync -rP srv/ root@your.domain:/srv/


This utility check for frequent login attempts and bans offending IPs for incrementally longer periods.

If you want to see who is attempting to connect to your server, run

journalctl -e

If you rent a VPS, most likely it will be polluted with bad login attempts.

Install fail2bad on Debian and Debian-derived systems:

apt install fail2ban

Default config is quite sufficient and works very well.

Check log:

tail /var/log/fail2ban.log

Check status and which IPs are currently banned:

fail2ban-client status sshd

Now you have a bit more of a peace of mind.