Self-hosting¶
Docker images¶
| Registry | Image |
|---|---|
| Docker Hub | stackopshq/ghostbit |
| GHCR | ghcr.io/stackopshq/ghostbit |
Available tags: latest, edge, semver (1.0.0, 1.0, 1).
Docker Compose (recommended)¶
SQLite¶
Redis¶
With a password:
The REDIS_PASSWORD variable is forwarded to both the Redis container (--requirepass) and the app (injected into the connection URL). If you connect to an external Redis that already has credentials in REDIS_URL, leave REDIS_PASSWORD unset.
Redis data is persisted via AOF + RDB snapshots on a named Docker volume.
HTTPS and Web Crypto¶
Ghostbit uses the Web Crypto API for all client-side encryption. Browsers only expose this API in a Secure Context, which means:
https://— always secure ✓http://localhostorhttp://127.0.0.1— granted by the browser for local development ✓http://on any other host — not a Secure Context, encryption is blocked ✗
Reverse proxy with HTTPS termination¶
The most common production setup — HTTPS on the proxy, plain HTTP internally — works perfectly:
The browser sees https://paste.example.com → Secure Context → Web Crypto works.
The internal HTTP leg between proxy and app is invisible to the browser.
Never expose the app directly over HTTP in production
If users can reach Ghostbit via http:// (bypassing the proxy), the browser will
refuse to encrypt and the app will show an error. Always ensure HTTPS is enforced
at the proxy level.
Nginx reverse proxy¶
HTTPS is required in production
crypto.subtle (Web Crypto API) requires a Secure Context.
Without HTTPS, the browser will refuse to encrypt pastes.
Caddy reverse proxy¶
Caddy handles HTTPS automatically via Let's Encrypt.
Data persistence¶
| Backend | Persistence |
|---|---|
| SQLite | Named Docker volume ghostbit_data mounted at /data |
| Redis | Named Docker volume redis_data, AOF + RDB snapshots |
Backup SQLite¶
Backup Redis¶
Updating¶
Privacy¶
- No IP addresses or User-Agent strings are ever logged
- Paste IDs are
secrets.token_urlsafe(6)— random, non-sequential - Burn-after-read fires only on API reads, not on HTML page loads
- The server never sees plaintext or passwords