Nostr Web (nweb)

Nostr Web (nweb): Reference Notes

Updated 2026-11-03. Checked against the nw-nips and nw-publisher READMEs and our relay’s info document. Not yet verified by an actual test publish. The project is young and moving, so check the repos before relying on any detail.

What it is, in one paragraph

Nostr Web lets you publish a static website without a web host. Each file (HTML, CSS, JS, images, fonts) is signed with your Nostr key and published as an event to Nostr relays. A browser extension then lets visitors type a normal domain name, finds the site’s relays via DNS, downloads the events, checks the signatures, and builds the page locally.

It is made by Shugur, who also make a Nostr relay. It is not an official Nostr standard yet (the specs are drafts, numbered “NIP-YY” and “NIP-ZZ” as placeholders).

Are the domains real?

Yes. They are ordinary domains from any registrar. Nothing is sold by the project and there is no special “web3” TLD.

DNS is used only for discovery. You add one TXT record at _nweb.yourdomain.com. The publisher generates the value for you (see below). It is JSON like this:

Host:  _nweb.yourdomain.com
Type:  TXT
Value: {"pk":"npub1...","relays":["wss://relay.one","wss://relay.two"]}
  • pk is the site’s public key, so the extension knows whose signatures to trust.
  • relays lists where the site’s events are published.

The extension checks for that record whenever you visit a domain. If found, it loads the site from the relays. If not, you get the normal website.

This is why the demo at https://nweb.shugur.com shows a “you need the extension” page in a normal browser: the domain’s ordinary web hosting serves a plain landing page, and the extension swaps in the Nostr version. The project describes this dual behaviour as deliberate.

How it works (the technical bit)

Four Nostr event kinds (from the draft spec, NIP-YY):

KindNameTypeWhat it holds
1125AssetRegularOne file (HTML/CSS/JS/image/font), with MIME type and SHA256 hash
1126Page manifestRegularThe assets that make up one route
31126Site indexAddressableMaps routes to page manifests; each version is kept
11126EntrypointReplaceablePoints to the current site index

NIP-ZZ defines the DNS TXT record.

Smart caching: on every deploy the publisher asks the relays what already exists and only uploads new or changed files (matched by SHA256). There is no local cache, so the relays are the source of truth and it works from any machine.

Versions: each deploy gets a version number, auto-incremented (patch for content changes, minor when routes are added or removed) or set with --version=X.Y.Z.

The pieces

PieceWhat it isWhere
SpecsThe draft NIPshttps://github.com/Shugur-Network/nw-nips
ExtensionVisitor-side browser. Chrome (v1.1.0 at last check) and Firefox. The publisher README says v0.9.6+ is neededLinked from the nw-nips README
PublisherNode CLI, npm package nw-publisher (v1.3.4 at last check)https://github.com/Shugur-Network/nw-publisher
RelayShugur’s relay (v1.3.5+) validates and hosts these kindshttps://github.com/Shugur-Network/relay
DemoLanding page that doubles as a demo sitehttps://nweb.shugur.com

The extension’s repo is spelled nw-extention (sic) on GitHub. Project size at last check: specs 28 stars, publisher 9 stars, one vendor behind everything.

Installing the publisher

The publisher is a Node.js program, so Node (which includes npm) has to be on whatever machine you publish from. It runs only while you deploy, and nothing needs to keep running afterwards. There is no standalone binary.

The README offers two install routes, but they lead to the same tool:

  • npm install -g nw-publisher downloads the finished package from the npm registry. Use this one.
  • “From source” (clone the repo, npm install, npm link) is for people who want to modify the code. Ignore it.

Suggested route on a laptop: install nvm, run nvm install --lts, then npm install -g nw-publisher. With nvm everything lives in the home directory, so deleting nvm removes Node and the publisher together. A throwaway Docker container is another clean option.

How-to: publishing a static site

  1. Have a fully static site in a folder: plain HTML, CSS, JS and images. No PHP, no server-side code, no server-side form handling.
  2. Make a dedicated Nostr keypair for the site. The README uses npx nostr-tools keygen. This key is the site’s identity and the DNS record points at it. Lose it and you can’t update the site.
  3. Create a .env file:NOSTR_SK_HEX=<private key, 64-char hex> RELAYS=wss://relay1,wss://relay2 NWEB_HOST=yourdomain.com
  4. Deploy: nw-publisher deploy <site-folder> (for example nw-publisher deploy .)
  5. Add the DNS record. The deploy writes _nweb.txt (instructions) and _nweb.txt.json (the value, ready to paste) into the site folder.
  6. Test: install the extension, visit the domain, and confirm the Nostr version loads from a different network.
  7. Keep your normal hosting at the domain if you want ordinary browsers to see something.

Other commands

CommandDoes
nw-publisher status [npub]Checks relay connectivity and site health
nw-publisher versions list/show/compareQueries version history
nw-publisher syncMakes sure every version exists on every configured relay (use after adding relays)
nw-publisher cleanup [--orphans / --version X / --all] [--dry-run] [--relay URL]Sends deletion requests (kind 5) for old or orphaned events. Always try --dry-run first

Warning: keep the private key out of the published folder

The README’s quick start creates .env (with the private key) inside the site folder. We haven’t checked whether deploy skips hidden files. If it doesn’t, the key could be published as an asset. Before the first deploy:

  • Read src/ to see how files are scanned and excluded, or run a test from a folder with no secrets.
  • Use a throwaway key for the first test.
  • Never commit .env to git.

Our relay (relay.directsponsor.net)

Info document checked 2026-11-03 (curl -H "Accept: application/nostr+json" https://relay.directsponsor.net):

  • strfry 1.1.0, supports NIPs 1, 2, 4, 9, 11, 28, 40, 45, 70, 77
  • max_message_length 131072, max_limit 500, max_subscriptions 20
  • No auth fields shown (strfry doesn’t report them, so this proves nothing either way)

Still to check:

  • Are reads open to anonymous visitors? Test over wss:// from outside our network: send ["REQ","t",{"kinds":[1],"limit":1}] and look for events or ["EOSE","t"]. This decides whether visitors can load the site from it.
  • Event size. strfry’s maxEventSize (in strfry.conf) isn’t exposed. The default is about 64 KB, and the publisher README also warns of ~64 KB limits. It mentions no chunking, so large images or fonts may fail.
  • Any writePolicy plugin or proxy rules that restrict who can write or read. The site key must be allowed to write kinds 1125, 1126, 31126 and 11126.
  • Subscription limit of 20. Watch for slow or partial page loads if the extension opens many queries at once.

Privacy decision: opening read access exposes everything on that relay. If the relay holds anything private, run a second strfry instance (own port or subdomain) for site events only, with open reads and writes limited to the site key. Our relay supports NIP-9, so cleanup should work there to reset a failed test.

Limits and caveats

  • Visitors need the extension. Normal browsers see only whatever the domain’s regular hosting serves. The authors say a no-extension gateway is planned but they don’t favour it, as it would be a central point of failure.
  • Static only. No PHP, no JSON flat-file logic, no logins, no server-side forms, nothing transactional.
  • Deletion depends on the relay. cleanup sends deletion requests, which relays may or may not honour. On relays we don’t run, treat published content as permanent.
  • Relay dependence. The site exists only while enough relays keep storing its events. Use our relay plus one or two public ones, and run sync after adding relays. Some public relays may reject these kinds or large events.
  • Early and small. Placeholder NIP numbers, small star counts, one vendor.
  • Trust friction. Asking visitors to install an extension is a real barrier, as the Show HN commenters pointed out.

Possible uses for our sites

  • A signed, censorship-resistant mirror of static info pages (what the project is, how sponsorship works), alongside the normal site rather than replacing it.
  • An experiment in keeping with the lean, no-framework approach.
  • Not suitable as the primary host for anything dynamic or payment-related.

Links


What about opening our relays as read-only? Would that make it available?

Yes, in principle. The extension fetches events straight from the relays named in your DNS record, so any visitor with the extension can load the site if your relay serves it to them. Read access is what matters, and write access can stay locked.

What the relay needs for visitors to load the site:

  • Reachable over wss://. That means a domain, a TLS certificate and a reverse proxy. A browser extension will almost certainly refuse plain ws://.
  • Open reads. No auth required to query. If you have NIP-42 auth or an IP allowlist, the extension can’t get through.
  • No aggressive rate limiting on connections or subscriptions. The extension fetches many events in parallel (one per asset), so tight limits would break page loads.
  • Your site key can write. It has to be allowed to publish kinds 1125, 1126, 31126 and 11126, and the other three are replaceable or addressable, which strfry handles natively.
  • Event size limits high enough for your assets. strfry has a configurable maximum event size, so check strfry.conf against your largest image or font. I don’t know whether the publisher splits big files, so I’d test it.

One important decision: opening read access exposes everything on that relay to everyone, not just the site events. If it holds anything you wouldn’t want public, such as DMs or a private feed, don’t open it. The cleaner option is a second strfry instance on its own port or subdomain, just for the site events, with read open and writes limited to your site key. strfry supports a write-policy plugin for that. It also means your private relay stays private.

Publishing to a couple of public relays as well gives you a fallback, but with yours as the main one.

I’d test before committing to it. Publish a tiny test page (a single HTML file) to the relay, add the _nweb TXT record on a spare subdomain, and load it with the extension from a different network.


paste this into the IDE:

Context: I’m evaluating Nostr Web (nweb) for our static pages. It publishes a static
site as signed Nostr events (kinds 1125 asset, 1126 page manifest, 31126 site index,
11126 entrypoint) to relays. A browser extension finds the site via a DNS TXT record at
_nweb. (holds the site’s pubkey and relay URLs), fetches the events, verifies
signatures and renders the page. Visitors need the extension. Static only.

Repos (clone and read them directly):

I have a wiki note, nostr-web.md, with what’s been established so far. Its how-to
section is an outline only, because the specs and publisher README weren’t readable
earlier.

Our relay: wss://relay.directsponsor.net (strfry 1.1.0-4, currently private).
Its NIP-11 info doc shows: max_message_length 131072, max_limit 500,
max_subscriptions 20, supported NIPs 1,2,4,9,11,28,40,45,70,77. It does not show
whether reads are open, who can write, or strfry’s maxEventSize.

Goal: find out whether we can publish a small static test page to our relay and have
it load for any visitor with the extension.

Tasks, in order:

  1. Read NIP-YY.md, NIP-ZZ.md and the nw-publisher README. Tell me:
    • the exact TXT record format for _nweb.
    • the publisher’s CLI commands and flags, and how it handles keys and relays
    • how it handles files larger than the event size limit (chunking or not)
    • how the extension fetches (parallelism, subscription count vs our limit of 20)
  2. Read our strfry.conf: maxEventSize, any writePolicy plugin, any read restrictions,
    and any proxy config (nginx or similar) in front of the relay that could block
    anonymous reads or limit websockets.
  3. Test anonymous read access over wss:// from outside our network (or tell me how if
    you can’t). Send [“REQ”,”t”,{“kinds”:[1],”limit”:1}] and report what comes back.
  4. Don’t change production relay config without asking me first. If reads or writes
    need changing, propose options. My preferred option is a second strfry instance on
    its own port or subdomain just for site events (open reads, writes limited to the
    site key), so the private relay stays private.
  5. Once steps 1 to 3 look fine, walk me through a minimal test publish: one small HTML
    file, a dedicated site keypair, a spare subdomain for the TXT record, then a load
    test with the extension from a different network.
  6. Update nostr-web.md with the verified details (TXT format, real commands, limits)
    and remove the “check the README” caveats that are no longer needed.

Constraints: the publisher needs Node, which is outside our usual zero-dependency
stack, so keep it isolated as a deploy tool and don’t add it to the site projects.
Report plainly what’s verified and what isn’t. Don’t guess at command flags or record
formats.