[⚡] usenostr
← back

setting up a nostr relay

with strfry, docker and caddy.

Setting up a relay is not very hard. You will need a bit of comfort with the terminal and some basic Docker knowledge, but it should be doable for most people.

In this guide I'll show you how to set up your own relay with strfry (a modern, fast Nostr relay written in C++), and Caddy in front of it to give you HTTPS automatically.

If strfry feels heavy for your use case, take a look at haven (an opinionated personal relay with inbox and outbox built in), khatru (a Go library to build your own relay in a handful of lines), or nostr-rs-relay (small, Rust, SQLite).

pre-requirements

  • A domain name. You can buy one at Njalla, which accepts cryptocurrencies and is privacy-friendly. Namecheap also takes Bitcoin. Porkbun is another good option.
  • A server. You can rent a small VPS for a few euros a month at Netcup, Hetzner, or DigitalOcean. For privacy-focused options, check kycnot.me.

requirements

  • Hardware: no special needs. Events are just text, so storage grows slowly. A 1GB RAM VPS is plenty for a personal or small community relay.
  • System: I recommend a recent version of Debian or Ubuntu if you don't have a preference.
  • Software: git, docker, and docker compose.

Once you have those, you're good to start.

dns

Before touching Caddy, make sure you've added an A record (and/or AAAA) on your domain pointing to your server's IP. Something like relay.example.com is fine. Caddy will use this to get a TLS certificate from Let's Encrypt.

setup

base setup

  1. Connect to your server via SSH and create a folder for the relay: mkdir -p ~/nostr-relay && cd ~/nostr-relay
  2. Create the data and config directories: mkdir -p data strfry

Now create strfry/strfry.conf with this content. Edit the name, description, pubkey and contact fields so the relay identifies itself properly (the pubkey should be your hex public key, not your npub):

# strfry.conf, a minimal config
db = "/app/strfry-db/"

relay {
    bind = "0.0.0.0"
    port = 7777

    info {
        name        = "my nostr relay"
        description = "a personal relay"
        pubkey      = "YOUR_HEX_PUBKEY"
        contact     = "you@example.com"
    }

    maxWebsocketPayloadSize = 131072
    autoPingSeconds         = 55
    enableTcpKeepalive      = true

    writePolicy {
        plugin = ""   # point to a script if you want custom filtering
    }

    compression {
        enabled       = true
        slidingWindow = true
    }
}

If you want to see every option, the full example config lives in the strfry repo.

Then create a docker-compose.yml file in ~/nostr-relay. The caddy.* labels tell our reverse proxy to pick up this service automatically (we'll set up the proxy in the next step):

services:
  strfry:
    image: dockurr/strfry:latest
    container_name: strfry
    restart: unless-stopped
    volumes:
      - ./data:/app/strfry-db
      - ./strfry/strfry.conf:/app/strfry.conf:ro
    networks:
      - caddy
    labels:
      caddy: relay.example.com
      caddy.reverse_proxy: "{{upstreams 7777}}"

networks:
  caddy:
    external: true

Replace relay.example.com with your own domain. Clients will connect to this with wss://relay.example.com.

Bring it up:

  1. Create the shared Docker network: docker network create caddy
  2. Start the relay: docker compose up -d
  3. Check the logs: docker compose logs -f. You should see strfry listening on 0.0.0.0:7777.

The relay is running inside the Docker network, but not yet reachable from the outside. Next we put a proxy in front of it for HTTPS.

proxy setup (caddy-docker-proxy)

We use caddy-docker-proxy, a Caddy build that reads labels from running containers and configures itself. No Caddyfile to maintain. Adding more services later is just a matter of adding labels to them.

If you already have your own reverse proxy (nginx, plain Caddy, Nginx Proxy Manager, etc.), just put it on the same caddy Docker network and forward to strfry:7777. Otherwise, follow along.

  1. Create a new directory at the same level as nostr-relay: mkdir ~/caddy && cd ~/caddy
  2. Create a docker-compose.yml:
services:
  caddy:
    image: lucaslorentz/caddy-docker-proxy:ci-alpine
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    environment:
      - CADDY_INGRESS_NETWORKS=caddy
      - CADDY_DOCKER_CADDYFILE_PATH=/config/Caddyfile
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - caddy

volumes:
  caddy_data:
  caddy_config:

networks:
  caddy:
    external: true

Bring it up:

  1. docker compose up -d
  2. docker compose logs -f caddy, and watch it pick up the strfry labels and grab a certificate from Let's Encrypt.

Make sure ports 80 and 443 are open on your server's firewall. Port 7777 should not be publicly exposed; all traffic should go through Caddy.

checking it works

  1. Open https://relay.example.com in a browser. You should see a small JSON document with your relay's info (that's NIP-11).
  2. From any Nostr client, add wss://relay.example.com to your relay list and publish a note.
  3. For some stats: docker exec strfry strfry info

That's it. You have your own relay. Announce it on Nostr so other people can use it, or keep it for yourself as a personal archive.

next steps

  • Backups. Everything important is in ~/nostr-relay/data/. Snapshot it.
  • Spam filtering. strfry supports plugin scripts for write policies, which you can use to build allowlists or web-of-trust filtering. See the plugin docs.
  • Syncing with other relays. strfry supports negentropy, a way for two relays to efficiently figure out which events they have in common. Run strfry sync wss://other-relay to mirror or backfill.
  • Getting listed. Register your relay on nostr.watch so people can find it.