1. How to host a Gemini capsule with Node and Nginx

    Project Gemini is a text-based web protocol, like a mash-up of TLS + Gopher. It's hyped as a "Small Internet" with outer space imagery, where instead of web sites, we have Gemini capsules. Some people love it, some people hate it, but it's there and I think it's kind of cool. Anyway, recently I was playing with it and I realized there aren't good docs on how to get it running with nginx. So here's a quick howto:

    1. Enable the nginx stream module

    Depending on your environment, you may need to install the nginx stream module (eg. sudo apt install libnginx-mod-stream), or it might just need to be enabled. Assuming it's installed, simply add this to the very top of your nginx.conf to enable it (the path may be different in your environment): load_module /usr/lib/nginx/modules/ngx_stream_module.so;

    2. Set up a stream directive in nginx.conf

    This should be in your nginx.conf as a sibling to the http directive (i.e. not within the http directive or sites_available). Basically in your actual nginx.conf, put it underneath the http directive, like this:

    http {
        # Basic Settings
        # ...
        # ... skipping ahead ...
        # ...
        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
    stream {
        # Configure ngx_stream_module for Gemini
        limit_conn_zone               $binary_remote_addr zone=addr:10m;
        limit_conn_log_level          warn;
        limit_conn                    addr 1;
        log_format                    basic '$remote_addr $upstream_addr [$time_local] '
                                      '$protocol $status $bytes_sent $bytes_received '
        access_log /var/log/nginx/gemini-access.log;
        error_log  /var/log/nginx/gemini-error.log;
        server {
            listen                    1965;
            proxy_buffer_size         16k;
            proxy_pass                'localhost:9003';  # set your actual port here

    3. Have a Gemini server listening on the local port specified in nginx.conf

    This is really easy to setup using the gemini-server npm package, which is modeled after Express (but really you can use any Gemini server). Here's a simple Node.js server written in TypeScript:

    import { readFileSync } from 'fs';
    import gemini, { Request, Response, status } from 'gemini-server';
    const PORT = 9003;
    const app = gemini({
      cert: readFileSync('./cert.pem'),
      key: readFileSync('./privkey.pem'),
      titanEnabled: false
    app.on('/', (_req: Request, res: Response) => {
    // Get the facts.
    app.on('/facts/:file', (_req: Request, res: Response) => {
      try {
        res.file('pages/facts/' + _req.params.file);
      } catch(error) {
        res.error(40 as status, 'File not found.')
    app.listen(PORT, () => console.log('Gemini listening on ' + PORT + '...'));

    Note that Gemini requires TLS, so you'll have to use a real cert.pem and privkey.pem, but if you already have these for your HTTPS domain you can reuse them. Otherwise check out this wiki to set up a cert.

    That's it. Have fun!

    Posted 2023-08-12 17:59:59 CST by henriquez.


    After all that work and going out of your way to avoid javascript (ie, gemini as a concept) you immediately go and put javascript back in?

    my server my choice