Ready to be tested
nostr-rs-relay with ScyllaDB
This is a nostr relay, written in Rust. This fork is optimized to use ScyllaDB as the backend database for improved scalability and performance.
The original project master repository is available on sourcehut, and is mirrored on GitHub.
NIPs with a relay-specific implementation are listed here.
- NIP-01: Basic protocol flow description
- Core event model
- Hide old metadata events
- Id/Author prefix search
- NIP-02: Contact List and Petnames
- NIP-03: OpenTimestamps Attestations for Events
- NIP-05: Mapping Nostr keys to DNS-based internet identifiers
- NIP-09: Event Deletion
- NIP-11: Relay Information Document
- NIP-12: Generic Tag Queries
- NIP-15: End of Stored Events Notice
- NIP-16: Event Treatment
- NIP-20: Command Results
- NIP-22: Event
created_at
limits (future-dated events only) - NIP-26: Event Delegation (implemented, but currently disabled)
- NIP-28: Public Chat
- NIP-33: Parameterized Replaceable Events
- NIP-40: Expiration Timestamp
- NIP-42: Authentication of clients to relays
- Ubuntu 24.04 LTS (recommended) or other Linux distribution
- Rust toolchain
- Git
- ScyllaDB cluster already set up and running
- Both servers in the same VNet with full network access
Building nostr-rs-relay
requires an installation of Cargo & Rust: https://www.rust-lang.org/tools/install
The following OS packages will be helpful; on Debian/Ubuntu:
sudo apt-get install build-essential cmake protobuf-compiler pkg-config libssl-dev git curl net-tools netcat-openbsd telnet python3-pip python3-venv python3-full
-
Install ScyllaDB on your dedicated server following the official documentation
-
Create a keyspace for nostr:
CREATE KEYSPACE nostr WITH replication = {'class': 'NetworkTopologyStrategy', 'datacenter1': 3} AND durable_writes = true;
-
Ensure your ScyllaDB server is accessible from your relay server (check firewall rules, etc.)
For security best practices, create a dedicated user to run the Nostr relay service:
# Update the system
sudo apt update && sudo apt upgrade -y
sudo apt update && sudo apt install -y build-essential pkg-config libssl-dev protobuf-compiler
# Create a new user
sudo useradd -m -s /bin/bash -c "Nostr Relay Service Account" nostr-user
# Lock the account password immediately
sudo passwd -l nostr-user
# Add the user to necessary groups
sudo usermod -aG sudo nostr-user
# Switch to the new user when needed
sudo su - nostr-user
# Install Rust for the new user
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
# Create directory for nostr-rs-relay
mkdir -p ~/nostr-relay/data/relay
cd ~/nostr-relay
# Clone the repository
git clone https://github.com/thyagocoan/nostr-rs-relay-master-scylladb.git
cd nostr-rs-relay-master-scylladb
cargo build --release
The relay executable is now located in target/release/nostr-rs-relay
.
This repository includes a sample configuration file config-scylladb.toml
that you can use as a starting point. Copy it to your configuration directory and modify it for your environment:
# Create configuration directory
mkdir -p ~/.nostr/config
# Copy the sample configuration
cp config-scylladb.toml ~/.nostr/config/config.toml
# Edit the configuration file
vim ~/.nostr/config/config.toml
The main settings you'll need to update in the configuration file are:
-
In the
[info]
section:relay_url
: Your relay's public WebSocket URLname
: Your relay's namedescription
: A description of your relay
-
In the
[database]
section:- Update the
connection
string with your ScyllaDB IP address:connection = "postgresql://your-scylladb-ip/nostr?sslmode=disable&application_name=nostr-rs-relay&connect_timeout=10&tcp_keepalives=on&tcp_keepalives_idle=60&tcp_keepalives_interval=30&tcp_keepalives_count=3&statement_cache_capacity=1000"
- If you're using authentication, include username and password:
connection = "postgresql://username:password@your-scylladb-ip/nostr?sslmode=disable&application_name=nostr-rs-relay&connect_timeout=10&tcp_keepalives=on&tcp_keepalives_idle=60&tcp_keepalives_interval=30&tcp_keepalives_count=3&statement_cache_capacity=1000"
- Update the
-
Adjust other settings as needed for your environment, such as:
[network]
settings for port and address[limits]
for rate limiting and message sizes[database.scylladb]
for ScyllaDB-specific settings
Create a systemd service file for automatic startup:
# Exit to your admin user if you're still logged in as nostr-user
exit
# Create the service file
sudo vim /etc/systemd/system/nostr-relay.service
Add the following content:
[Unit]
Description=Nostr Relay Service
After=network.target
[Service]
Type=simple
User=nostr-user
Group=nostr-user
WorkingDirectory=/home/nostr-user/nostr-relay/nostr-rs-relay-master-scylladb/
ExecStart=/home/nostr-user/nostr-relay/nostr-rs-relay-master-scylladb/target/release/nostr-rs-relay --config /home/nostr-user/.nostr/config/config.toml
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
Ensure the nostr-user has proper permissions:
# Set ownership of the nostr-relay directory
sudo chown -R nostr-user:nostr-user /home/nostr-user/nostr-relay/nostr-rs-relay-master-scylladb/
# Make sure the executable has proper permissions
sudo chmod +x /home/nostr-user/nostr-relay/nostr-rs-relay-master-scylladb/target/release/nostr-rs-relay
# Reload systemd
sudo systemctl daemon-reload
# Start the service
sudo systemctl start nostr-relay
# Enable service on boot
sudo systemctl enable nostr-relay
# Check service status
sudo systemctl status nostr-relay
To run the relay manually with logging enabled, execute it with the RUST_LOG
variable set:
$ RUST_LOG=warn,nostr_rs_relay=info ./target/release/nostr-rs-relay
Use the script to setup nginx:
chmod +x setup-nginx.sh
./setup-nginx.sh
For examples of putting the relay behind a reverse proxy (for TLS termination, load balancing, and other features), see Reverse Proxy.
The ScyllaDB implementation includes the following optimizations:
-
Distributed Architecture Support: The schema is optimized for ScyllaDB's distributed architecture with appropriate partition and clustering keys.
-
Materialized Views: Uses materialized views for efficient querying by different access patterns.
-
Batch Operations: Uses batch statements for related data (like event tags) to improve performance.
-
Connection Resilience: Implements connection retry logic and connection pooling optimized for distributed databases.
-
Query Optimization: Queries are optimized to leverage ScyllaDB's partitioning scheme and indexing.
For production deployments, you can fine-tune the ScyllaDB-specific settings in your config.toml
. The config-scylladb.toml
file includes these settings in the [database.scylladb]
section:
read_consistency
andwrite_consistency
: Control the consistency level for database operationsbatch_size
: Controls the number of operations in a batchmax_retry_attempts
,initial_retry_delay_ms
,max_retry_delay_ms
, andretry_multiplier
: Configure connection retry behavior
- Check if the relay service is running and properly configured:
# Check service status
sudo systemctl status nostr-relay
# Verify service is enabled to start on boot
sudo systemctl is-enabled nostr-relay
# Check for any errors in the logs
sudo journalctl -u nostr-relay -f
# Verify the process is listening on the configured port
sudo ss -tulpn | grep 8080
- Verify ScyllaDB connectivity from the relay server:
# Check if the Nostr relay logs show successful database connection
sudo journalctl -u nostr-relay | grep -i "database\|scylla\|connected" | tail -n 20
# Test basic connectivity to ScyllaDB (replace with your ScyllaDB IP)
telnet 192.168.100.10 9042
# or
nc -zv 192.168.100.10 9042
# Check if the port is open using nmap (install if needed: sudo apt install nmap)
sudo nmap -p 9042 192.168.100.10
- Verify ScyllaDB schema and data:
# Connect to ScyllaDB and check keyspaces (replace with your ScyllaDB IP)
cqlsh your-scylladb-ip -e "DESCRIBE KEYSPACES;"
# Check if the nostr keyspace exists
cqlsh your-scylladb-ip -e "DESCRIBE KEYSPACE nostr;"
# Examine tables in the nostr keyspace
cqlsh your-scylladb-ip -e "USE nostr; DESCRIBE TABLES;"
# Check ScyllaDB cluster status (if nodetool is installed)
nodetool -h your-scylladb-ip status
# Monitor network traffic to ScyllaDB (useful for debugging)
sudo tcpdump -i any host your-scylladb-ip and port 9042 -n -c 20
- Test basic WebSocket connectivity:
# Install websocat if not already installed
cargo install websocat
# Test connection to local relay
websocat ws://localhost:8080
# If using Nginx as reverse proxy, test the public endpoint
websocat ws://your-relay-domain:8080
- Test NIP-01 protocol compliance:
# Connect to your relay
websocat ws://localhost:8080
# Once connected, send a simple PING message
["PING"]
# You should receive a PONG response
- Test event creation and retrieval:
# Connect to your relay
websocat ws://localhost:8080
# Once connected, send a test event (paste this JSON):
["EVENT", {"id": "fa1dcf1f0f16c4c1df926c0509516663fc0358225525ad4b4c5c5ca8f2c5cda0", "pubkey": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "created_at": 1234567890, "kind": 1, "tags": [], "content": "Hello ScyllaDB!", "sig": "a7c2ab3b9dec6ac4c816a66b3baa294792a769e931542f2c6dee27f223f31c89e5c3f7b821c01e7b3acf366626c7b7d2c515ab5f2b79fa1c7d8f89aab9be00de"}]
# Then try to retrieve it with a subscription:
["REQ", "test-sub", {"ids": ["fa1dcf1f0f16c4c1df926c0509516663fc0358225525ad4b4c5c5ca8f2c5cda0"]}]
# You should receive the event back in a response like:
# ["EVENT", "test-sub", {"id": "fa1dcf1f0f16c4c1df926c0509516663fc0358225525ad4b4c5c5ca8f2c5cda0", ...}]
- Test filter-based subscriptions:
# Connect to your relay
websocat ws://localhost:8080
# Subscribe to all kind 1 events
["REQ", "kind1-sub", {"kinds": [1], "limit": 5}]
# You should receive up to 5 kind 1 events if any exist in the database
For high-traffic relays, consider the following:
-
Increase the database connection pool size in your
config.toml
:[database] min_conn = 8 max_conn = 32
-
Adjust the event buffer sizes:
[limits] broadcast_buffer = 32768 event_persist_buffer = 8192
-
Configure appropriate
messages_per_sec
andsubscriptions_per_min
limits -
Monitor system resources and adjust accordingly:
# Monitor system resources htop # Monitor network connections sudo netstat -anp | grep 8080 | wc -l # Check for any errors or warnings in logs sudo journalctl -u nostr-relay -f | grep -i "error\|warning"
-
Consider enabling connection pooling if needed
Monitor your relay's performance:
# Check system resources
htop
# Check logs in real-time
journalctl -u nostr-relay -f
# Check ScyllaDB connection
nodetool status
-
Set up firewall rules to restrict access:
# Check firewall status sudo ufw status # Ensure only necessary ports are open sudo ufw status verbose | grep ALLOW
-
Verify SSL/TLS configuration (if using Nginx with SSL):
# Test SSL configuration (install if needed: apt install ssl-cert-check) ssl-cert-check -c /etc/letsencrypt/live/your-relay-domain/cert.pem
-
Consider enabling authentication if needed
-
Monitor logs for suspicious activity
-
Keep the system and nostr-rs-relay updated
-
Use the dedicated nostr-user instead of root for better security
-
If the service fails to start:
- Check logs:
journalctl -u nostr-relay -f
- Verify ScyllaDB connection:
cqlsh your-scylladb-ip
- Check permissions:
ls -l /home/nostr-user/.nostr/config/config.toml
- Verify user exists:
id nostr-user
- Check logs:
-
If WebSocket connections fail:
- Check firewall settings:
sudo ufw status
- Verify the service is listening:
netstat -tulpn | grep 8080
- Check Nginx configuration if using reverse proxy
- Check firewall settings:
-
If database connections fail:
- Verify ScyllaDB is running:
systemctl status scylla-server
(on the ScyllaDB server) - Check network connectivity:
ping your-scylladb-ip
- If you have ScyllaDB client tools installed:
- Verify database exists:
cqlsh your-scylladb-ip -e "DESC KEYSPACE nostr;"
- Check ScyllaDB logs:
sudo journalctl -u scylla-server | tail -n 50
(on the ScyllaDB server)
- Verify database exists:
- If you don't have ScyllaDB client tools:
- Test basic connectivity:
telnet your-scylladb-ip 9042
ornc -zv your-scylladb-ip 9042
- Check if the port is open:
sudo nmap -p 9042 your-scylladb-ip
(install nmap if needed)
- Test basic connectivity:
- Verify firewall allows port 9042:
sudo ufw status | grep 9042
- Check if ScyllaDB is listening on the correct interface:
sudo ss -tulpn | grep 9042
(on the ScyllaDB server) - Verify the database configuration in your config file has the correct IP, port, and credentials
- Verify ScyllaDB is running:
-
If you encounter permission issues:
- Check ownership:
ls -la /home/nostr-user/nostr-relay
- Verify service user:
grep User /etc/systemd/system/nostr-relay.service
- Check systemd logs:
journalctl -u nostr-relay -n 50
- Check ownership:
- Service is running and enabled
- Database connection is successful
- WebSocket connections are accepted
- Events can be published and retrieved
- Subscriptions work correctly
- System performance is acceptable under load
- Firewall is properly configured
- SSL/TLS is correctly set up (if applicable)
- Relay works with standard Nostr clients
- NIP-11 information document is accessible
This project is MIT licensed.
This guide provides instructions for setting up nostr-rs-relay to work with ScyllaDB. This setup assumes both servers are in the same VNet with full access to each other.
- Ubuntu 24.04 LTS
- Rust toolchain
- Git
- ScyllaDB cluster already set up and running
- Both servers in the same VNet with full network access
# Update system packages
sudo apt update && sudo apt upgrade -y
# Install build essentials and other dependencies
sudo apt install -y build-essential pkg-config libssl-dev git curl net-tools protobuf-compiler netcat-openbsd telnet python3-pip python3-venv python3-full
For security best practices, create a dedicated user to run the Nostr relay service:
# Create a new user
sudo useradd -m -s /bin/bash -c "Nostr Relay Service Account" nostr-user
# Lock the account password immediately
sudo passwd -l nostr-user
# Add the user to necessary groups
sudo usermod -aG sudo nostr-user
# Switch to the new user when needed
sudo su - nostr-user
# Install Rust for the new user
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
# Create directory for nostr-rs-relay
mkdir -p ~/nostr-relay/data/relay
cd ~/nostr-relay
# Clone the repository
git clone https://github.com/thyagocoan/nostr-rs-relay-master-scylladb.git
cd nostr-rs-relay
# Build the project (this may take a few minutes)
cargo build --release
Create the configuration directory and file:
mkdir -p ~/.nostr/config
vim ~/.nostr/config/config.toml
Add the following configuration (adjust values as needed):
[info]
relay_url = "ws://relay.bubbly.social:8080" # Replace with your domain
name = "DEV & TEST Bubbly Relay"
description = "This is a test enviroment for Bubbly Social"
pubkey = "" # Your public key (optional)
contact = "" # Your contact info (optional)
[database]
# ScyllaDB connection settings
engine = "scylla"
host = "192.168.100.10" # Replace with your ScyllaDB IP
port = 9042
user = "" # If you set up authentication
password = "" # If you set up authentication
database = "nostr"
max_connections = 20
[network]
address = "0.0.0.0"
port = 8080
remote_ip_header = "X-Forwarded-For" # If using a reverse proxy
ping_interval_seconds = 300
[limits]
messages_per_sec = 100
subscriptions_per_client = 20
broadcast_buffer = 16384
max_blocking_threads = 16
max_event_bytes = 65536
max_ws_message_bytes = 131072
max_ws_frame_bytes = 131072
max_filter_subscriptions = 10
max_filters = 100
max_limit = 1000
min_pow = 0
auth_required = false
payment_required = false
admission_price = 0
[retention]
max_events = 1000000
min_pow = 0
cost_per_event = 0
Create a systemd service file for automatic startup:
# Exit to your admin user if you're still logged in as nostr-user
exit
# Create the service file
sudo vim /etc/systemd/system/nostr-relay.service
Add the following content:
[Unit]
Description=Nostr Relay Service
After=network.target
[Service]
Type=simple
User=nostr-user
Group=nostr-user
WorkingDirectory=/home/nostr-user/nostr-relay/nostr-rs-relay
ExecStart=/home/nostr-user/nostr-relay/nostr-rs-relay/target/release/nostr-rs-relay
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
Ensure the nostr-user has proper permissions:
# Set ownership of the nostr-relay directory
sudo chown -R nostr-user:nostr-user /home/nostr-user/nostr-relay
# Make sure the executable has proper permissions
sudo chmod +x /home/nostr-user/nostr-relay/nostr-rs-relay/target/release/nostr-rs-relay
# Reload systemd
sudo systemctl daemon-reload
# Start the service
sudo systemctl start nostr-relay
# Enable service on boot
sudo systemctl enable nostr-relay
# Check service status
sudo systemctl status nostr-relay
Use the script to setup nginx
chmod +x setup-nginx.sh
./setup-nginx.sh
- Check if the relay service is running and properly configured:
# Check service status
sudo systemctl status nostr-relay
# Verify service is enabled to start on boot
sudo systemctl is-enabled nostr-relay
# Check for any errors in the logs
sudo journalctl -u nostr-relay -f
# Verify the process is listening on the configured port
sudo ss -tulpn | grep 8080
- Verify ScyllaDB connectivity from the relay server:
# Check if the Nostr relay logs show successful database connection
sudo journalctl -u nostr-relay | grep -i "database\|scylla\|connected" | tail -n 20
# Activate the cqlsh environment if using pip installation
source ~/cqlsh-env/bin/activate
# Test basic connectivity to ScyllaDB (replace with your ScyllaDB IP)
telnet 192.168.100.10 9042
# or
nc -zv 192.168.100.10 9042
# Check if the port is open using nmap (install if needed: sudo apt install nmap)
sudo nmap -p 9042 192.168.100.10
- Verify ScyllaDB schema and data:
# Connect to ScyllaDB and check keyspaces (replace with your ScyllaDB IP)
cqlsh 192.168.100.10 -e "DESCRIBE KEYSPACES;"
# Check if the nostr keyspace exists
cqlsh 192.168.100.10 -e "DESCRIBE KEYSPACE nostr;"
# Examine tables in the nostr keyspace
cqlsh 192.168.100.10 -e "USE nostr; DESCRIBE TABLES;"
# Check ScyllaDB cluster status (if nodetool is installed)
nodetool -h 192.168.100.10 status
# Monitor network traffic to ScyllaDB (useful for debugging)
sudo tcpdump -i any host 192.168.100.10 and port 9042 -n -c 20
- Test basic WebSocket connectivity:
# Install websocat if not already installed
cargo install websocat
# Test connection to local relay
websocat ws://localhost:8080
# If using Nginx as reverse proxy, test the public endpoint
websocat ws://relay.bubbly.social:8080
- Test NIP-01 protocol compliance:
# Connect to your relay
websocat ws://localhost:8080
# Once connected, send a simple PING message
["PING"]
# You should receive a PONG response
- Test event creation and retrieval:
# Connect to your relay
websocat ws://localhost:8080
# Once connected, send a test event (paste this JSON):
["EVENT", {"id": "fa1dcf1f0f16c4c1df926c0509516663fc0358225525ad4b4c5c5ca8f2c5cda0", "pubkey": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "created_at": 1234567890, "kind": 1, "tags": [], "content": "Hello ScyllaDB!", "sig": "a7c2ab3b9dec6ac4c816a66b3baa294792a769e931542f2c6dee27f223f31c89e5c3f7b821c01e7b3acf366626c7b7d2c515ab5f2b79fa1c7d8f89aab9be00de"}]
# Then try to retrieve it with a subscription:
["REQ", "test-sub", {"ids": ["fa1dcf1f0f16c4c1df926c0509516663fc0358225525ad4b4c5c5ca8f2c5cda0"]}]
# You should receive the event back in a response like:
# ["EVENT", "test-sub", {"id": "fa1dcf1f0f16c4c1df926c0509516663fc0358225525ad4b4c5c5ca8f2c5cda0", ...}]
- Test filter-based subscriptions:
# Connect to your relay
websocat ws://localhost:8080
# Subscribe to all kind 1 events
["REQ", "kind1-sub", {"kinds": [1], "limit": 5}]
# You should receive up to 5 kind 1 events if any exist in the database
- Basic load testing with multiple connections:
# Install hey load testing tool (if not installed)
go install github.com/rakyll/hey@latest
# Run a simple load test (adjust parameters as needed)
hey -n 1000 -c 50 -m GET http://localhost:8080
# For WebSocket specific load testing, consider using wscat or a custom script
- Monitor system performance during tests:
# Monitor system resources
htop
# Monitor network connections
sudo netstat -anp | grep 8080 | wc -l
# Check for any errors or warnings in logs
sudo journalctl -u nostr-relay -f | grep -i "error\|warning"
- Verify firewall settings:
# Check firewall status
sudo ufw status
# Ensure only necessary ports are open
sudo ufw status verbose | grep ALLOW
- Verify SSL/TLS configuration (if using Nginx with SSL):
# Test SSL configuration (install if needed: apt install ssl-cert-check)
ssl-cert-check -c /etc/letsencrypt/live/relay.bubbly.social/cert.pem
# Or use online SSL checker
echo "Visit https://www.ssllabs.com/ssltest/analyze.html?d=relay.bubbly.social to verify SSL configuration"
- Test with popular Nostr clients:
# Instructions for testing with Damus (iOS)
echo "In Damus, go to Settings > Relays > Add Relay and enter: ws://relay.bubbly.social:8080"
# Instructions for testing with Amethyst (Android)
echo "In Amethyst, go to Settings > Relays > Add and enter: ws://relay.bubbly.social:8080"
# Instructions for testing with Iris (Web)
echo "In Iris, go to Settings > Relays > Add and enter: ws://relay.bubbly.social:8080"
- Verify relay information endpoint:
# Test the NIP-11 information document
curl -H "Accept: application/nostr+json" http://relay.bubbly.social:8080
# Expected output should include relay information from your config.toml
- Service is running and enabled
- Database connection is successful
- WebSocket connections are accepted
- Events can be published and retrieved
- Subscriptions work correctly
- System performance is acceptable under load
- Firewall is properly configured
- SSL/TLS is correctly set up (if applicable)
- Relay works with standard Nostr clients
- NIP-11 information document is accessible
Monitor your relay's performance:
# Check system resources
htop
# Check logs in real-time
journalctl -u nostr-relay -f
# Check ScyllaDB connection
nodetool status
-
If the service fails to start:
- Check logs:
journalctl -u nostr-relay -f
- Verify ScyllaDB connection:
cqlsh your_scylladb_ip
- Check permissions:
ls -l /home/nostr-user/.nostr/config/config.toml
- Verify user exists:
id nostr-user
- Check logs:
-
If WebSocket connections fail:
- Check firewall settings:
sudo ufw status
- Verify the service is listening:
netstat -tulpn | grep 8080
- Check Nginx configuration if using reverse proxy
- Check firewall settings:
-
If database connections fail:
- Verify ScyllaDB is running:
systemctl status scylla-server
(on the ScyllaDB server) - Check network connectivity:
ping your_scylladb_ip
- If you have ScyllaDB client tools installed:
- Verify database exists:
cqlsh your_scylladb_ip -e "DESC KEYSPACE nostr;"
- Check ScyllaDB logs:
sudo journalctl -u scylla-server | tail -n 50
(on the ScyllaDB server)
- Verify database exists:
- If you don't have ScyllaDB client tools:
- Test basic connectivity:
telnet your_scylladb_ip 9042
ornc -zv your_scylladb_ip 9042
- Check if the port is open:
sudo nmap -p 9042 your_scylladb_ip
(install nmap if needed)
- Test basic connectivity:
- Verify firewall allows port 9042:
sudo ufw status | grep 9042
- Check if ScyllaDB is listening on the correct interface:
sudo ss -tulpn | grep 9042
(on the ScyllaDB server) - Verify the database configuration in `
- Verify ScyllaDB is running: