The Concept: Digital Dead Drop
During the Cold War, agents and informants used "dead drops" — predetermined physical locations to leave messages without ever meeting. A loose brick in a wall, a hollow tree, a secret compartment under a park bench.
VaporDrop brings this concept into the digital age. It's an anonymous exchange point on the Tor network where two people can deposit and retrieve messages and files without knowing each other, without registering, without leaving traces.
The key difference? You can host it yourself. The server is yours, the data is under your control, and when you shut down the Docker container, everything vanishes.
How Access Works
Forget traditional usernames and passwords. VaporDrop uses a mnemonic system called Brain Key.
Six Words, One Identity
To log in, you need six words of at least four characters each. These words are processed through PBKDF2 with 100,000 iterations to generate a seed, which in turn generates a P-256 cryptographic key pair. The same combination of words always produces the same identity.
There's no "forgot password" because there's no user database. Your six words are your identity.
Choosing Memorable Words
The system doesn't require complicated words. You can use:
- A song chorus: "under this shining sun walking forward"
- A book title: "hundred years solitude gabriel marquez"
- A personal phrase: "grandma maria pasta sunday table"
- Words in logical sequence: "london paris berlin rome madrid tokyo"
The important thing is that they're words you can reconstruct mentally without having to write them down anywhere.
The Numeric ID
Once logged in, the system assigns you a Numeric ID in the format 12345678-90. This is the identifier you share with whoever needs to contact you via message. It's derived from your public key, so the same six words will always produce the same Numeric ID.
Messages and Files: Two Modes
Text Messages
Just the recipient's Numeric ID. The message is AES-256-GCM encrypted in the browser before sending.
File Transfer
Up to 1GB, encrypted chunk by chunk. Requires exchange of complete public keys (130 hex characters).
File Transfer Flow
Key Exchange
The recipient copies their public key and communicates it to the sender
Local Encryption
The sender pastes the key, drags the file — it gets encrypted in the browser
Chunk Upload
Encrypted chunks (1MB each) are uploaded to the server
Download and Decrypt
The recipient downloads, decrypts locally, and the server deletes the chunks
End-to-End Encryption
All cryptographic code runs in the browser. The server never sees cleartext data.
Cryptographic Stack
| Component | Algorithm | Notes |
|---|---|---|
| Key Exchange | ECDH P-256 | 65 bytes = 130 hex |
| Symmetric Encryption | AES-256-GCM | Random 12-byte IV |
| Brain Key Derivation | PBKDF2-SHA256 | 100,000 iterations |
| Onion Key Derivation | Argon2id | 64MB RAM, 3 iter |
| Onion Service Key | Ed25519 | Deterministic |
| RAM Protection | MemGuard | Page locking |
Active Backend Protections
- Anti-replay: each request includes a unique nonce, cached for 24 hours
- Rate limiting: maximum 60 requests per minute per IP
- Timing jitter: random 50-500ms delay to prevent timing attacks
- Padding: messages include random padding to mask actual length
- MemGuard: keys locked in RAM, not swappable to disk
- Constant-time comparison: hash comparisons resistant to timing attacks
The Destroy Button
In the dashboard you'll find a red button: 🔥 Destroy.
It instantly deletes:
- The private key stored in the browser
- All locally saved contacts
- Theme preferences
- Any local data associated with VaporDrop
Note: this does not delete messages already deposited on the server for you. Those remain until automatic expiration (7 days) or until you retrieve them.
Data Lifetime on Server
Messages and files have a maximum lifetime of 7 days.
After one week from deposit, an automatic garbage collector permanently deletes them. This choice balances two needs: giving the recipient enough time to retrieve the data, and not accumulating material indefinitely on the server.
For different requirements, you can modify the constants in the source code and deploy your own customized instance.
Self-Hosting with Docker
VaporDrop is distributed as a Docker container. It works on any system: Linux, Windows, macOS.
Requirements
- Docker and Docker Compose installed
- At least 512MB of available RAM
- Internet connection for the Tor network
- Disk space for temporary files (10GB recommended)
Installation
# Create project directory
mkdir vapordrop && cd vapordrop
# Create structure
mkdir -p static file_storage
# Copy files: main.go, index.html, Dockerfile, docker-compose.yml, go.mod
# Set the secret key (generates the .onion address)
export VAPOR_KEY="your-very-long-secret-phrase"
# Start
docker compose up -d --build
# Find your .onion address in logs
docker compose logs -f
Windows/macOS with Docker Desktop
Install Docker Desktop, launch it, open a terminal and follow the same commands. Docker Desktop automatically manages the underlying Linux VM.
The VAPOR_KEY Variable
VAPOR_KEY is the secret phrase that deterministically generates your service's .onion address.
- Same phrase = same .onion address
- Different phrase = different address
Warning: If you lose the phrase, you lose the address. If someone knows it, they can impersonate your service. Treat it like a master password.
Dockerfile (Multi-Stage Hardened)
# STAGE 1: Build
FROM golang:1.22-alpine AS builder
RUN apk add --no-cache git ca-certificates
WORKDIR /build
COPY go.mod go.sum* ./
RUN go mod download 2>/dev/null || true
COPY main.go .
RUN [ -f go.mod ] || go mod init vapordrop
RUN go mod tidy
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags="-s -w -extldflags '-static'" \
-trimpath -o vapordrop main.go
# STAGE 2: Runtime
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
tor ca-certificates && rm -rf /var/lib/apt/lists/*
RUN groupadd -g 1000 vapor && \
useradd -r -s /bin/false -d /app -u 1000 -g 1000 vapor
WORKDIR /app
COPY --from=builder /build/vapordrop /app/vapordrop
COPY static/ /app/static/
RUN chown -R vapor:vapor /app && chmod 500 /app/vapordrop
USER vapor
ENTRYPOINT ["/app/vapordrop"]
docker-compose.yml (Hardened)
services:
vapordrop:
build: .
container_name: vapordrop
volumes:
- ./static:/app/static:ro
- ./file_storage:/app/file_storage
environment:
- VAPOR_KEY=${VAPOR_KEY:?VAPOR_KEY required}
# Security
cap_add:
- IPC_LOCK # For MemGuard
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
read_only: true
# RAM-only temp dirs
tmpfs:
- /tmp:size=256M,mode=1777,uid=1000,gid=1000
- /run:size=64M,mode=1777
deploy:
resources:
limits:
memory: 512M
restart: unless-stopped
First Boot
In the logs you'll see:
⚙️ Key derivation with Argon2id (~64MB RAM, ~1 sec)...
⚙️ Starting VaporDrop Node...
⚙️ Creating Onion Service v3...
═══════════════════════════════════════════════════════
✅ VAPORDROP ONLINE
🔗 http://abc123xyz456...onion
═══════════════════════════════════════════════════════
Project Structure
vapordrop/
├── main.go # Go backend (~700 lines)
├── go.mod # Dependencies: memguard, bine, crypto
├── go.sum
├── Dockerfile # Multi-stage hardened
├── docker-compose.yml # With security options
├── static/
│ └── index.html # Complete frontend (~500 lines)
└── file_storage/ # Chunk directory (auto-created)
API Endpoints
| Endpoint | Method | Function |
|---|---|---|
/api/register | POST | Register Numeric ID ↔ Public Key |
/api/resolve/{id} | GET | Resolve ID to Public Key(s) |
/api/send | POST | Deposit encrypted message |
/api/fetch | POST | Retrieve messages (and delete) |
/api/file/init | POST | Start file transfer |
/api/file/chunk/{id}/{n} | POST | Upload encrypted chunk |
/api/file/pending/{pk} | GET | List pending files |
/api/file/download/{id}/{n} | GET | Download chunk |
/api/file/complete/{id} | POST | Confirm download (delete) |
/api/stats | GET | Public statistics |
Customization
Modifiable constants in main.go:
const (
MessageTTL = 7 * 24 * time.Hour // Message duration
FileTTL = 7 * 24 * time.Hour // File duration
MaxFileSize = 1 << 30 // 1GB max
FileChunkSize = 1 << 20 // 1MB per chunk
MaxPendingFiles = 1000 // Pending files
MaxIdentities = 100000 // Registered identities
RateLimitWindow = 1 * time.Minute // Rate limit window
MaxRequestsPerIP = 60 // Requests per IP
)
FAQ
Conclusion
VaporDrop isn't for everyone. It doesn't have Telegram's animated emojis, WhatsApp's blue checkmarks, or Signal's groups with hundreds of people.
It's a minimal tool for a specific purpose: allowing two people to exchange information in an ephemeral, anonymous, and verifiable way.
If you need a communication channel that leaves no traces, requires no trust in third parties, and that you can host yourself — VaporDrop is an option.
Six words. No account. No trace.