nostream is a Nostr relay you run yourself, with Tor and I2P in the box
Own a relay for social network nobody can switch off
At a glance
- What is it?
- nostream is a TypeScript implementation of a Nostr relay that a community can host directly, with a long list of supported NIPs, Marmot protocol support for end to end encrypted group messaging, read replica support in PostgreSQL, and a single CLI that starts the server on the public internet, on Tor or on I2P. It is MIT licensed and the current version is 3.6.2.
- Who is it for?
- nostream fits a community, an organisation or an individual who wants to run a Nostr relay rather than rent one, because it ships with the database, cache, observability and privacy options needed for a real deployment rather than a demo. It is the wrong choice for a client developer who only needs to read a feed, and the wrong choice for a hosted deployment that expects a managed service, since every operational task, from migrations to read replica tuning, lands on you.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A relay is infrastructure, and nostream treats it that way
nostream is a Nostr relay written in TypeScript, and the project describes the goal in a single line: own a relay for a social network nobody can switch off.
That framing is the whole point of the project. Nostr is a protocol where relays hold events and clients talk to them, so the relay is the piece that can be censored, shut down or pressured. A relay you run yourself is a relay nobody can switch off for you.
The repository description says the implementation is production-ready, and the documentation, features and guides live on the project website at nostream.dev. The homepage of the project itself is www.nostream.dev, and the master repository is on GitHub under cameri.
The topic list on the repository shows the direction of travel, with decentralized social network, i2p network, tor network, lightning network, marmot protocol and nostr protocol among the tags. A relay that can be reached over Tor or I2P, that speaks the Marmot protocol for encrypted group messaging, and that can accept payments is not a minimal server.
The version in the package manifest is 3.6.2, and the release history shows [email protected] published on 2026-10-18 alongside [email protected] and 1.3.0, so the server and its documentation site are released separately. The last push to the repository was on 2026-10-20.
The NIP list is long, and it has one deliberate hole
The README lists every NIP and MIP that has a relay-specific implementation, and the list is long enough to be the main adoption argument.
Supported are NIP-01 the basic protocol flow, NIP-02 contact lists and petnames, NIP-03 OpenTimestamps attestations, NIP-04 encrypted direct messages, NIP-05 mapping Nostr keys to DNS based identifiers, NIP-09 event deletion, NIP-11 the relay information document, NIP-12 generic tag queries, NIP-13 proof of work, NIP-14 subject tags, NIP-15 the end of stored events notice, NIP-16 event treatment, NIP-20 command results, NIP-22 created_at limits, NIP-25 reactions, NIP-28 public chat, NIP-33 parameterized replaceable events, NIP-40 expiration timestamps, NIP-42 client authentication, NIP-43 invite codes, NIP-44 versioned encrypted payloads, NIP-45 event counts, NIP-50 search, NIP-62 request to vanish, NIP-65 relay list metadata and NIP-77 Negentropy synchronisation.
One entry is not supported, and the reason is given: NIP-26 delegated event signing was removed upstream and is therefore not implemented. That is a small but telling detail, because it means the list tracks the protocol rather than a frozen snapshot of it.
The package manifest encodes the same list as a supportedNips array of numbers, and the manifest also carries supportedMips of 0, 1, 2 and 3. The Marmot protocol support covers MIPs 00 to 03, which is end to end encrypted group messaging over Nostr using kinds 443, 444, 445, 10051 and 30443, and the README notes that supported_mips is advertised in the NIP-11 relay information document so clients can discover it.
Supporting Marmot is the item that most distinguishes this relay, because it moves encrypted group chat onto the relay rather than leaving it in the client.
Getting it running with Docker Compose and one secret
The requirements for a standalone setup are PostgreSQL 14.0, Redis, Node v24 and TypeScript, and the Docker route needs Docker v20.10 and Docker Compose v2.10, with Docker Desktop 4.2.0 or newer plus mkcert for the local setup.
There is a warning worth repeating because it is unusual. Docker distributions from Snap, Brew or Debian repositories are not supported and will result in errors, and the README says to install Docker only from the official guide. It even says you may have to uninstall Docker if you installed it using a different guide.
The quick start is a clone, a secret and a start command.
git clone [email protected]:Cameri/nostream.git
cd nostreamGenerate a secret with openssl rand -hex 128, copy the output and paste it into an .env file.
SECRET=aaabbbccc...dddeeefffThen the server starts with a single command.
nostream startThe same command has flags for the privacy networks and for a reverse proxy.
nostream start --tornostream start --i2pRELAY_DOMAIN=relay.example.com [email protected] nostream start --nginxStopping is nostream stop, and the onion and I2P hostnames are printed on demand with nostream info --tor-hostname and nostream info --i2p-hostname.
The env example file shows the whole configuration surface, from the required SECRET and the database settings through Redis, the relay port 8008, the worker count, the config directory where settings.yaml lives, debug namespaces, OpenTelemetry metrics, Prometheus admin metrics and an opt-in admin console that is disabled by default.
The unified CLI replaced a directory of shell scripts
A detail in the README tells you about the direction of the project. The old shell wrapper scripts are no longer shipped in scripts/, and the unified nostream CLI is to be used directly instead. The README then prints the mapping.
scripts/start -> nostream start
scripts/start_with_tor -> nostream start --tor
scripts/start_with_i2p -> nostream start --i2p
scripts/start_with_nginx -> nostream start --nginx
scripts/stop -> nostream stop
scripts/print_tor_hostname -> nostream info --tor-hostname
scripts/print_i2p_hostname -> nostream info --i2p-hostname
scripts/update -> nostream update
scripts/clean -> nostream cleanThat is a project moving from a pile of small shell entry points to one command with subcommands, and the migration table is there so that existing documentation and muscle memory still work.
The CLI also has a documented exit code contract, which matters for anyone scripting it. It exits 0 on success, 1 on runtime or validation errors, and 2 on usage errors such as an invalid command or option. The full command reference and interactive mode documentation live in CLI.md.
There is an optional global install from a source checkout.
pnpm add -g .
nostream --helpThe import path is documented in the same section. NIP-01 events can be imported from .jsonl or .json files straight into the relay database, and compressed .jsonl files are supported and decompressed on the fly, both .jsonl.gz and .jsonl.xz.
nostream import ./events.jsonlAn equivalent alias form uses the --file option, and the same import works for a JSON array file.
Tor, I2P and the nginx front end are configuration, not separate builds
The compose file set shows how the deployment variants are organised. There is docker-compose.yml for the base case, and separate files for i2p, local, nginx, tor and windows.
The base compose file describes the service environment in detail, and it is a good picture of what a real relay needs. The relay listens on RELAY_PORT 8008. The database is PostgreSQL with a connection pool that defaults from 16 to 64 with a 60 second acquire timeout, and there is configuration for two read replicas, RR0 and RR1, each with its own pool settings, plus a note that you add RR2, RR3 and so on to configure more. READ_REPLICAS is set to 2 and READ_REPLICA_ENABLED is 'false', so the replicas are wired but off until you turn them on.
Redis is configured for the cache, and the environment file states that Redis is required for rate limiting. Tor is configured with a control port of 9051 and a hidden service port of 80.
The payment section is the piece that shows how far this goes beyond a plain relay. API keys are configured for Zebedee, Nodeless with a webhook secret, OpenNode and Lnbits. The README's table of contents includes a section on accepting payments, which is the piece that makes a community relay economically plausible.
Observability is configured rather than bolted on. The environment file has OpenTelemetry service name and OTLP endpoint settings, Prometheus admin metrics settings, and the opt-in admin console with Grafana settings and a dashboard UID. The repository carries an otel-collector-config.yaml, a prometheus.yaml, a grafana/ directory and a Caddyfile.local for local development.
The container is built to be small and to run as a non-root user
The Dockerfile is a two stage build on node:24-alpine, and the pinned package manager version is 10.33.0, matching the packageManager field in package.json.
The build stage enables corepack, prepares the pinned pnpm version, and installs with a frozen lockfile so a build cannot silently resolve different dependency versions than the committed lockfile. It then runs the build, which in the package scripts is tsc against tsconfig.build.json.
The runtime stage copies only the compiled dist directory, the package manifest and lockfile, the migrations and the knexfile. Migrations are included because the database schema is managed with knex, and the migrations/ directory plus knexfile.js travel with the image for exactly that reason. The final install runs pnpm install with the production flag and a frozen lockfile, and the container runs as the node user rather than root, with the command node src/index.js.
The image carries OCI labels for the title, the source repository, the description, the author, who the Dockerfile records as Ricardo Arturo Cabral Mejía, and the MIT licence identifier.
The repository layout supports the same picture from the source side. There are seeds/ for database seed data, test/ with both mocha configuration and cucumber, a .nycrc.json for coverage, a .changeset/ directory for release notes, biome for linting and formatting, husky for git hooks, commitlint for commit message rules, knip for unused dependency checks, sonar-project.properties, and a website/ directory that is released as its own package.
Where a relay like this is the wrong choice
Two situations rule it out, and one is a matter of scale.
The first is if you are writing a client. A client needs to connect to relays and read events, not run one. nostream is a server with a PostgreSQL database, a Redis cache, read replica configuration, optional Tor and I2P hosting, payment processor keys and an observability stack. None of that is needed to publish a note, and adopting a relay to build a client is like deploying a mail server to send one email.
The second is if you expect somebody else to run it. The whole premise is that you or your community own the relay, and the operational consequences follow. You are responsible for the database migrations, the read replica tuning, the secret, the TLS termination and the upgrades, and the releases carry a version 3 with a change set workflow, which means the upgrade path is a real piece of work rather than a package bump.
On scale, the honest reading is that the defaults in the compose file describe a mid-sized deployment. The connection pool, the two read replicas and the payment integrations are all sized for a relay serving a community, and a hobby instance running for a handful of friends does not need Redis for rate limiting, two read replicas, or four payment provider keys. You can run it with less, but the shipped defaults are not minimal.
One protocol gap is worth knowing about too. NIP-26 delegated event signing is not implemented because it was removed upstream, so a client that relies on delegation will not work against this relay.
Editorial conclusion
nostream fits a community, an organisation or an individual who wants to run a Nostr relay rather than rent one, because it ships with the database, cache, observability and privacy options needed for a real deployment rather than a demo. It is the wrong choice for a client developer who only needs to read a feed, and the wrong choice for a hosted deployment that expects a managed service, since every operational task, from migrations to read replica tuning, lands on you. Before adopting it, read the supported NIP list in the README and the version at nostream.dev, plan the PostgreSQL and Redis footprint including the read replicas, and set the SECRET with openssl rand -hex 128 exactly as the documentation says, because everything else keys off it.
Frequently asked questions
What is nostream?
It is a Nostr relay written in TypeScript, intended to be run by the community that uses it, with the project goal of owning a relay for a social network nobody can switch off. The documentation and guides live at nostream.dev, and the current version is 3.6.2.
How do I start a nostream relay?
Clone the repository, create an .env file with a SECRET generated by openssl rand -hex 128, then run nostream start. There are variants for the privacy networks, nostream start --tor and nostream start --i2p, and for a reverse proxy, RELAY_DOMAIN with CERTBOT_EMAIL and nostream start --nginx.
Which NIPs does the nostream relay support?
The README lists a relay specific implementation for NIP-01, 02, 03, 04, 05, 09, 11, 12, 13, 14, 15, 16, 20, 22, 25, 28, 33, 40, 42, 43, 44, 45, 50, 62, 65 and 77, plus Marmot protocol MIPs 00 to 03. NIP-26 is not implemented because it was removed upstream.
What does nostream need to run?
A standalone setup needs PostgreSQL 14.0, Redis, Node v24 and TypeScript, and the Docker route needs Docker v20.10 with Docker Compose v2.10, plus Docker Desktop 4.2.0 or newer and mkcert for the local setup. The README warns that Docker builds from Snap, Brew or Debian repositories are not supported.
Can I import existing events into a nostream relay?
Yes. NIP-01 events can be imported from .jsonl or .json files directly into the relay database with nostream import, and compressed .jsonl files in .gz or .xz form are decompressed on the fly.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/cameri-nostream)Was this useful?