Skip to content

Instantly share code, notes, and snippets.

@leesalminen
Last active February 11, 2023 03:22
Show Gist options
  • Save leesalminen/801e50a2d6034b05fa39da982c8f0c40 to your computer and use it in GitHub Desktop.
Save leesalminen/801e50a2d6034b05fa39da982c8f0c40 to your computer and use it in GitHub Desktop.
How to Set Up Your Own nostr-rs-relay

Domain Name

First, ensure you have access to modify the DNS settings for a domain name you want to use.

VM

Next, ensure you get a virtual machine from your favorite provider. For a private-ish, friends/family relay, get something with 2GB RAM. YMMV. Make sure you choose Ubuntu Server 20.04 or 22.04.

Map DNS A record to IP of VM machine

You'll need to log into your DNS provider, and set an A record for your (sub)domain to point to the public IP address of the VM you just created.

SSH into VM

Now, log into your VM over SSH

Update system packages

sudo apt update

sudo apt upgrade -y

Install dependencies

sudo apt install -y nginx certbot python3-certbot-nginx

Setup Docker GPG key

sudo mkdir -p /etc/apt/keyrings

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Setup apt Docker repository

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker

sudo apt update

sudo apt-get install -y docker-ce

Check installation is successful by checking verions

docker --version
nginx -V
certbot --version

make user to own directory

sudo groupadd --gid 1000 appuser

sudo useradd --uid 1000 --gid appuser appuser

make directory for relay database to live

sudo mkdir /nostr-data

sudo mkdir /nostr-data/data

sudo chown -R 1000:1000 /nostr-data

Paste in new relay settings file (see heading NOSTR RELAY SETTINGS below)

sudo nano /nostr-data/config.toml

start docker container with relay

sudo docker run -it -d \
 -p 127.0.0.1:8080:8080 \
 --mount src=/nostr-data/config.toml,target=/usr/src/app/config.toml,type=bind \
 --mount src=/nostr-data/data,target=/usr/src/app/db,type=bind \
 --restart unless-stopped \
 --pull always \
 scsibug/nostr-rs-relay:latest

Check installation is successful, you should see "Please use a Nostr client to connect." as the reponse

curl localhost:8080

Delete the default nginx settings file

sudo rm -rf /etc/nginx/sites-available/default

Paste in new settings file contents (see heading NGINX SETTINGS below)

sudo nano /etc/nginx/sites-available/default

Restart nginx

sudo systemctl restart nginx

Request SSL cert from letsencrypt/certbot (REPLACE subdomain.mydomain.com with yours)

sudo certbot --nginx -d subdomain.mydomain.com

Test Connection

Navigate to https://websocketking.com, enter wss://subdomain.mydomain.com (replace with yours), and click connect. You should see connected.

Navigate to https://subdomain.mydomain.com (replace with yours). It should say "Please use a Nostr client to connect.".

Add Relay To Client

Finally, in your Nostr client, add your newly created relay wss://subdomain.yourdomain.com

Next Steps

You may want to consider hardening your VM against common attack types. Hardning the SSH server, install a firewall like UFW, etc. There are lots of guides out there. If you do decide to install a firewall, keep in mind that we're using ports 22(ssh), 80(http), and 443(https/websocket).


NGINX SETTINGS

Use the contents below as the contents of the default nginx setting. Don't forget to change subdomain.mydomain.com to your domain.

server{
    server_name subdomain.mydomain.com;
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

NOSTR RELAY SETTINGS

Use the contents below as the contents of the config.toml nostr-rs-relay configuration file. Be sure to change the following settings: relay_url, name, description fields at a minimum.

# Nostr-rs-relay configuration

[info]
# The advertised URL for the Nostr websocket.
relay_url = "wss://nostr.example.com/"

# Relay information for clients.  Put your unique server name here.
name = "nostr-rs-relay"

# Description
description = "A newly created nostr-rs-relay.\n\nCustomize this with your own info."

# Administrative contact pubkey
#pubkey = "0c2d168a4ae8ca58c9f1ab237b5df682599c6c7ab74307ea8b05684b60405d41"

# Administrative contact URI
#contact = "mailto:contact@example.com"

[diagnostics]
# Enable tokio tracing (for use with tokio-console)
#tracing = true

[database]
# Directory for SQLite files.  Defaults to the current directory.  Can
# also be specified (and overriden) with the "--db dirname" command
# line option.
data_directory = "."


# Use an in-memory database instead of 'nostr.db'.
# Caution; this will not survive a process restart!
#in_memory = false

# Database connection pool settings for subscribers:

# Minimum number of SQLite reader connections
#min_conn = 4

# Maximum number of SQLite reader connections
#max_conn = 128

[network]
# Bind to this network address
address = "0.0.0.0"

# Listen on this port
port = 8080

# If present, read this HTTP header for logging client IP addresses.
# Examples for common proxies, cloudflare:
#remote_ip_header = "x-forwarded-for"
#remote_ip_header = "cf-connecting-ip"

# Websocket ping interval in seconds, defaults to 5 minutes
#ping_interval = 300

[options]
# Reject events that have timestamps greater than this many seconds in
# the future.  Recommended to reject anything greater than 30 minutes
# from the current time, but the default is to allow any date.
reject_future_seconds = 1800

[limits]
# Limit events created per second, averaged over one minute.  Must be
# an integer.  If not set (or set to 0), defaults to unlimited.  Note:
# this is for the server as a whole, not per-connection.
# messages_per_sec = 0

# Limit client subscriptions created per second, averaged over one
# minute.  Must be an integer.  If not set (or set to 0), defaults to
# unlimited.
#subscriptions_per_min = 0

# UNIMPLEMENTED...
# Limit how many concurrent database connections a client can have.
# This prevents a single client from starting too many expensive
# database queries.  Must be an integer.  If not set (or set to 0),
# defaults to unlimited (subject to subscription limits).
#db_conns_per_client = 0

# Limit blocking threads used for database connections.  Defaults to 16.
#max_blocking_threads = 16

# Limit the maximum size of an EVENT message.  Defaults to 128 KB.
# Set to 0 for unlimited.
#max_event_bytes = 131072

# Maximum WebSocket message in bytes.  Defaults to 128 KB.
#max_ws_message_bytes = 131072

# Maximum WebSocket frame size in bytes.  Defaults to 128 KB.
#max_ws_frame_bytes = 131072

# Broadcast buffer size, in number of events.  This prevents slow
# readers from consuming memory.
#broadcast_buffer = 16384

# Event persistence buffer size, in number of events.  This provides
# backpressure to senders if writes are slow.
#event_persist_buffer = 4096

[authorization]
# Pubkey addresses in this array are whitelisted for event publishing.
# Only valid events by these authors will be accepted, if the variable
# is set.
#pubkey_whitelist = [
#  "35d26e4690cbe1a898af61cc3515661eb5fa763b57bd0b42e45099c8b32fd50f",
#  "887645fef0ce0c3c1218d2f5d8e6132a19304cdc57cd20281d082f38cfea0072",
#]

[verified_users]
# NIP-05 verification of users.  Can be "enabled" to require NIP-05
# metadata for event authors, "passive" to perform validation but
# never block publishing, or "disabled" to do nothing.
#mode = "disabled"

# Domain names that will be prevented from publishing events.
#domain_blacklist = ["wellorder.net"]

# Domain names that are allowed to publish events.  If defined, only
# events NIP-05 verified authors at these domains are persisted.
#domain_whitelist = ["example.com"]

# Consider an pubkey "verified" if we have a successful validation
# from the NIP-05 domain within this amount of time.  Note, if the
# domain provides a successful response that omits the account,
# verification is immediately revoked.
#verify_expiration = "1 week"

# How long to wait between verification attempts for a specific author.
#verify_update_frequency = "24 hours"

# How many consecutive failed checks before we give up on verifying
# this author.
#max_consecutive_failures = 20
@jesterhodl
Copy link

Hi! Thanks for these instructions. On Ubuntu 22.04 curl failing. The nostr-rs-relay port (8080) is open but it's closing it immediately.
The only thing I changed is the id for appuser from 1000 to 2000
Any ideas?

root@redacted:/nostr-data# ss -ntpl
State           Recv-Q          Send-Q                   Local Address:Port                   Peer Address:Port         Process
LISTEN          0               4096                         127.0.0.1:8080                        0.0.0.0:*             users:(("docker-proxy",pid=22783,fd=4))
LISTEN          0               511                            0.0.0.0:80                          0.0.0.0:*             users:(("nginx",pid=21010,fd=6),("nginx",pid=21009,fd=6),("nginx",pid=20998,fd=6))
LISTEN          0               511                            0.0.0.0:443                         0.0.0.0:*             users:(("nginx",pid=21010,fd=12),("nginx",pid=21009,fd=12),("nginx",pid=20998,fd=12))
root@redacted:/nostr-data# curl localhost:8080
curl: (56) Recv failure: Connection reset by peer
root@redacted:/nostr-data# ls -la
total 20
drwxr-xr-x  3 appuser appuser 4096 Jan  2 19:31 .
drwxr-xr-x 21 root    root    4096 Jan  2 19:23 ..
-rw-r--r--  1 root    root    4425 Jan  2 19:31 config.toml
drwxr-xr-x  2 appuser appuser 4096 Jan  2 19:23 data
root@redacted:/nostr-data# ls -la data
total 8
drwxr-xr-x 2 appuser appuser 4096 Jan  2 19:23 .
drwxr-xr-x 3 appuser appuser 4096 Jan  2 19:31 ..
root@redacted:/nostr-data#

@jesterhodl
Copy link

All right, I added -u 2000:2000 to the docker cmdline
I didn't use 1000 because 1000 is the ubuntu group and user id
Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment