wisp
wisp - a lightweight nostr relay

A fast, lightweight nostr relay written in Zig.
Why Wisp?
- Fast: ~9x higher throughput than strfry, sub-millisecond p99 latency
- Small: Single binary, ~11MB RAM at idle
- Simple: One command to run your personal relay with your feed
- Spider Mode: Automatically syncs events from people you follow
Quickstart
Docker
docker run -d -p 7777:7777 -v wisp-data:/data ghcr.io/privkeyio/wisp --spider-admin npub1yourkey...
Build from source
Download the latest release or build from source:
# 1. Install dependencies (requires Zig 0.16.0)
sudo apt install -y liblmdb-dev libsecp256k1-dev libssl-dev
# 2. Build
git clone https://github.com/privkeyio/wisp && cd wisp
zig build -Doptimize=ReleaseFast
# 3. Run (replace with your npub)
./zig-out/bin/wisp --spider-admin npub1yourkey...
That’s it. Wisp will fetch your follow list, sync notes from popular relays, and serve them at ws://localhost:7777. Add this relay URL to your Nostr client.
For more options, see wisp.toml.example.
Features
- NIPs: 1, 2, 9, 11, 13, 16, 33, 40, 42, 45, 50, 65, 70, 77, 86
- LMDB storage (no external database)
- Spider mode for syncing events from external relays
- Import/export to JSONL
- Prometheus metrics at
GET /metrics
Monitoring
Operational metrics are exposed in Prometheus format at GET /metrics on the
relay’s port (connections, events stored/rejected/broadcast, REQ count, rate
limiting). The endpoint honors the relay’s IP allowlist/blocklist, so restrict
it there or at your reverse proxy/firewall if you don’t want it public.
Import/Export
./zig-out/bin/wisp export > backup.jsonl
./zig-out/bin/wisp import < backup.jsonl
Configuration
Copy wisp.toml.example to wisp.toml and customize, or use environment variables with the WISP_ prefix:
WISP_PORT=8080 ./zig-out/bin/wisp
Environment variables override the config file. See the Configuration reference for every setting, its environment variable, default, and meaning.
Deploy (wss://)
To make your relay publicly accessible with TLS, run wisp with Caddy:
# Run wisp
docker run -d --restart always -p 7777:7777 -v wisp-data:/data \
ghcr.io/privkeyio/wisp --spider-admin npub1yourkey...
# Install Caddy for automatic TLS
sudo apt install -y caddy
Create /etc/caddy/Caddyfile:
relay.yourdomain.com {
reverse_proxy localhost:7777
}
sudo systemctl restart caddy
Your relay is now live at wss://relay.yourdomain.com.
Benchmarks
Peak write throughput, all relays at 100% delivery:
| Relay | Events/sec | p99 Latency | Memory (RSS) |
|---|---|---|---|
| Wisp | 25,600 | 0.28 ms | 11 MB |
| nostr-rs-relay | 5,400 | 5.9 ms | 20 MB |
| strfry | 2,800 | 2.9 ms | 3 MB |
nostr-bench, 5,000 events x 4 workers at peak rate (--rate 0), native release builds on a 16-core Linux host, with the event-rate limit raised. RssAnon sampled during the run. These are peak figures with Wisp in sync = none (non-durable); Wisp’s default is sync = meta (durable, never corrupts), which trades raw throughput for crash safety. strfry and nostr-rs-relay write durably by default, so a fair durable comparison runs Wisp in meta/full (see benchmarks). Wisp leads on throughput (~9x strfry, ~5x nostr-rs-relay) and p99 latency; strfry stays smallest in memory.
Contributing
See CONTRIBUTING.md for guidelines on reporting issues and submitting pull requests.
Changelog
See CHANGELOG.md for a history of changes to this project.
License
MIT