Zero-knowledge secret sharing: hand someone a password, a key or a file with a link that opens once, or expires, and then is gone. Everything is encrypted in the browser before it is uploaded; the server stores an opaque, padded blob and the hash of its identifier. It cannot read a secret, tell a file from a note, or say who created or opened what, and it keeps no logs that could.
- Text and files, single-view or time-limited (up to 14 days), optional passphrase
- No accounts, no cookies for visitors (the admin panel uses one session cookie), no third-party requests; the share link carries the key in its fragment, which never reaches the server
- Padded blobs (Padmé) so sizes reveal nothing; uniform "not found" answers so probing reveals nothing
- Reports remove a secret without anyone seeing it; aggregate daily counters are the only statistics
- Admin panel and JSON admin API, rate limiting without storing addresses, multi-language UI
- A minimal built-in website, or your own frontend against the API (
SHH_WEB=api) built on the@shhnote/clientpackage - One static binary; SQLite or PostgreSQL; blobs inline, on disk or on S3
- AGPL-3.0; the protocol is specified in
SPEC.mdand pinned by test vectors
You need a host with Docker, and a domain name pointing at it.
mkdir shhnote && cd shhnote
curl -fsSLO https://raw.githubusercontent.com/shhnote/shhnote/main/deploy/docker/docker-compose.yml
curl -fsSLO https://raw.githubusercontent.com/shhnote/shhnote/main/deploy/docker/Caddyfile
curl -fsSL https://raw.githubusercontent.com/shhnote/shhnote/main/deploy/docker/.env.example -o .env
docker run --rm ghcr.io/shhnote/shhnote init >> .env # appends the two secrets
chmod 600 .env # it holds credentials now
# edit .env: DOMAIN, SHH_URL
docker compose up -dCaddy fetches the TLS certificate; the admin panel is at /en/admin. Sign in with the bootstrap token, create an admin key, set the site name and a contact address, remove the token — until then every public page and API call answers 503, and only the admin panel, the admin API, /static/* and /health work. Details and the other ways to run it:
- Docker: compose with Caddy, with your own proxy, with Postgres
- Bare metal: release binary, systemd, an existing proxy and database
- Fly.io: one app per region
- Reverse proxies and operations: configuration reference, backups, upgrades, storage tiers
- Your own frontend with
SHH_WEB=api, and the frontend conformance checklist
Rust (stable, with the wasm32-unknown-unknown target) and Node 24.
(umask 077; cp .env.example .env) # SQLite and local addresses; owner-readable, it will hold credentials
scripts/build-client.sh # Argon2 WASM module and the JavaScript bundles; the server build needs them
cargo run -p shhnote-server -- init --env .env # fills in SHH_SECRET_KEY and SHH_ADMIN_TOKEN
cargo run -p shhnote-server # http://localhost:3000
cargo test --workspace # add SHH_TEST_PG_URL=postgres://… to cover Postgres too
git config core.hooksPath .githooks # once per clone: keeps scripts executable in the indexThe layout: crates/shhnote-core (protocol), crates/shhnote-store (database), crates/shhnote-server (API and website), crates/shhnote-argon2-wasm (Argon2id for browsers), client/ (TypeScript: the @shhnote/client package in three layers, crypto/, lib/, ui/, and the built-in page bundle). vectors/v1.json holds the conformance vectors both implementations must pass.
Everything the website does goes through the JSON API, documented on every instance at /en/docs. The shh.js module served at /static/shh.js implements the protocol for scripts and other clients; it runs in browsers and in Node.
The browser side is published as @shhnote/client, with three entry points: @shhnote/client/crypto (the protocol, no network, no DOM), @shhnote/client (adds the API client, createSecret/revealSecret/burnSecret and the frontend-safety helpers, still no DOM) and @shhnote/client/ui (the reference page controllers, which bind to data-shh-* attributes and take their strings from you). @shhnote/client/argon2.wasm is the Argon2id module to serve from your own origin. Every instance also serves the root and /ui entries as /static/shh.js and /static/shh-ui.js for frontends without a build step. scripts/pack-client.sh builds the package; releases publish it. A frontend built on it should meet docs/frontend-conformance.md.
AGPL-3.0-only. See LICENSE.