💾 Archived View for yuki.social › notes › 2022-07-12-vger-systemd-nginx.gmi captured on 2023-05-24 at 17:44:06. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

Use Vger with systemd and nginx

Vger is a secure Gemini server I recently switched to to serve my Gemini content. So why is it secure? It only does what it needs to do. Get a request from stdin, chroot in your gemini directory, send the file back to stdout. The socket thing and TLS are left as an excercise to the sysadmin.

More on this on the author's blog

Vger was intended to be used with inetd and be compatible with BSD, but if you're on Linux, you likely use systemd (love or hate it) and so you can leverage its security powers. It's pretty much inetd on steroids.

So the workflow here is:

Here's the config files I use:

/etc/systemd/system/vger@.service
[Unit]
Description=vger gemini server
Requires=vger.socket

[Service]
Type=simple
ExecStart=-/usr/bin/vger -d /srv/gemini/ -v -i # see man vger

# Set which user you want to run it as, or a random dynamic one
User=http
# DynamicUser=yes

# very important so it goes to the socket
StandardInput=socket
StandardOutput=socket
StandardError=journal # you can also set null here

# most of these are useless since vger takes cares about getting itself in a chroot but these instructions works for literally everything
ProtectHome=true
PrivateUsers=true
ProtectSystem=strict # Implied by DynamicUser=yes
PrivateTmp=true # Also implied by DynamicUser=yes
# read the systemd manpages, there's a ton of security features in there

[Install]
WantedBy=multi-user.target

Now create the socket service:

/etc/systemd/system/vger.socket
[Socket]
ListenStream=/run/vger.socket # could be a port number but an AF_UNIX socket is better
Accept=yes

[Install]
WantedBy = sockets.target

We can then use nginx to manage connections from port 1965 and encrypt them with TLS. Be sure to change the ssl_certificate paths if you don't have a Let's Encrypt certificate for every domain you want to serve, and make sure you don't put this inside a http block.

/etc/nginx/nginx.conf
stream {
        server {
                listen                  1965 ssl;
                listen                  [::]:1965 ssl;
                ssl_certificate         /etc/letsencrypt/live/$ssl_server_name/fullchain.pem;
                ssl_certificate_key     /etc/letsencrypt/live/$ssl_server_name/privkey.pem;
                proxy_pass              unix:/run/vger.socket;
        }
}

Now launch your services...

sudo systemctl enable vger.socket
sudo systemctl start vger.socket
sudo systemctl reload nginx

...et voilà, you have a Gemini capsule in the geminisphere, or whatever kids call it these days.

From here, the sky's the limit: you can create a socket for every virtualhost you want to serve and use $ssl_server_name to point to different sockets and certificates, maybe even make use of ALPN to serve HTTPS on the same port? Be creative!

Stay tuned for part 2 where I create a Gemini client to solve all of your problems! Maybe even a part 3 where I abuse ALPN? Who knows! Anyway, hope you liked this.

--Yuki

Read something else