From 7e3b3f4a27322c2762eb9926a52805422eedf4df Mon Sep 17 00:00:00 2001 From: chappie-daemon Date: Fri, 16 Oct 2026 19:16:05 -0400 Subject: [PATCH 1/5] docs: link the project website from the README intro --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 011631dba..abd8e4e50 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@

This is a [nostr](https://github.com/fiatjaf/nostr) relay, written in -Typescript. +Typescript. Documentation, features and guides live on the project website: +**[ema.tnsor.network](https://ema.tnsor.network)**. This implementation is production-ready. See below for supported features. From 4818324bcc4bd47c28fc2700267dd606f8cc10f1 Mon Sep 17 00:00:00 2001 From: chappie-daemon Date: Fri, 16 Oct 2026 19:19:27 -0400 Subject: [PATCH 2/5] docs: add the changeset the repo requires --- .changeset/readme-website-link.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/readme-website-link.md diff --git a/.changeset/readme-website-link.md b/.changeset/readme-website-link.md new file mode 100644 index 000000000..36962d3c4 --- /dev/null +++ b/.changeset/readme-website-link.md @@ -0,0 +1,5 @@ +--- +"nostream-website": patch +--- + +README now links the project website (ema.tnsor.network) from the intro. From 79fdf014b489458cb6f43ec1e87c13fc464ff8b2 Mon Sep 17 00:00:00 2001 From: chappie-daemon Date: Fri, 16 Oct 2026 19:29:58 -0400 Subject: [PATCH 3/5] docs: modernize the README Add a table of contents, fix the NIP checklist to match package.json's supportedNips (adds NIP-42/43/50/77, marks NIP-26 as removed upstream, drops the duplicate NIP-44), reorder the major sections into a start-first flow (quick starts before the payments guide, standalone next to Docker, troubleshooting near the end), fix the stale ./scripts reference in the NWC step (the wrapper scripts are gone), and normalize the indented code fences to plain ones. No factual content changed: URLs, environment variable names and command invocations are byte-identical to the previous version. --- README.md | 675 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 350 insertions(+), 325 deletions(-) diff --git a/README.md b/README.md index abd8e4e50..6b9965e5f 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,26 @@ The project master repository is available on [GitHub](https://github.com/cameri [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template/Xfk5F7?referralCode=Kfv2ly) +## Table of contents + +- [Features](#features) +- [Requirements](#requirements) +- [Quick start (Docker Compose)](#quick-start-docker-compose) + - [Importing events from JSON Lines or JSON Arrays](#importing-events-from-json-lines-or-json-arrays) + - [NIP-43 invite codes](#nip-43-invite-codes) +- [Quick start (Standalone)](#quick-start-standalone) +- [Full guide](#full-guide) + - [Accepting payments](#accepting-payments) +- [Running as a Service](#running-as-a-service) +- [Troubleshooting](#troubleshooting) +- [Export Events](#export-events) +- [Benchmark Database Queries](#benchmark-database-queries) +- [Relay Maintenance](#relay-maintenance) +- [Configuration](#configuration) +- [Development & Contributing](#development--contributing) +- [Dev Channel](#dev-channel) +- [License](#license) + ## Features NIPs and MIPs with a relay-specific implementation are listed here. @@ -61,14 +81,19 @@ NIPs and MIPs with a relay-specific implementation are listed here. - [x] NIP-20: Command Results - [x] NIP-22: Event `created_at` Limits - [x] NIP-25: Reactions -- [ ] NIP-26: Delegated Event Signing (REMOVED) +- [ ] NIP-26: Delegated Event Signing (removed upstream; not implemented) - [x] NIP-28: Public Chat - [x] NIP-33: Parameterized Replaceable Events - [x] NIP-40: Expiration Timestamp +- [x] NIP-42: Authentication of clients to relays +- [x] NIP-43: Invite codes - [x] NIP-44: Encrypted Payloads (Versioned) - [x] NIP-45: Event Counts +- [x] NIP-50: Search capability - [x] NIP-62: Request to Vanish - [x] NIP-65: Relay List Metadata +- [x] NIP-77: Negentropy Synchronization + - [x] Marmot Protocol [MIPs 00–03](https://github.com/marmot-protocol/marmot): E2EE group messaging over Nostr — kinds 443, 444, 445, 10051 and 30443, with `supported_mips` advertised in the NIP-11 relay information document ## Requirements @@ -90,120 +115,6 @@ NIPs and MIPs with a relay-specific implementation are listed here. WARNING: Docker distributions from Snap, Brew or Debian repositories are NOT SUPPORTED and will result in errors. Install Docker from their [official guide](https://docs.docker.com/engine/install/) ONLY. -## Full Guide - -- [Set up a Paid Nostr relay with Nostream and ZEBEDEE](https://docs.zbdpay.com/payments/nostr/nostr-relay) by [André Neves](https://primal.net/andre) (CTO & Co-Founder at [ZEBEDEE](https://zebedee.io/)) -- [Set up a Nostr relay in under 5 minutes](https://andreneves.xyz/p/set-up-a-nostr-relay-server-in-under) by [André Neves](https://twitter.com/andreneves) (CTO & Co-Founder at [ZEBEDEE](https://zebedee.io/)) - -### Accepting Payments - -1. Before you begin - - Complete one of the Quick Start guides in this document - - Create a `.env` file - - On `.nostr/settings.yaml` file make the following changes: - - Set `payments.enabled` to `true` - - Set `payments.feeSchedules.admission.enabled` to `true` - - Set `limits.event.pubkey.minBalance` to the minimum balance in msats required to accept events (i.e. `1000000` to require a balance of `1000` sats) - - Choose one of the following payment processors: `zebedee`, `nodeless`, `opennode`, `lnbits`, `lnurl`, `nwc` - -2. [ZEBEDEE](https://zebedee.io) - - Complete the step "Before you begin" - - [Sign up for a ZEBEDEE Developer Dashboard account](https://dashboard.zebedee.io/signup), create a new LIVE Project, and get that Project's API Key - - Set `ZEBEDEE_API_KEY` environment variable with the API Key above on your `.env` file - - ``` - ZEBEDEE_API_KEY={YOUR_ZEBEDEE_API_KEY_HERE} - ``` - - - Follow the required steps for all payments processors - - On `.nostr/settings.yaml` file make the following changes: - - `payments.processor` to `zebedee` - - `paymentsProcessors.zebedee.callbackBaseURL` to match your Nostream URL (e.g. `https://{YOUR_DOMAIN_HERE}/callbacks/zebedee`) - - Restart Nostream (`nostream stop` followed by `nostream start`) - - Read the in-depth guide for more information: [Set Up a Paid Nostr Relay with ZEBEDEE API](https://docs.zbdpay.com/payments/nostr/nostr-relay) - -3. [Nodeless](https://nodeless.io/?ref=587f477f-ba1c-4bd3-8986-8302c98f6731) - - Complete the step "Before you begin" - - [Sign up](https://nodeless.io/?ref=587f477f-ba1c-4bd3-8986-8302c98f6731) for a new account, create a new store and take note of the store ID - - Go to Profile > API Tokens and generate a new key and take note of it - - Create a store webhook with your Nodeless callback URL (e.g. `https://{YOUR_DOMAIN_HERE}/callbacks/nodeless`) and make sure to enable all of the events. Grab the generated store webhook secret - - Set `NODELESS_API_KEY` and `NODELESS_WEBHOOK_SECRET` environment variables with generated API key and webhook secret, respectively - - ``` - NODELESS_API_KEY={YOUR_NODELESS_API_KEY} - NODELESS_WEBHOOK_SECRET={YOUR_NODELESS_WEBHOOK_SECRET} - ``` - - - On your `.nostr/settings.yaml` file make the following changes: - - Set `payments.processor` to `nodeless` - - Set `paymentsProcessors.nodeless.storeId` to your store ID - - Restart Nostream (`nostream stop` followed by `nostream start`) - -4. [OpenNode](https://www.opennode.com/) - - Complete the step "Before you begin" - - Sign up for a new account and get verified - - Go to Developers > Integrations and setup two-factor authentication - - Create a new API Key with Invoices permission - - Set `OPENNODE_API_KEY` environment variable on your `.env` file - - ``` - OPENNODE_API_KEY={YOUR_OPENNODE_API_KEY} - ``` - - - On your `.nostr/settings.yaml` file make the following changes: - - Set `payments.processor` to `opennode` - - Restart Nostream (`nostream stop` followed by `nostream start`) - -5. [LNBITS](https://lnbits.com/) - - Complete the step "Before you begin" - - Create a new wallet on you public LNbits instance - - [Demo](https://legend.lnbits.com/) server must not be used for production - - Your instance must be accessible from the internet and have a valid SSL/TLS certificate - - Get wallet Invoice/read key (in Api docs section of your wallet) - - set `LNBITS_API_KEY` environment variable with the Invoice/read key Key above on your `.env` file - - ``` - LNBITS_API_KEY={YOUR_LNBITS_API_KEY_HERE} - ``` - - On your `.nostr/settings.yaml` file make the following changes: - - Set `payments.processor` to `lnbits` - - set `lnbits.baseURL` to your LNbits instance URL (e.g. `https://{YOUR_LNBITS_DOMAIN_HERE}/`) - - Set `paymentsProcessors.lnbits.callbackBaseURL` to match your Nostream URL (e.g. `https://{YOUR_DOMAIN_HERE}/callbacks/lnbits`) - - Restart Nostream (`nostream stop` followed by `nostream start`) - -6. [Alby](https://getalby.com/) or any LNURL Provider with [LNURL-verify](https://github.com/lnurl/luds/issues/182) support - - Complete the step "Before you begin" - - [Create a new account](https://getalby.com/user/new) if you don't have an LNURL - - On your `.nostr/settings.yaml` file make the following changes: - - Set `payments.processor` to `lnurl` - - Set `lnurl.invoiceURL` to your LNURL (e.g. `https://getalby.com/lnurlp/your-username`) - - Restart Nostream (`nostream stop` followed by `nostream start`) - -7. Nostr Wallet Connect (NIP-47 / NWC) - - Complete the step "Before you begin" - - Create an app connection in your NWC-compatible wallet and copy the generated NWC URL - - Set `NWC_URL` environment variable on your `.env` file - - ``` - NWC_URL={NOSTR_WALLET_CONNECT_URL} - ``` - - - On your `.nostr/settings.yaml` file make the following changes: - - Set `payments.processor` to `nwc` - - Restart Nostream (`./scripts/stop` followed by `./scripts/start`) - -8. Ensure payments are required for your public key - - Visit https://{YOUR-DOMAIN}/ - - You should be presented with a form requesting an admission fee to be paid - - Fill out the form and take the necessary steps to pay the invoice - - Wait until the screen indicates that payment was received - - Add your relay URL to your favorite Nostr client (wss://{YOUR-DOMAIN}) and wait for it to connect - - Send a couple notes to test - - Go to https://websocketking.com/ and connect to your relay (wss://{YOUR_DOMAIN}) - - Convert your npub to hexadecimal using a [Key Converter](https://damus.io/key/) - - Send the following JSON message: `["REQ", "payment-test", {"authors":["your-pubkey-in-hexadecimal"]}]` - - You should get back the few notes you sent earlier - ## Quick Start (Docker Compose) For full command reference and interactive mode documentation, see [CLI.md](CLI.md). @@ -213,59 +124,59 @@ Non-interactive CLI usage conventions: - exit `2` on usage errors (invalid command/options) Optional global installation from a source checkout: - ``` - pnpm add -g . - nostream --help - ``` +``` +pnpm add -g . +nostream --help +``` Install Docker following the [official guide](https://docs.docker.com/engine/install/). You may have to uninstall Docker if you installed it using a different guide. Clone repository and enter directory: - ``` - git clone git@github.com:Cameri/nostream.git - cd nostream - ``` +``` +git clone git@github.com:Cameri/nostream.git +cd nostream +``` Generate a secret with: `openssl rand -hex 128` Copy the output and paste it into an `.env` file: - ``` - SECRET=aaabbbccc...dddeeefff - # Secret shortened for brevity - ``` +``` +SECRET=aaabbbccc...dddeeefff +# Secret shortened for brevity +``` Start: - ``` - nostream start - ``` +``` +nostream start +``` or - ``` - nostream start --tor - ``` +``` +nostream start --tor +``` or - ``` - nostream start --i2p - ``` +``` +nostream start --i2p +``` or - ``` - RELAY_DOMAIN=relay.example.com CERTBOT_EMAIL=you@example.com nostream start --nginx - ``` +``` +RELAY_DOMAIN=relay.example.com CERTBOT_EMAIL=you@example.com nostream start --nginx +``` Stop the server with: - ``` - nostream stop - ``` +``` +nostream stop +``` Print the Tor hostname: - ``` - nostream info --tor-hostname - ``` +``` +nostream info --tor-hostname +``` Print I2P hostname(s): - ``` - nostream info --i2p-hostname - ``` +``` +nostream info --i2p-hostname +``` The old shell wrapper scripts are no longer shipped in `scripts/`. Use the unified `nostream` CLI directly instead: @@ -292,30 +203,30 @@ Compressed `.jsonl` files are also supported and decompressed on-the-fly: - `.jsonl.xz` (XZ) Basic import: - ``` - nostream import ./events.jsonl - ``` +``` +nostream import ./events.jsonl +``` Equivalent alias form: - ``` - nostream import --file ./events.jsonl - ``` +``` +nostream import --file ./events.jsonl +``` Import from a JSON array file (compatible with `nostream export --format json`): - ``` - nostream import --file ./events.json - ``` +``` +nostream import --file ./events.json +``` Import a compressed backup: - ``` - nostream import ./events.jsonl.gz - nostream import ./events.jsonl.xz - ``` +``` +nostream import ./events.jsonl.gz +nostream import ./events.jsonl.xz +``` Set a custom batch size (default: `1000`): - ``` - nostream import ./events.jsonl --batch-size 500 - ``` +``` +nostream import ./events.jsonl --batch-size 500 +``` The importer: @@ -331,10 +242,10 @@ The importer: Kind 28934 join requests are implemented. Mint a code and share it out of band: - ``` - nostream invite create --json - docker compose exec nostream node src/cli/index.js invite create - ``` +``` +nostream invite create --json +docker compose exec nostream node src/cli/index.js invite create +``` Users can also request a code themselves: the relay answers a `REQ` for kind 28935 by minting one on the fly. Off by default — set `nip43.allowInviteRequests` to enable it. @@ -342,199 +253,259 @@ minting one on the fly. Off by default — set `nip43.allowInviteRequests` to en See [CLI.md](CLI.md) for `--uses` / `--expires-in` and Docker vs local Postgres, and [CONFIGURATION.md](CONFIGURATION.md) for the invite request settings. -### Running as a Service +## Quick Start (Standalone) -By default this server will run continuously until you stop it with Ctrl+C or until the system restarts. +Set the following environment variables: -You can [install as a systemd service](https://www.swissrouting.com/nostr.html#installing-as-a-service) if you want the server to run again automatically whenever the system is restarted. For example: +``` +DB_URI="postgresql://postgres:postgres@localhost:5432/nostr_ts_relay_test" +DB_USER=postgres +``` + or +``` +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=nostr_ts_relay +DB_USER=postgres +DB_PASSWORD=postgres +``` - ``` - $ nano /etc/systemd/system/nostream.service +``` +REDIS_URI="redis://default:nostr_ts_relay@localhost:6379" - # Note: replace "User=..." with your username, and - # "/home/nostr/nostream" with the directory where you cloned the repo. +REDIS_HOST=localhost +REDIS_PORT=6379 +REDIS_USER=default +REDIS_PASSWORD=nostr_ts_relay +``` - [Unit] - Description=Nostr TS Relay - After=network.target - StartLimitIntervalSec=0 +Generate a long random secret and set SECRET: +You may want to use `openssl rand -hex 128` to generate a secret. - [Service] - Type=simple - Restart=always - RestartSec=5 - User=nostr - WorkingDirectory=/home/nostr/nostream - ExecStart=/usr/bin/env bash -lc 'cd /home/nostr/nostream && nostream start' - ExecStop=/usr/bin/env bash -lc 'cd /home/nostr/nostream && nostream stop' +``` +SECRET=aaabbbccc...dddeeefff +# Secret shortened for brevity +``` - [Install] - WantedBy=multi-user.target - ``` +### Initializing the database -And then: +Create `nostr_ts_relay` database: - ``` - systemctl enable nostream - systemctl start nostream - ``` +``` +$ psql -h $DB_HOST -p $DB_PORT -U $DB_USER -W +postgres=# create database nostr_ts_relay; +postgres=# quit +``` -The logs can be viewed with: +Start Redis and use `redis-cli` to set the default password and verify: +``` +$ redis-cli +127.0.0.1:6379> CONFIG SET requirepass "nostr_ts_relay" +OK +127.0.0.1:6379> AUTH nostr_ts_relay +Ok +``` - ``` - journalctl -u nostream - ``` +Clone repository and enter directory: +``` +git clone git@github.com:Cameri/nostream.git +cd nostream +``` -## Troubleshooting +Install dependencies: -### Linux: Docker DNS resolution failures (`EAI_AGAIN`) +``` +corepack enable +pnpm install +``` -On some Linux environments (especially rolling-release distros or setups using -`systemd-resolved`), `docker compose` builds can fail with DNS errors such as: +Run migrations (at least once and after pulling new changes): -- `getaddrinfo EAI_AGAIN registry.npmjs.org` -- `Temporary failure in name resolution` +``` +pnpm db:migrate +``` -To fix this, configure Docker daemon DNS in `/etc/docker/daemon.json`. +Create .nostr folder inside nostream project folder and copy over the settings file: -1. Create or update `/etc/docker/daemon.json`: +``` +mkdir .nostr +cp resources/default-settings.yaml .nostr/settings.yaml +``` - ``` - sudo mkdir -p /etc/docker - sudo nano /etc/docker/daemon.json - ``` +To start in development mode: - Add or update the file with: +``` +pnpm dev +``` - ``` - { - "dns": ["1.1.1.1", "8.8.8.8"] - } - ``` +Or, start in production mode: - If this file already exists, merge the `dns` key into the existing JSON - instead of replacing the entire file. +``` +pnpm start +``` - If your environment does not allow public resolvers, replace `1.1.1.1` and - `8.8.8.8` with DNS servers approved by your network. +To clean up the build, coverage and test reports run: -2. Restart Docker: +``` +pnpm clean +``` +## Full Guide - ``` - sudo systemctl restart docker - ``` +- [Set up a Paid Nostr relay with Nostream and ZEBEDEE](https://docs.zbdpay.com/payments/nostr/nostr-relay) by [André Neves](https://primal.net/andre) (CTO & Co-Founder at [ZEBEDEE](https://zebedee.io/)) +- [Set up a Nostr relay in under 5 minutes](https://andreneves.xyz/p/set-up-a-nostr-relay-server-in-under) by [André Neves](https://twitter.com/andreneves) (CTO & Co-Founder at [ZEBEDEE](https://zebedee.io/)) -3. Verify DNS works inside containers: +### Accepting Payments - ``` - docker run --rm busybox nslookup registry.npmjs.org - ``` +1. Before you begin + - Complete one of the Quick Start guides in this document + - Create a `.env` file + - On `.nostr/settings.yaml` file make the following changes: + - Set `payments.enabled` to `true` + - Set `payments.feeSchedules.admission.enabled` to `true` + - Set `limits.event.pubkey.minBalance` to the minimum balance in msats required to accept events (i.e. `1000000` to require a balance of `1000` sats) + - Choose one of the following payment processors: `zebedee`, `nodeless`, `opennode`, `lnbits`, `lnurl`, `nwc` -4. Retry starting nostream: +2. [ZEBEDEE](https://zebedee.io) + - Complete the step "Before you begin" + - [Sign up for a ZEBEDEE Developer Dashboard account](https://dashboard.zebedee.io/signup), create a new LIVE Project, and get that Project's API Key + - Set `ZEBEDEE_API_KEY` environment variable with the API Key above on your `.env` file - ``` - nostream start - ``` +``` + ZEBEDEE_API_KEY={YOUR_ZEBEDEE_API_KEY_HERE} +``` -Note: avoid `127.0.0.53` in Docker DNS settings because it points to the host's -local resolver stub and is often unreachable from containers. + - Follow the required steps for all payments processors + - On `.nostr/settings.yaml` file make the following changes: + - `payments.processor` to `zebedee` + - `paymentsProcessors.zebedee.callbackBaseURL` to match your Nostream URL (e.g. `https://{YOUR_DOMAIN_HERE}/callbacks/zebedee`) + - Restart Nostream (`nostream stop` followed by `nostream start`) + - Read the in-depth guide for more information: [Set Up a Paid Nostr Relay with ZEBEDEE API](https://docs.zbdpay.com/payments/nostr/nostr-relay) -## Quick Start (Standalone) +3. [Nodeless](https://nodeless.io/?ref=587f477f-ba1c-4bd3-8986-8302c98f6731) + - Complete the step "Before you begin" + - [Sign up](https://nodeless.io/?ref=587f477f-ba1c-4bd3-8986-8302c98f6731) for a new account, create a new store and take note of the store ID + - Go to Profile > API Tokens and generate a new key and take note of it + - Create a store webhook with your Nodeless callback URL (e.g. `https://{YOUR_DOMAIN_HERE}/callbacks/nodeless`) and make sure to enable all of the events. Grab the generated store webhook secret + - Set `NODELESS_API_KEY` and `NODELESS_WEBHOOK_SECRET` environment variables with generated API key and webhook secret, respectively -Set the following environment variables: +``` + NODELESS_API_KEY={YOUR_NODELESS_API_KEY} + NODELESS_WEBHOOK_SECRET={YOUR_NODELESS_WEBHOOK_SECRET} +``` - ``` - DB_URI="postgresql://postgres:postgres@localhost:5432/nostr_ts_relay_test" - DB_USER=postgres - ``` - or - ``` - DB_HOST=localhost - DB_PORT=5432 - DB_NAME=nostr_ts_relay - DB_USER=postgres - DB_PASSWORD=postgres - ``` - - ``` - REDIS_URI="redis://default:nostr_ts_relay@localhost:6379" - - REDIS_HOST=localhost - REDIS_PORT=6379 - REDIS_USER=default - REDIS_PASSWORD=nostr_ts_relay - ``` + - On your `.nostr/settings.yaml` file make the following changes: + - Set `payments.processor` to `nodeless` + - Set `paymentsProcessors.nodeless.storeId` to your store ID + - Restart Nostream (`nostream stop` followed by `nostream start`) -Generate a long random secret and set SECRET: -You may want to use `openssl rand -hex 128` to generate a secret. +4. [OpenNode](https://www.opennode.com/) + - Complete the step "Before you begin" + - Sign up for a new account and get verified + - Go to Developers > Integrations and setup two-factor authentication + - Create a new API Key with Invoices permission + - Set `OPENNODE_API_KEY` environment variable on your `.env` file - ``` - SECRET=aaabbbccc...dddeeefff - # Secret shortened for brevity - ``` + ``` + OPENNODE_API_KEY={YOUR_OPENNODE_API_KEY} + ``` -### Initializing the database + - On your `.nostr/settings.yaml` file make the following changes: + - Set `payments.processor` to `opennode` + - Restart Nostream (`nostream stop` followed by `nostream start`) -Create `nostr_ts_relay` database: +5. [LNBITS](https://lnbits.com/) + - Complete the step "Before you begin" + - Create a new wallet on you public LNbits instance + - [Demo](https://legend.lnbits.com/) server must not be used for production + - Your instance must be accessible from the internet and have a valid SSL/TLS certificate + - Get wallet Invoice/read key (in Api docs section of your wallet) + - set `LNBITS_API_KEY` environment variable with the Invoice/read key Key above on your `.env` file - ``` - $ psql -h $DB_HOST -p $DB_PORT -U $DB_USER -W - postgres=# create database nostr_ts_relay; - postgres=# quit - ``` + ``` + LNBITS_API_KEY={YOUR_LNBITS_API_KEY_HERE} + ``` + - On your `.nostr/settings.yaml` file make the following changes: + - Set `payments.processor` to `lnbits` + - set `lnbits.baseURL` to your LNbits instance URL (e.g. `https://{YOUR_LNBITS_DOMAIN_HERE}/`) + - Set `paymentsProcessors.lnbits.callbackBaseURL` to match your Nostream URL (e.g. `https://{YOUR_DOMAIN_HERE}/callbacks/lnbits`) + - Restart Nostream (`nostream stop` followed by `nostream start`) -Start Redis and use `redis-cli` to set the default password and verify: - ``` - $ redis-cli - 127.0.0.1:6379> CONFIG SET requirepass "nostr_ts_relay" - OK - 127.0.0.1:6379> AUTH nostr_ts_relay - Ok - ``` +6. [Alby](https://getalby.com/) or any LNURL Provider with [LNURL-verify](https://github.com/lnurl/luds/issues/182) support + - Complete the step "Before you begin" + - [Create a new account](https://getalby.com/user/new) if you don't have an LNURL + - On your `.nostr/settings.yaml` file make the following changes: + - Set `payments.processor` to `lnurl` + - Set `lnurl.invoiceURL` to your LNURL (e.g. `https://getalby.com/lnurlp/your-username`) + - Restart Nostream (`nostream stop` followed by `nostream start`) -Clone repository and enter directory: - ``` - git clone git@github.com:Cameri/nostream.git - cd nostream - ``` +7. Nostr Wallet Connect (NIP-47 / NWC) + - Complete the step "Before you begin" + - Create an app connection in your NWC-compatible wallet and copy the generated NWC URL + - Set `NWC_URL` environment variable on your `.env` file -Install dependencies: + ``` + NWC_URL={NOSTR_WALLET_CONNECT_URL} + ``` - ``` - corepack enable - pnpm install - ``` + - On your `.nostr/settings.yaml` file make the following changes: + - Set `payments.processor` to `nwc` + - Restart Nostream (`nostream stop` followed by `nostream start`) -Run migrations (at least once and after pulling new changes): +8. Ensure payments are required for your public key + - Visit https://{YOUR-DOMAIN}/ + - You should be presented with a form requesting an admission fee to be paid + - Fill out the form and take the necessary steps to pay the invoice + - Wait until the screen indicates that payment was received + - Add your relay URL to your favorite Nostr client (wss://{YOUR-DOMAIN}) and wait for it to connect + - Send a couple notes to test + - Go to https://websocketking.com/ and connect to your relay (wss://{YOUR_DOMAIN}) + - Convert your npub to hexadecimal using a [Key Converter](https://damus.io/key/) + - Send the following JSON message: `["REQ", "payment-test", {"authors":["your-pubkey-in-hexadecimal"]}]` + - You should get back the few notes you sent earlier - ``` - pnpm db:migrate - ``` +## Running as a Service -Create .nostr folder inside nostream project folder and copy over the settings file: +By default this server will run continuously until you stop it with Ctrl+C or until the system restarts. - ``` - mkdir .nostr - cp resources/default-settings.yaml .nostr/settings.yaml - ``` +You can [install as a systemd service](https://www.swissrouting.com/nostr.html#installing-as-a-service) if you want the server to run again automatically whenever the system is restarted. For example: -To start in development mode: +``` +$ nano /etc/systemd/system/nostream.service + +# Note: replace "User=..." with your username, and +# "/home/nostr/nostream" with the directory where you cloned the repo. + +[Unit] +Description=Nostr TS Relay +After=network.target +StartLimitIntervalSec=0 + +[Service] +Type=simple +Restart=always +RestartSec=5 +User=nostr +WorkingDirectory=/home/nostr/nostream +ExecStart=/usr/bin/env bash -lc 'cd /home/nostr/nostream && nostream start' +ExecStop=/usr/bin/env bash -lc 'cd /home/nostr/nostream && nostream stop' + +[Install] +WantedBy=multi-user.target +``` - ``` - pnpm dev - ``` +And then: -Or, start in production mode: +``` +systemctl enable nostream +systemctl start nostream +``` - ``` - pnpm start - ``` +The logs can be viewed with: -To clean up the build, coverage and test reports run: +``` +journalctl -u nostream +``` - ``` - pnpm clean - ``` ## Development & Contributing For development environment setup, testing, linting, load testing, and contribution guidelines @@ -606,38 +577,92 @@ corresponding data from the derived `event_tags` table when present. Dry run (no deletion): - ``` - nostream dev db:clean --all --dry-run - ``` +``` +nostream dev db:clean --all --dry-run +``` Full wipe: - ``` - nostream dev db:clean --all --force - ``` +``` +nostream dev db:clean --all --force +``` Delete events older than N days: - ``` - nostream dev db:clean --older-than=30 --force - ``` +``` +nostream dev db:clean --older-than=30 --force +``` Delete only selected kinds: - ``` - nostream dev db:clean --kinds=1,7,4 --force - ``` +``` +nostream dev db:clean --kinds=1,7,4 --force +``` Delete only selected kinds older than N days: - ``` - nostream dev db:clean --older-than=30 --kinds=1,7,4 --force - ``` +``` +nostream dev db:clean --older-than=30 --kinds=1,7,4 --force +``` By default, the command asks for explicit confirmation (`Type 'DELETE' to confirm`). Use `--force` to skip the prompt. +## Troubleshooting + +### Linux: Docker DNS resolution failures (`EAI_AGAIN`) + +On some Linux environments (especially rolling-release distros or setups using +`systemd-resolved`), `docker compose` builds can fail with DNS errors such as: + +- `getaddrinfo EAI_AGAIN registry.npmjs.org` +- `Temporary failure in name resolution` + +To fix this, configure Docker daemon DNS in `/etc/docker/daemon.json`. + +1. Create or update `/etc/docker/daemon.json`: + +``` +sudo mkdir -p /etc/docker +sudo nano /etc/docker/daemon.json +``` + + Add or update the file with: + +``` +{ + "dns": ["1.1.1.1", "8.8.8.8"] +} +``` + + If this file already exists, merge the `dns` key into the existing JSON + instead of replacing the entire file. + + If your environment does not allow public resolvers, replace `1.1.1.1` and + `8.8.8.8` with DNS servers approved by your network. + +2. Restart Docker: + +``` +sudo systemctl restart docker +``` + +3. Verify DNS works inside containers: + +``` +docker run --rm busybox nslookup registry.npmjs.org +``` + +4. Retry starting nostream: + +``` +nostream start +``` + +Note: avoid `127.0.0.53` in Docker DNS settings because it points to the host's +local resolver stub and is often unreachable from containers. + ## Configuration You can change the default folder by setting the `NOSTR_CONFIG_DIR` environment variable to a different path. From dd55552cd28dbc985518f26900f997c2a131a6c3 Mon Sep 17 00:00:00 2001 From: chappie-daemon Date: Fri, 16 Oct 2026 19:36:29 -0400 Subject: [PATCH 4/5] =?UTF-8?q?docs:=20drop=20the=20changeset=20=E2=80=94?= =?UTF-8?q?=20a=20README=20change=20does=20not=20release=20the=20website?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/readme-website-link.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/readme-website-link.md diff --git a/.changeset/readme-website-link.md b/.changeset/readme-website-link.md deleted file mode 100644 index 36962d3c4..000000000 --- a/.changeset/readme-website-link.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"nostream-website": patch ---- - -README now links the project website (ema.tnsor.network) from the intro. From 286dab5a96b8ff979d5f83bac3584d88cbba1b30 Mon Sep 17 00:00:00 2001 From: chappie-daemon Date: Fri, 16 Oct 2026 19:43:22 -0400 Subject: [PATCH 5/5] =?UTF-8?q?docs:=20add=20an=20empty=20changeset=20?= =?UTF-8?q?=E2=80=94=20docs-only=20change,=20no=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/ten-radios-sniff.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changeset/ten-radios-sniff.md diff --git a/.changeset/ten-radios-sniff.md b/.changeset/ten-radios-sniff.md new file mode 100644 index 000000000..a845151cc --- /dev/null +++ b/.changeset/ten-radios-sniff.md @@ -0,0 +1,2 @@ +--- +---