Deploy Wastebin

Tiny Rust pastebin — encrypted, burn-after-reading, expirations, QR

Deploy Wastebin

Just deployed

/data

Wastebin Lite

A 20 MB single-binary pastebin. Fast, small, self-hostable on one container. Encrypted pastes, burn-after-reading, expirations, markdown rendering, QR codes, 9 themes, 170+ syntax-highlighted languages — built in Rust/Axum with no Node runtime.

Deploy on Railway

Deploy and Host

One click. Railway provisions a single service with the /data volume, sets the two per-install secrets, and wires the public URL. Nothing to configure unless you want to change the theme or paste size limit.

  • Runtime — Rust (statically linked, scratch base). No Node.js, no Python, no JVM.
  • Memory — ~20 MB at rest. Fits on Railway Hobby.
  • Port — 8088 (baked into the Docker wrapper).
  • Persistence — SQLite on the /data volume. Pastes survive redeploys and restarts.
  • Public URL — WASTEBIN_BASE_URL is auto-filled from RAILWAY_PUBLIC_DOMAIN on every new deploy.

Why Deploy

  • Sticky by design. Once you start keeping logs, API responses, snippets, and secrets in one place, a second pastebin never gets installed.
  • Encrypted by choice. Password-protected pastes use ChaCha20-Poly1305 + argon2 — for keys, credentials, incident notes.
  • Burn-after-reading built in. A paste can self-destruct after a one-time confirmation reveal, so you can pass a secret URL to someone without leaving a trail.
  • Tiny binary. One ~20 MB static ELF. Deploys in seconds; restarts are instant.
  • Keyboard-first UI. r raw, n index, y copy URL, c copy content, q QR, w wrap, m markdown toggle, ? all keybindings.
  • API-first. Every paste feature is reachable with pure curl — no browser required. Scripts and CI can share long outputs without a UI.

Common Use Cases

  • Log capture & share — pipe journalctl, kubectl logs, tail -f, or CI output into a paste and paste the URL next to the incident.
  • Encrypted secret handoff — paste a password or API key, share the URL privately, let the recipient use their own password header to unlock.
  • Burn-after-reading — share a token to a single person who must click through a confirm page exactly once; the paste is gone afterwards.
  • Code / config snippet sharing — syntax-highlighted paste, rendered markdown view, raw endpoint for pipelines.
  • QR for mobile — /qr/{id} prints a phone-scannable QR of the paste URL (convenient for logs you want to read on a phone).
  • Expiring pastes — 10 min, 1 h, 1 d, 1 M, 1 y options out of the box.
  • Agent & bot log drop — paste long tracebacks and logs for another service (or a human) to fetch.

Deployment Dependencies

No external database, cache, or queue:

  • Railway Hobby or above — 1 GB RAM is plenty; the binary uses ~20 MB at rest.
  • /data volume — SQLite state.db lives here; the template attaches it automatically. Without it, pastes vanish on redeploy.
  • No Postgres, no Redis, no external auth — everything is embedded.

Architecture

One service, one container, one volume:

PieceValue
Containerquxfoo/wastebin:3.7.1 (scratch base) + root wrapper in this repo
Port8088 (baked into the Dockerfile; Railway reverse-proxy + external healthcheck target /)
Volume/data — mounted by Railway; SQLite state.db persists here
Secretsper-install WASTEBIN_SIGNING_KEY (>= 64 bytes) + WASTEBIN_PASSWORD_SALT (16 bytes)
Domainauto-generated by Railway; exposed at 8088

The wrapper runs as root because Railway mounts persistent volumes as root-owned; quxfoo/wastebin ships as a non-root user and would EACCES-crash-loop writing the database. The scratch base has no shell, so the healthcheck is Railway's external probe of / (there is no in-container HEALTHCHECK to write). The Dockerfile pins WASTEBIN_DATABASE_PATH=/data/state.db; without it, Wastebin writes the DB to the container's writable layer and every redeploy silently wipes all pastes.

Features

  • Encrypted pastes — ChaCha20-Poly1305 + argon2 password protection.
  • Burn-after-reading — confirm once, reveal once, then 404.
  • Expirations — 0,10m,1h,1d,1M,1y (configurable per deploy).
  • 1 MiB max body — raise WASTEBIN_MAX_BODY_SIZE for long logs; 170+ languages highlighted.
  • Markdown render — /md/{id} with GitHub tables, task lists, admonitions.
  • Raw view — /raw/{id} for pipes, curl, CI scripts.
  • QR code — /qr/{id} for phone sharing.
  • Theme picker — 9 themes: ayu, base16ocean, catppuccin, coldark, gruvbox, monokai, onehalf, rosepine, solarized.
  • Owner tokens — every paste URL carries a signed delete token so the author can revoke it.
  • Keyboard-first UI — full keybinding layer in the browser.

Dependencies for Wastebin Lite

  • Railway Hobby or above — 1 GB RAM is plenty; the binary uses ~20 MB at rest.
  • /data volume — required for persistence. The template attaches it automatically.
  • No external database, cache, or queue — SQLite is embedded in the container.

About Hosting

Wastebin Lite is a single container. Railway's reverse proxy terminates TLS at the edge and forwards plain HTTP to the container on port 8088; the external healthcheck targets /. The root wrapper exists solely to make the Railway volume mount writable by the Wastebin process — the binary itself is unchanged from the upstream quxfoo/wastebin:3.7.1 image.

Configuration

VariableDefaultDescription
WASTEBIN_BASE_URL${{RAILWAY_PUBLIC_DOMAIN}}Public URL for the paste links in the UI and the API response.
WASTEBIN_TITLEWastebin LiteSite title in the browser tab.
WASTEBIN_THEMEcatppuccinDefault theme (see Features).
WASTEBIN_MAX_BODY_SIZE1048576Max paste size in bytes (1 MiB). Raise for long logs.
WASTEBIN_PASTE_EXPIRATIONS0,10m,1h,1d,1M,1yUI expiry options (0 = no expiry).
WASTEBIN_SIGNING_KEY${{secret(64)}}Required, >= 64 bytes — the server refuses to start on a shorter key. Signs owner/delete tokens. Auto-generated per install.
WASTEBIN_PASSWORD_SALT${{secret(16)}}Argon2 salt used to derive the encryption password key. Auto-generated per install.

How to Use

1. Deploy

Deploy on Railway

The template creates one service with the /data volume. On first deploy it sets the two per-install secrets and wires WASTEBIN_BASE_URL to your public domain — no manual configuration needed.

2. Paste in the browser

Open YOUR-DOMAIN, type or paste content, choose an expiry and (optionally) an extension and password, press Enter. Keyboard: r raw, n index, y copy URL, c copy content, q QR, w wrap, m markdown toggle, ? all keybindings.

3. Paste with the API

# Plain paste (1 MiB default, .log extension, 1-day expiry)
curl -s -X POST -H "Content-Type: application/json" \
  -d '{"text":"CPU 90% I/O 3% Uptime 42d","extension":"log","expires":86400,"burn_after_reading":false}' \
  https://YOUR-DOMAIN/
# -> {"path":"/abcd-ef.log","owner":"SIGNED-OWNER-TOKEN"}

# Raw content
curl https://YOUR-DOMAIN/raw/abcd-ef.log

# Encrypted paste
curl -s -X POST -H "Content-Type: application/json" \
  -d '{"text":"secret-key-material","password":"mypass"}' \
  https://YOUR-DOMAIN/
# Read back with the password header:
curl -H "wastebin-password: mypass" https://YOUR-DOMAIN/raw/abcd-ef.log

# Burn after reading
curl -s -X POST -H "Content-Type: application/json" \
  -d '{"text":"self-destructing","burn_after_reading":true}' \
  https://YOUR-DOMAIN/
# The normal URL redirects to /burn/abcd-ef — confirm once, then the paste 404s.

Pipe anything in:

journalctl -u systemd --since "1 hour ago" | curl -s --data-binary @- \
  -H "Content-Type: text/plain" https://YOUR-DOMAIN/

4. Endpoints

MethodPathDescription
POST/Create a paste. JSON or raw body. Returns {path, owner}.
GET/{id}HTML view. Burn-protected pastes redirect to /burn/{id}.
GET/raw/{id}Unprocessed paste body.
GET/md/{id}Rendered markdown view.
GET/qr/{id}QR code of the paste URL.
GET/burn/{id}One-time confirm interstitial for burn pastes. POST confirm_burn=1 reveals and burns.
GET/{id}?owner=SIGNED-OWNER-TOKENOwner handshake — signs the uid session cookie authorizing delete.
DELETE/{id}Delete the paste (requires the uid cookie from the handshake).
POST/delete/{id}Browser-form delete (same uid cookie requirement).
GET/themeSwitch theme (query `pref=DARK

Troubleshooting

  • Container crash-loops on a fresh install — confirm WASTEBIN_SIGNING_KEY is >= 64 bytes (the server refuses to start on a shorter key). The ${{secret(64)}} value satisfies this.
  • Pastes vanish after a redeploy — WASTEBIN_DATABASE_PATH must point at the volume (/data/state.db, baked into the Dockerfile) and the /data volume must be attached to the service.
  • Encrypted pastes unreadable after a redeploy — WASTEBIN_PASSWORD_SALT changed between deploys; regenerate the paste or pin a stable salt value.
  • Owner token 403 / paste not deleted — the token contains base64 + and /; when passing it as a query parameter, URL-encode it, and always perform the GET /{id}?owner=SIGNED-OWNER-TOKEN handshake before the DELETE or POST /delete/{id}.
  • Paste too large — bump WASTEBIN_MAX_BODY_SIZE (bytes) and redeploy.
  • Port / health — the container listens on 0.0.0.0:8088 (baked into the Dockerfile); the external healthcheck targets /.

License

Upstream Wastebin is MIT-licensed. This template's wrapper Dockerfile and config are provided as-is.


Template Content

More templates in this category

View Template
Garage S3 Storage
Ultra-light S3 server: fast, open-source, plug-and-play.

PROJETOS
8
View Template
Redis
Self Host Latest Redis with Railway

9
View Template
EasyImg
Simple self-hostable Nuxt.js personal image hosting system.

Muhammad Bilal
0