nsyte — Decentralized Static Site Deployment
nsyte is a Deno-based CLI that publishes static websites to the Nostr network using Blossom servers for file storage. Sites are content-addressed (SHA-256), censorship-resistant, and discoverable via Nostr relays.
Key concepts: For Nostr/Blossom domain knowledge (relays, pubkeys, nsec, NIP-46, events), see references/nostr-concepts.md.
Installation
Check if installed
If this prints a version string, skip to
Project Setup.
Linux / macOS (recommended — no Deno required)
bash
curl -fsSL https://nsyte.run/get/install.sh | bash
Installs to
. Use
if that directory is not writable.
Linux / macOS (alternative — requires Deno 2.x)
bash
deno install -A -f -g -n nsyte jsr:@nsyte/cli
Windows
Download the latest binary from
https://github.com/sandwichfarm/nsyte/releases
, place in
, and add that directory to PATH.
Troubleshooting installation
- Command not found: Add to PATH in or and reload.
- Permission denied: Use for the curl install, or install to a user-writable location.
- Deno version too old: Run or use the binary install instead.
Project Setup
bash
cd /path/to/your/project
nsyte init
Interactive prompts ask for:
- Auth method — generate new key, enter existing nsec/hex key, or connect NIP-46 bunker
- Relay URLs — one or more relay WebSocket URLs
- Blossom server URLs — one or more Blossom server URLs
On success, creates
. See
Configuration for the schema.
Configuration
For the full JSON Schema, see assets/config.schema.json.
Required fields
| Field | Type | Description |
|---|
| | Nostr relay URLs (), unique items |
| | Blossom server URLs (), unique items |
Authentication
| Field | Type | Description |
|---|
| | 64-char hex pubkey for NIP-46 bunker. Pattern: . Always set via , never manually. |
Site identity
| Field | Type | Default | Description |
|---|
| | | /empty = root site (kind 15128). Non-empty = named site (kind 35128) |
| | — | Site title for manifest event |
| | — | Site description for manifest event |
| | — | 404 fallback HTML path (e.g., for SPAs) |
Publishing flags (root sites only — must be null/empty)
| Field | Type | Description |
|---|
| | Publish kind 0 profile metadata. Requires non-empty object |
| | Publish kind 10002 relay list |
| | Publish kind 10063 Blossom server list |
| | Publish NIP-89 handler. Requires with |
Optional objects
| Field | Type | Description |
|---|
| | Nostr profile: , , , , , , , , |
| | NIP-89 config: (required), , , , , |
| | Gateway hostnames (default: ) |
Example configs
Minimal (root site):
json
{
"relays": ["wss://relay.damus.io", "wss://nos.lol"],
"servers": ["https://cdn.hzrd149.com"]
}
Named site (blog):
json
{
"relays": ["wss://relay.damus.io"],
"servers": ["https://cdn.hzrd149.com"],
"id": "blog",
"title": "My Blog",
"description": "A blog about decentralized applications"
}
With profile publishing:
json
{
"relays": ["wss://relay.damus.io", "wss://nos.lol"],
"servers": ["https://cdn.hzrd149.com"],
"publishProfile": true,
"publishRelayList": true,
"publishServerList": true,
"profile": {
"name": "Alice",
"display_name": "Alice",
"about": "Decentralization enthusiast",
"picture": "https://example.com/avatar.jpg",
"nip05": "alice@example.com",
"lud16": "alice@getalby.com"
}
}
With NIP-89 app handler:
json
{
"relays": ["wss://relay.damus.io"],
"servers": ["https://cdn.hzrd149.com"],
"publishAppHandler": true,
"appHandler": {
"kinds": [1, 30023],
"name": "My Nostr Viewer",
"description": "A viewer for notes and articles",
"icon": "https://example.com/logo.png"
}
}
Interactive config editor
Requires an interactive terminal. Keys:
/
navigate,
edit,
save,
reset,
quit.
For non-interactive contexts, edit
directly and validate:
Authentication
NIP-46 Bunker (recommended)
Connect via QR code
Choose "Scan QR Code", enter a relay URL, scan with signer app (Amber, nsec.app), approve.
Connect via bunker URL
bash
nsyte bunker connect 'bunker://pubkey?relay=wss://relay.example.com&secret=xxx'
CRITICAL: Always single-quote the URL —
and
are shell metacharacters.
Link bunker to project
bash
nsyte bunker use [pubkey]
Sets
in config and stores nbunksec in OS keychain.
Never manually edit .
Bunker management commands
| Command | Purpose |
|---|
| Connect interactively (QR or URL) |
nsyte bunker connect '<url>'
| Connect via bunker URL |
nsyte bunker import nbunksec1...
| Import existing nbunksec |
nsyte bunker export [pubkey]
| Export stored bunker as nbunksec |
| List stored bunkers |
nsyte bunker use [pubkey]
| Set project to use a bunker |
nsyte bunker remove [pubkey]
| Remove a bunker from storage |
nsyte bunker migrate [pubkeys...]
| Rebuild keychain index |
Secrets storage
nsyte auto-selects the best backend:
- macOS: Keychain
- Linux: Secret Service (fallback: encrypted file)
- Windows: Credential Manager (fallback: encrypted file)
Override with
NSYTE_FORCE_ENCRYPTED_STORAGE=true
.
Deployment
Basic deploy
Auth resolution order
-
bash
nsyte deploy ./dist --sec "nsec1..."
nsyte deploy ./dist --sec "${NBUNK_SECRET}"
Auto-detects format:
,
,
, or 64-char hex.
-
Stored bunker from
+ OS keychain.
-
If neither available, nsyte exits with an error.
Common flags
| Flag | Purpose |
|---|
| Provide signing key/credential |
| Re-upload all files (skip diff) |
| SPA fallback for 404s |
| CI mode — no prompts, fail fast |
Interpreting output
- Full success:
{N} files uploaded successfully ({size})
— all files to all servers
- Partial success:
{uploaded}/{total} files uploaded
— some servers failed
- Total failure:
Failed to upload any files
— check relay/server/auth errors
Gateway URL printed after deploy:
https://{npub}.nsite.lol/
CI/CD
Step 1: Generate CI credential (one-time, on dev machine)
bash
nsyte ci
# or with bunker URL:
nsyte ci 'bunker://pubkey?relay=wss://relay.example.com&secret=xxx'
The
string is printed once and never stored. Copy it immediately and save as a CI secret.
Step 2: Deploy in pipeline
bash
nsyte deploy ./dist --non-interactive --sec "${NBUNK_SECRET}"
GitHub Actions example
yaml
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: denoland/setup-deno@v1
- run: nsyte deploy ./dist --non-interactive --sec "${{ secrets.NBUNK_SECRET }}"
CI checklist
Other Commands
| Command | Purpose |
|---|
| List published files |
| Interactive TUI file browser with relay/server propagation tracking |
| Download published files |
| Local dev server |
| Start resolver server with npub subdomains |
| Debug nsite setup (relays, servers, integrity) |
| Validate config (exit 0 = valid, 1 = invalid) |
| Remove published files from relays/servers |
| List available sites (root + named) |
Troubleshooting
Auth errors
- "No valid signing method": Provide or configure bunker via .
- "No stored credential": set in config but keychain entry missing. Fix:
nsyte bunker use [pubkey]
.
- Bunker URL rejected: Shell ate metacharacters. Use single quotes: .
Deploy errors
- Relay issues: Check array in config has valid URLs. Try .
- Blossom server rejection: Check array. Try adding a different server via .
- Config missing: Run first.
Config errors
- "Config editor requires interactive terminal": Edit JSON directly + .
- Validation fails: Common causes: malformed URLs, without , on named site.
- bunkerPubkey format: Must be 64 hex chars, not npub. Always use .