This is an implementation of the Nostr protocol server (Nostr Relay) in Ruby. It implements the following list of specifications (Nostr Implementation Possibilities or NIPs):
- NIP-01: Basic protocol flow description
- NIP-04: Encrypted Direct Message
- NIP-09: Event Deletion
- NIP-11: Relay Information Document
- NIP-12: Generic Tag Queries
- NIP-13: Proof of Work
- NIP-16: Event Treatment
- NIP-20: Command Results
- NIP-22: Event
created_at
Limits - NIP-26: Delegated Event Signing
- NIP-28: Public Chat
- NIP-33: Parameterized Replaceable Events
- NIP-40: Expiration Timestamp
- NIP-42: Authentication of clients to relays
- NIP-43: Fast Auth (experimental)
- NIP-45: Event Counts
- NIP-65: Relay List Metadata
Nostr requires decentralization. Decentralization requires servers. Many different servers, small and big. Some servers should be robust and cheap to operate at scale. Some servers are better to be cute and simple to use. This relay aims to become the most developer-friendly and the most relay-operator-friendly implementation through:
- high configurability — like support for dynamic feature flags in future
- clean errors descriptions — including different formats and granular causes
- Comprehensive tests and documentation coverage — plans to focus on mutation and unit tests
- feature rich — for example, experimental NIPs and non-nostr related stuff like backups, cross posting etc
- great accessibility — plans to add support for major integrations aka HTTP API, GraphQL, webhooks and others
The ultimate goal is everyone using this relay for the next use-cases:
- Developers, while working on a client, need to connect to some relays, play with different NIPs, fix errors, check hypothesis
- Non-technical but curious people wants to setup a private relay to share it with friends and family
- Small-to-medium businesses use custom configuration of the relay to provide paid services in their specific niche (i.e. invite-driven userbase gets IT-related curated content into their feed)
This however doesn't mean it shouldn't be possible to serve millions of users per day with this relay. It just means that with Ruby and concurrency one will have to spend more money into hardware. So performance optimizations will usually have low priority unless it prevents some interesting use-cases.
Here you won't find any instructions on how to deploy production-ready services for millions of active connections because there are infinite amount of ways of how to achieve it and which trade-offs to choose.
Some thoughts and hints on production deployment may be found here. 2 main use-cases described here are:
- Deployment through docker-compose with a very primitive setup to give a basic understanding on how things work together, quickly test it and potentially deploy to a single server expecting small workload
- Local setup for development and contributions
- TBD: link to the guide on how to deploy to managed cloud environment
- Live instance could be found at https://saltivka.org and relay address is
wss://saltivka.org
- Prepare a host with docker environment installed (something like this). Demo setup expects approximately 8 GB of RAM and 4vCPU
- SSH into this host
git clone https://github.com/viktorvsk/saltivka.git
cd saltivka
docker compose up --build
That's it! Wait a minute or two until database is ready. Now you should have HTTP/WS server available at localhost:3000
and HTTPS/WSS at localhost:2402
. Ensure ports are open on your server. Both commands should work and let you start working with Nostr:
wscat -c "ws://localhost:3000"
wscat --no-check -c "wss://localhost:2402"
(Assuming wscat
is installed and localhost
is changed to the server IP if necessary.)
It's a typical Ruby on Rails application so all defaults mostly apply.
git clone https://github.com/viktorvsk/saltivka.git
cd saltivka
cp .env.example .env.development
(Adjust Postgres and Redis settings)echo POSTGRES_DATABASE=saltivka_test > .env.test
- Adjust Postgres and Redis credentials in
.env.test
if needed. Use databases different from development environment rails db:create db:migrate db:seed
rspec
rails server
bundle exec sidekiq -q nostr