Skip to main content
Self-Hosting & Privacy

PrivateBin: Self-Hosted, Encrypted Pastebin

PrivateBin encrypts pastes in your browser before they ever reach the server — the decryption key never leaves the URL fragment. A real Docker Compose deployment and why it beats a public pastebin.

milanbuha00August 25, 20266 min read
ShareXin
PrivateBin: Self-Hosted, Encrypted Pastebin

You need to share a config snippet, a stack trace, or a one-off API key with someone right now, so you paste it into whatever pastebin is on top of a search result — and only afterward wonder how long that plaintext sits on someone else's server, readable by anyone with the link, forever. PrivateBin exists specifically to fix that, and the fix is more interesting than "it's encrypted": the server it runs on genuinely cannot read what you paste into it.

TL;DR

  • PrivateBin encrypts your paste with AES-256-GCM inside your browser, before any of it reaches the server — the server only ever stores ciphertext.
  • The decryption key lives in the URL fragment (after the #), a part of the address browsers never send to any server — so not even PrivateBin's own operator can read a paste, even if compelled to.
  • "Burn after reading" pastes delete themselves automatically after the first view, which is exactly the behavior you want for a one-off password or token.
  • PrivateBin requires HTTPS to function at all, which is a real deployment constraint, not an optional hardening step.
  • Self-hosting it removes a third party from ever holding your pasted text, even briefly — the same reasoning behind running your own password vault or DNS resolver.

KEY-STAT: 0 — Bytes of plaintext content a PrivateBin server ever receives — encryption happens entirely client-side before upload

What zero-knowledge actually means here

"Zero-knowledge" gets used loosely in privacy marketing, so it's worth being precise about what it means for PrivateBin specifically. When you type a paste and hit submit, your browser encrypts the text locally using AES-256-GCM before anything is transmitted. The server receives and stores only that ciphertext — it has no way to decrypt it, because it never receives the key.

The key itself is embedded in the shareable URL, but specifically in the fragment identifier — the part after the # character. Browsers treat URL fragments specially: they're used entirely client-side for things like same-page anchors, and are never included in the HTTP request sent to a server. That's the actual mechanism, not a policy promise: the server literally never sees the key, because the browser never sends that part of the URL anywhere.

Note

This also means the key isn't in your browser history the way a typical URL query parameter would be logged server-side, and it isn't visible in server access logs at all — because it never reaches the server.

PrivateBin vs a public pastebin vs disappearing chat messages

Public pastebinDisappearing chat messageSelf-hosted PrivateBin
Who can read the plaintextThe service operator, alwaysThe chat provider, at least brieflyNobody but the link holder — not even you as the server operator
Server stores plaintextYesUsually, brieflyNever
Self-destruct on viewRarely (some paid tiers)Yes, but provider-controlledYes, built-in, your control
Third-party server involvedYesYesNo — you run it
CostFree (ad-supported) or paid tiersFreeYour own hosting (near-$0 on existing homelab hardware)

The gap that matters most is the first row. A public pastebin operator technically can read every paste on the platform, encrypted-in-transit or not, because the plaintext arrives at their server. PrivateBin's architecture removes that capability entirely, regardless of who's running the instance.

Deploying PrivateBin with Docker Compose

I run PrivateBin on my Proxmox homelab behind a reverse proxy that handles Let's Encrypt certificates — this isn't optional: PrivateBin refuses to function without HTTPS, because the whole security model depends on the browser's fragment-handling behavior, which itself depends on a secure context. The actual container setup is small:

services:
  privatebin:
    image: privatebin/nginx-fpm-alpine:latest
    restart: unless-stopped
    volumes:
      - privatebin_data:/srv/data
    expose:
      - "8080"
volumes:
  privatebin_data:

That's the entire application — no database server required, since PrivateBin stores pastes as flat files by default. Point your reverse proxy at port 8080 with a valid TLS certificate, and the instance is live. The lightweight Alpine-based image means it runs comfortably on the same low-power hardware as Vaultwarden — I run both on the same small VM without either one noticing the other exists.

Tip

Set an expiration default (PrivateBin supports 5 minutes up to never) and a paste-size limit in the instance's conf.php before you start using it seriously — the defaults are reasonable, but tightening the maximum expiration is worth doing if every paste you'll ever create is meant to be short-lived.

The one-time-view feature: why it matters for secrets

The feature that makes PrivateBin genuinely useful beyond "encrypted text sharing" is burn-after-reading: a paste can be configured to delete itself from the server automatically the instant it's viewed once. That's the correct behavior for sharing a one-off database password, an API token during a support call, or SSH key material with a colleague — the artifact simply stops existing after it's been read, rather than sitting retrievable indefinitely by anyone who later gets the link.

Warning

Burn-after-reading only protects against the paste being read again later — it does nothing to stop the link from being intercepted or logged the first time it's sent (email, chat history, screen share). Send the link over a channel you already trust, the same caveat that applies to sharing credentials through Signal or any messaging app's underlying encryption.

Is self-hosting it worth it, or is a paste feature in your chat app enough

If you rarely share sensitive text and your chat app already supports disappearing messages, that's a reasonable everyday option — the provider briefly holds the plaintext, but for occasional use the exposure window is small. If you regularly share logs, configs, or credentials — the kind of habit anyone running a homelab or managing infrastructure develops fast — self-hosting PrivateBin removes that third party from the picture entirely, for the cost of about ten minutes of setup on hardware you likely already have running. It's the same calculus that applies across a self-hosted stack: each piece you bring in-house, from the DNS resolver handling your lookups to the pastebin holding your logs, is one less service that ever holds your data, even briefly, even encrypted-in-transit only.

Frequently asked questions

Is PrivateBin actually secure?

Yes, by design rather than by policy — pastes are encrypted with AES-256-GCM in your browser before upload, and the decryption key lives only in the URL fragment, which is never transmitted to any server. The server stores ciphertext it cannot decrypt.

Can the server operator read a PrivateBin paste?

No, structurally not — even the person running the PrivateBin instance only has access to encrypted data. Without the key from the URL fragment, which never reaches the server in the first place, the stored content is unreadable.

How do I self-host PrivateBin?

The official privatebin/nginx-fpm-alpine Docker image runs the entire application in one lightweight container with no separate database required (pastes are stored as flat files by default). Point a reverse proxy with a valid TLS certificate at its exposed port, since PrivateBin will not run without HTTPS.

Does PrivateBin require HTTPS?

Yes, and it's enforced rather than recommended — the security model relies on browser behavior around secure contexts and URL fragments, so the application will not function correctly served over plain HTTP.

What happens to a PrivateBin paste after it's viewed?

It depends on the expiration setting chosen at creation. A "burn after reading" paste deletes itself from the server automatically after the first view. Otherwise, it persists until its configured expiration time (from 5 minutes up to never, depending on instance settings).

Related stories

More from Self-Hosting & Privacy

Stay in the loop

Get the latest articles delivered to your inbox. No spam, unsubscribe anytime.

Read next

What Encrypted DNS Actually Hides

Encrypted DNS hides your queries from your ISP, but not your destination IP or (usually) the domain in the TLS handshake. What it actually protects, and a first-hand Pi-hole + Unbound setup.

Continue Reading