1---2title: NIP-5A static websites3audience: user4---56# NIP-5A static websites78Status: `draft` and `optional` upstream. bind.ws follows [`5A.md` at9commit 5d6b432267d4046464490b1923b96844ac4559d0](https://raw.githubusercontent.com/nostr-protocol/nips/5d6b432267d4046464490b1923b96844ac4559d0/5A.md),10last checked 2026-09-04.1112## Use a relay as a site host1314NIP-5A stores a website as a signed Nostr event. Each `path` tag maps an15absolute filename to the SHA-256 hash of a file on Blossom. The relay stores16the event and files, then serves the site from a single-label hostname.1718| Kind | Address | Purpose |19|---|---|---|20| 15128 | `https://<npub>.bind.ws` | author's root site |21| 35128 | `https://<pubkeyB36><dTag>.bind.ws` | named site |22| 5128 | `https://v<snapshotIdB36>.bind.ws` | manifest snapshot |2324Publish with an existing NIP-5A client such as nsyte or nsite-cli. The relay25does not provide a publishing CLI. A path must be an absolute filename with26an extension and a lowercase 64-character SHA-256 hash. The optional `x` tag27is checked against the order-independent aggregate of the `path` tags.2829The `pubkeyB36` and `snapshotIdB36` portions encode the 32-byte value in30lowercase base36 and are exactly 50 characters wide. This fixed width keeps31leading zero bytes, resolving the draft's conflict between "no padding" and32"always exactly 50 characters." Kind 34128 is deprecated by NIP-5A and is not33hosted by the NIP-5A site door; generic relay event policy may still accept it.3435Directories select `index.html`: `/` selects `/index.html`, and `/blog/`36selects `/blog/index.html`. A missing path selects the site's `/404.html` when37present and otherwise returns 404. A missing manifest, missing file, hash38mismatch, unavailable blob, or failed remote fetch returns a plain 404.39Responses forward the stored content type and length, use the blob hash as the ETag,40and verify the blob before serving it. `Cache-Control: no-transform` keeps41intermediaries from changing the verified representation or its validators.4243The relay's Rules > Reads setting applies to sites. Open reads make a site44public; signed-in and members-only reads require the same admission as the45relay's other read doors. Site hosting is enabled by default and can be46switched off under the `sites` feature. NIP-40 `expiration` and the relay's47retention policy determine lifetime.4849Snapshots copy the source `path` tags, carry one matching aggregate `x` tag50and one `a` tag naming the source. Copies retain their immediate parent in51`a` and their lineage origin in `A`.5253## Sign-in5455When your relay's read rule admits everyone, site requests are public. When56the rule requires sign-in, a browser GET that accepts HTML receives a NIP-0757sign-in page. The page creates a five-minute challenge and asks your browser58signer to sign kind 22242 with the site origin and challenge. It then posts59that event as JSON to `/.well-known/nsite/auth`, with an exact NIP-98 proof for60the POST URL, method and body.6162After verification, your relay signs a host-only `__Host-nsite` cookie. The63cookie is Secure, HttpOnly, SameSite=Lax, and lasts seven days. Every site64request checks the cookie against the current read rule. API clients can use65an exact NIP-98 Authorization header directly. Passwords are not part of the66site protocol.6768## Relay additions6970The NIP-11 information document exposes an `nsites` object while site hosting71is enabled:7273```json74{75 "host": "bind.ws",76 "kinds": [15128, 35128, 5128],77 "root": "https://<npub>.bind.ws",78 "named": "https://<pubkeyB36><dTag>.bind.ws",79 "snapshot": "https://v<snapshotIdB36>.bind.ws"80}81```8283The relay keeps a KV index from each site label to the relay holding its84manifest. It also mirrors missing blobs into its own bucket when85`sites.mirror` is on (the default), checking hashes before storing them.86Mirroring is one job per manifest. It tries up to ten `server` tags from the87manifest and then up to ten servers from the author's kind 10063. Sources88must be public HTTPS URLs (or a local sibling relay), redirects are checked89again, credentials are never forwarded, and the size cap is the smaller of90the relay's `maxBlobMB` and 32 MiB. Bad hashes, failed checks, and oversized91files are never stored. Remote bytes and served bytes appear in the traffic meters but have no fuel92price. Stored mirrors share the file allowance; request work contributes to93the relay's estimated awake-time meter.9495If mirroring is disabled, the site door still proxies a cache miss using the96same checks and cap. A file is retried at most three times; a failed job stops97and can be rerun. Deleting or replacing a manifest stops its pending mirror98work. A local R2 blob is also available through the relay's implicit Blossom99provider, so a manifest need not contain server tags.100101Sites have their own origin. A site hostname reaches only the site door and102does not expose the relay console, websocket, management methods or Blossom103API. A custom domain may be pointed at a relay or one of its sites from the104owner's domain controls; the same read rule remains in force. The management105calls are `adddomain(host, site?)` and `setdomainsite(host, site?)`, where an106omitted or empty site selects the relay itself. `listdomains` returns the107selected site label. The console offers relay, root, named-site and snapshot108destinations.109110The edge mapping may remain cached for up to 60 seconds. The local record111checks that the selected site still exists before it serves a request, so a112stale mapping cannot serve a removed target.113114Manifest replacements coalesce into one index write per hostname in each115outbox batch. The route stays present while a throttled write waits for a116retry; replacing a manifest does not delete and recreate its hostname.117118## Deliberate limits119120Supporting Nostr clients can resolve a hosted site URL through121[NIP-AD web addresses](23-nip-ad-web-addresses.md). Discovery maps existing122site paths to the live manifest under the same site authentication and read123rules, with the hosting relay as its hint. Custom site domains retain their124site origin; discovery does not open the hosting relay's other HTTP doors.125126bind.ws advertises `5A` in `supported_nips` when sites are enabled and the127owner opts into lettered NIP identifiers (or enables relay push). Numeric128entries keep their JSON number type. `nsites` remains available while sites129are enabled, including in the default numeric-only mode. Some clients reject130lettered entries; see [NIP-11 identifier compatibility](26-nip11-compatibility.md).131`5A` is a literal identifier, never decimal 90.132133The implementation tracks upstream changes to the label grammar, aggregate134hash, snapshot and copy tags, and the status of kind 34128. If those change,135the parser, host templates and this document must change together.