Practical recipes for day-to-day use. Assumes Linux (amd64); macOS differences are called out where they matter.
For protocol design, see SPEC.md and PROTOCOL.md.
# build from source (requires Go 1.22+)
git clone https://github.com/<you>/deaddrop.git
cd deaddrop
go build -trimpath -o deaddrop ./cmd/deaddrop
# optional: install to PATH
sudo install -m 755 deaddrop /usr/local/bin/No runtime dependencies.
The Linux binary is statically linked (CGO_ENABLED=0). The repo
Makefile exports CGO_ENABLED=0 for make build, which is the
right default on Linux: identity and passcache backends use the
kernel keyring via direct syscalls, no cgo needed.
macOS builds require CGO_ENABLED=1. The identity and passcache
backends call Security.framework / CoreFoundation.framework via
cgo, so a CGO_ENABLED=0 build fails with undefined: identitystore.New / undefined: passcache.New.
# prerequisite: Xcode Command Line Tools (provides system headers + ld64)
xcode-select --install
# build (override the Makefile default)
CGO_ENABLED=1 go build -trimpath -o deaddrop ./cmd/deaddrop
# Apple Silicon (default on M1/M2/M3/M4):
GOARCH=arm64 CGO_ENABLED=1 go build -trimpath -o deaddrop ./cmd/deaddrop
# Intel Mac:
GOARCH=amd64 CGO_ENABLED=1 go build -trimpath -o deaddrop ./cmd/deaddropBuilding from source is the recommended path. If you instead receive
a deaddrop binary downloaded from the internet (Safari, curl, etc.),
macOS will quarantine it on first run with a Gatekeeper warning. To
clear the quarantine attribute on a binary you trust:
xattr -d com.apple.quarantine ./deaddropmake build from the repo Makefile will fail on macOS unless you
override CGO_ENABLED. Either run go build directly with cgo on, or
invoke make build CGO_ENABLED=1.
Every command needs the relay URL and deploy secret.
Set them once in your shell profile or .env:
export DEADDROP_RELAY="https://relay.example.com/<prefix>"
export DEADDROP_DEPLOY_SECRET="hex:<64-char-hex>"
export DEADDROP_WRITE_TOKEN="hex:<64-char-hex>" # needed for send/bootstrap onlyDEADDROP_DEPLOY_SECRET requires a hex: or b64: prefix.
DEADDROP_WRITE_TOKEN is optional — only needed if the relay enforces write auth.
deaddrop keygen ~/.deaddrop/capsule
# prompts for passphrase twice (enter + confirm)
# prints capsule fingerprint — compare OOB with your peerCopy the capsule file to the other laptop (USB, Signal, SCP). Both sides share the same 109-byte file and the same passphrase.
Keygen capsules have no E2E identity. A
keygencapsule is a shared symmetric secret with no per-pair X25519 identity entry, so the default-on E2E check (--require-e2e, see §15) has nothing to bind to. Everysend/recvagainst a keygen capsule must pass--no-require-e2e, otherwise it exits 22 (IdentityMiss):deaddrop send --no-require-e2e ~/file.txt deaddrop recv --no-require-e2e ~/out.txtFor automatic content-layer E2E (no flag needed), use Option B instead — bootstrap provisions the identity entry the check requires.
Both laptops need the same DEADDROP_RELAY and DEADDROP_DEPLOY_SECRET.
Laptop A (initiator):
deaddrop bootstrap --role=initiator
# generates a 6-word Diceware passphrase (~77 bits)
# read it aloud to your peer (voice, Signal, etc.)Laptop B (responder) — start within 60 seconds:
deaddrop bootstrap --role=responder
# type the 6 words when promptedBoth sides:
- Show a pairing fingerprint — compare OOB, press Enter to confirm
- Prompt for a local capsule passphrase (can differ per side)
- Write
~/.deaddrop/capsuleand store X25519 identity in OS keyring
After bootstrap, E2E is automatic — send/recv wrap payloads
with a content-layer AEAD the relay cannot read.
deaddrop send ~/documents/report.pdf
# prompts for capsule passphrase (cached after first use)The file is encrypted and uploaded. Maximum 10 MiB. Exit code 0 means the relay accepted it.
The bare commands in §4–§6 assume a bootstrap capsule (Option B),
where E2E is automatic. With a keygen capsule (Option A), add
--no-require-e2e to every send/recv — see the callout in §3.
printf 'my-passphrase' | deaddrop send \
--passphrase-fd 0 ~/documents/report.pdfOr via env var (emits a warning — acceptable for automation):
deaddrop send --passphrase-env MY_PASS ~/documents/report.pdfdeaddrop recv ~/downloads/report.pdfOr to stdout:
deaddrop recv | tar xzExit code 1 means no message found. The 3-minute window comes from the blind-probe design — receiver checks the last 3 minute-buckets.
For "send now, recv whenever":
# poll for up to 1 hour (default), check every 60 seconds
deaddrop recv --watch ~/downloads/report.pdf
# poll for 30 minutes, check every 45 seconds
deaddrop recv --watch --duration 30m --watch-interval 45s ~/downloads/report.pdf
# poll indefinitely until message arrives or Ctrl-C
deaddrop recv --watch --duration 0 ~/downloads/report.pdf- First probe runs immediately (no initial sleep)
--watch-intervalminimum is 30 seconds--durationmaximum is 24 hours;0= unbounded- Ctrl-C exits cleanly with code 130
- Auth/crypto errors are terminal (not retried)
Every message is consumed on first recv — the relay deletes it atomically.
A second recv returns exit code 1:
echo "secret" | deaddrop send --passphrase-fd 3 /dev/stdin 3<<<'pass'
deaddrop recv --passphrase-fd 3 /tmp/first.txt 3<<<'pass' # succeeds
deaddrop recv --passphrase-fd 3 /tmp/second.txt 3<<<'pass' # exit 1# capsule fingerprint (both sides should match)
deaddrop fingerprint
# pairing fingerprint (after bootstrap, includes identity keys)
deaddrop fingerprint --identity
# output: 6chars 6chars 6chars 6chars 8charsAfter the first passphrase prompt, deaddrop caches it in the OS keyring. Subsequent commands skip the prompt until the TTL expires.
deaddrop send ~/file1.txt # prompts
deaddrop send ~/file2.txt # uses cache — no prompt
# change TTL (default: 1 hour / 3600 seconds)
deaddrop send --passcache-ttl 7200 ~/file.txt # 2 hours
# disable caching for one command
deaddrop send --passcache=none ~/file.txt
# forget cached passphrase and re-prompt
deaddrop send --forget-passcache ~/file.txtCache lives in the kernel session keyring. Survives tmux/screen detach but is lost on logout.
# list cached entries
keyctl list @s | grep 'deaddrop:'
# manually clear all deaddrop cache entries
keyctl list @s | awk '/deaddrop:/ {print $1}' | while read id; do
keyctl unlink "$id" @s
doneCache lives in the login keychain. No per-item TTL — entries persist
until the login keychain locks (which rarely happens in practice;
the login keychain auto-unlocks at login and stays unlocked across
sleep, screen-lock, and reboot). --passcache-ttl is silently
ignored (note printed to stderr).
# list entries
security find-generic-password -s deaddrop
# delete one
security delete-generic-password -s deaddrop -a 'deaddrop:<hex>'For full Keychain semantics — ACL prompts, persistence vs Linux, locked-keychain handling, identity vs passcache services — see section 9b below.
deaddrop uses the Linux kernel keyring for two things:
- Passphrase cache — session keyring, short-lived, auto-expires
- E2E identity keys — UID-scoped persistent keyring, long-lived
After deaddrop bootstrap, X25519 identity keys are stored in the
UID-scoped persistent keyring via KEYCTL_GET_PERSISTENT. This keyring:
- Survives logout (unlike the session keyring)
- Lives in kernel RAM — lost on reboot
- Has a 3-day idle expiry (default), reset on every access
- Configurable via
/proc/sys/kernel/keys/persistent_keyring_expiry - Requires
CONFIG_PERSISTENT_KEYRINGS=yin the kernel
# check if your kernel supports persistent keyrings
grep PERSISTENT_KEYRINGS /boot/config-$(uname -r)
# → CONFIG_PERSISTENT_KEYRINGS=y
# after bootstrap, show the session keyring tree
# (persistent keyring appears as a linked sub-keyring)
keyctl show @s
# list identity entries
keyctl list @s | grep 'deaddrop-id-'
# check persistent keyring expiry (seconds)
cat /proc/sys/kernel/keys/persistent_keyring_expiry
# → 259200 (3 days)On kernels without CONFIG_PERSISTENT_KEYRINGS, or in restricted
namespaces (EPERM), deaddrop falls back to the session keyring
and prints a warning:
WARN: persistent keyring unavailable, using session keyring (identity lost on logout)
If you see this, identity keys won't survive logout — you'll need
to re-run deaddrop bootstrap after logging back in. The capsule
file is unaffected.
# list all keys in session keyring
keyctl list @s
# read a specific key (raw bytes)
keyctl pipe <key-id> | xxd
# show key metadata (permissions, expiry)
keyctl describe <key-id>
# check remaining TTL on a cached passphrase
keyctl timeout <key-id> # prints remaining seconds
# show full keyring hierarchy
keyctl show @s# "key was rejected by service" — wrong passphrase cached
deaddrop send --forget-passcache ~/file.txt
# "disk quota exceeded" — too many keys
cat /proc/sys/kernel/keys/maxkeys # per-user limit
cat /proc/sys/kernel/keys/maxbytes # per-user byte limit
# increase if needed (as root)
echo 5000 > /proc/sys/kernel/keys/maxkeys
# "operation not permitted" inside container/namespace
# → use --passcache=none or ensure keyring syscalls are allowedCounterpart to section 9 for macOS users. deaddrop uses the user's
login keychain (the default for security CLI) — never the
System keychain, never iCloud Keychain.
| Service name | Purpose | Account format |
|---|---|---|
deaddrop |
Passphrase cache (short-lived) | deaddrop:<8-byte-hex> |
deaddrop-identity |
Per-pair X25519 identity (long-lived) | deaddrop:pair:<16-byte-hex> |
The two services are intentionally distinct so an operator running
security delete-generic-password -s deaddrop to clear the passcache
does NOT also wipe identity entries (would silently break the pair).
- Survives logout: yes (login keychain re-unlocks on next login).
- Survives reboot: yes (login keychain is on disk, encrypted at rest).
- Migrated to a new Mac via Migration Assistant or restore: no.
Both services use
kSecAttrAccessibleWhenUnlockedThisDeviceOnly, which excludes the entry from device-to-device migration and from iCloud Keychain sync. - Available while screen is locked: depends on whether keychain
is locked. Default macOS behavior: lock screen alone does NOT lock
the login keychain. The keychain only locks if you explicitly lock
it via Keychain Access or via
security lock-keychain, or if you set "Lock keychain when sleeping" in Keychain Access preferences.
This is a meaningful behavioral difference from Linux: on Linux the persistent keyring is RAM-only and reboot wipes it (rebootstrap needed). On macOS, identity entries survive reboot.
The first time deaddrop reads or writes a Keychain item, macOS
shows an authorization dialog:
"deaddrop wants to access your confidential information stored in [item-name] in your keychain. To allow this, enter the [keychain] password."
You will see this dialog once per Keychain item (so once after
first passcache write, plus once per pair after deaddrop bootstrap).
The dialog has three buttons:
- Always Allow — adds
deaddropto that item's ACL. Future reads/writes from the same binary path are silent. This is what you want. - Allow — one-time grant. The dialog will appear again on the next access. Annoying for an interactive workflow, fatal for cron.
- Deny —
deaddropgetserrSecAuth/errSecItemNotFound, which surfaces asIdentityMiss(exit 22) or a wrong-passphrase error.
Touch ID may replace the password prompt on Macs with a Secure Enclave; the ACL semantics are identical.
If you change the binary path (e.g., move from /usr/local/bin/
to ~/bin/) or rebuild with a different team-id signature, macOS
treats it as a new binary and re-prompts. Pick "Always Allow" again.
# list every passcache entry (returns the first match by default;
# use -g to print attributes, repeat queries to enumerate)
security find-generic-password -s deaddrop -g
# list identity entries for a specific pair
security find-generic-password -s deaddrop-identity \
-a 'deaddrop:pair:<16-hex>'
# dump every deaddrop-related entry (pipe through grep)
security dump-keychain | grep -E 'deaddrop|deaddrop-identity'
# delete one passcache entry
security delete-generic-password -s deaddrop -a 'deaddrop:<hex>'
# delete one identity entry (forces rebootstrap for that pair)
security delete-generic-password -s deaddrop-identity \
-a 'deaddrop:pair:<hex16>'
# nuke ALL passcache entries (one per call — repeat until ENOENT)
while security delete-generic-password -s deaddrop 2>/dev/null; do :; donesecurity find-generic-password returns only the first match per
invocation. To enumerate, narrow with -a <account> or use
security dump-keychain and filter.
If the login keychain is locked when deaddrop send/recv runs,
the identity store returns ErrMiss (D-62 graceful degradation):
the user-facing error is IdentityMiss (exit 22), not a cryptic
OSStatus number. The fix path is one of:
# unlock the login keychain (prompts for password)
security unlock-keychain ~/Library/Keychains/login.keychain-db
# or rebootstrap the pair (last resort)
deaddrop bootstrap --role=...Same behavior applies if the keychain item exists but ACL denies deaddrop's process. Re-run interactively, click "Always Allow."
# every send/recv re-prompts for keychain password
# → first prompt got "Allow" instead of "Always Allow"; delete the
# item and re-run, choosing "Always Allow" this time.
# "wrong passphrase" but you typed the right one
# → stale passcache entry; force-forget and retype:
deaddrop send --forget-passcache ~/file.txt
# bootstrap succeeded but next send shows IdentityMiss (exit 22)
# → keychain was locked between bootstrap and send; unlock and retry:
security unlock-keychain ~/Library/Keychains/login.keychain-db
# "deaddrop" is not in the ACL of an existing item (binary moved)
# → easiest fix is to delete and recreate:
security delete-generic-password -s deaddrop-identity \
-a 'deaddrop:pair:<hex16>'
deaddrop bootstrap --role=...- iCloud Keychain — deaddrop entries do not sync. The
ThisDeviceOnlyaccessibility class blocks iCloud upload. - System keychain — never written to. No sudo-elevated keychain prompts.
- Time Machine — login keychain is included in default Time
Machine backups, but the backup is encrypted with the user's login
password. Restoring to a new Mac does not migrate
ThisDeviceOnlyitems, so the practical effect is zero. If you want explicit exclusion, add~/Library/Keychains/to Time Machine exclusions in System Settings.
deaddrop respects standard HTTP proxy environment variables.
Go's net/http handles this automatically — no flags needed.
# HTTPS traffic through a forward proxy
export HTTPS_PROXY=http://proxy.example.com:8080
deaddrop send ~/file.txt
deaddrop recv ~/received.txt
# lowercase also works
export http_proxy=http://proxy.example.com:8080
# bypass proxy for specific hosts
export NO_PROXY=relay.internal.example.com
deaddrop send ~/file.txt # goes direct, not through proxyAll relay communication uses HTTPS. The proxy sees a CONNECT
request to the relay hostname:443 — it cannot see the request
path, headers, or body (TLS tunnel).
# on your workstation: tunnel local port to a remote proxy
ssh -L 8080:proxy.internal:3128 jumpbox
# then
HTTPS_PROXY=http://127.0.0.1:8080 deaddrop send ~/file.txtIf the proxy terminates TLS with its own CA:
export SSL_CERT_FILE=/path/to/corporate-ca.pem
deaddrop send ~/file.txtCheck your proxy logs for CONNECT <relay-host>:443 entries.
With Squid:
TCP_TUNNEL/200 ... CONNECT deaddrop.example.com:443
Go's net/http reads HTTPS_PROXY / HTTP_PROXY / NO_PROXY
environment variables on every platform — but it does not read
the macOS system proxy from System Settings → Network → Proxies.
If your Mac is configured to use a corporate proxy via System
Settings or a PAC file, deaddrop will bypass it and try to connect
direct (which will likely fail).
# inspect the macOS system proxy (informational; deaddrop won't read this)
scutil --proxy
# if you see HTTPS proxy / PAC, set the env var to match before running:
export HTTPS_PROXY=http://proxy.corp.example.com:8080
deaddrop send ~/file.txtPAC (Proxy Auto-Config) files are not supported. Resolve the PAC to a concrete proxy URL once and export it.
For relays with self-signed certificates (e.g., tls internal in Caddy):
# extract Caddy's self-signed root CA (run on the relay host)
docker exec deaddrop-caddy cat /data/caddy/pki/authorities/local/root.crt > /tmp/caddy-root.crt
# scp it to your client machine (Linux or macOS), then:
export SSL_CERT_FILE=/tmp/caddy-root.crt
deaddrop send ~/file.txtThis also works for --watch mode and bootstrap.
SSL_CERT_FILE is the recommended path on macOS too — Go's
crypto/tls honors it on every platform, no rebuild needed.
You can alternatively add the Caddy root to the macOS System keychain trust roots, but the env-var approach is cleaner because it scopes the trust to deaddrop only:
# only if you need the cert trusted system-wide (other tools, browsers)
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain /tmp/caddy-root.crt
# remove later:
sudo security delete-certificate -c "Caddy Local Authority" \
/Library/Keychains/System.keychain- A Linux server with SSH access and Docker installed
- A domain pointing to the server (for Let's Encrypt), or IP-only (self-signed)
- Create
deployment.yamlfrom the example:
cp deployment.yaml.example deployment.yaml
# edit: fill in host, domain, user, tls mode# production VPS with Let's Encrypt
./scripts/deploy.sh vps
# internal VM with self-signed TLS
./scripts/deploy.sh vm
# clean deploy (wipe containers first)
./scripts/deploy.sh vps --clean
# deploy + smoke test
./scripts/deploy.sh vps --testThe script:
- Syncs code via
git archive | ssh tar xf - Generates secrets on first deploy (or reuses existing
.env) - Builds and starts Docker containers (relay + Caddy)
- Waits for TLS health
- Prints relay URL and env export commands
vps:
host: 203.0.113.10
user: root
domain: deaddrop.example.com
tls: acme # Let's Encrypt
env_path: /etc/deaddrop/relay.env
deploy_dir: /root/deaddrop
vm:
host: 192.168.122.254
user: root
tls: internal # self-signed
deploy_dir: /root/deaddropCaddy handles Let's Encrypt certificate renewal automatically — no cron job needed. Certificates are renewed ~30 days before expiry via a background goroutine. Check status:
ssh root@relay docker logs deaddrop-caddy 2>&1 | grep -i certgo test ./...sh test/smoke/qa-roundtrip.sheval "$(./scripts/deploy.sh vps 2>/dev/null | grep export)"
./test/perf/perf-roundtrip.sh
./test/perf/perf-roundtrip.sh --parallel 4 --cycles 10
./test/perf/perf-roundtrip.sh --sizes "1024 102400" --report /tmp/perfeval "$(./scripts/deploy.sh vps 2>/dev/null | grep export)"
./test/proxy/proxy-e2e.sh
./test/proxy/proxy-e2e.sh --proxy http://127.0.0.1:8080
./test/proxy/proxy-e2e.sh --skip-largeTests: HTTPS_PROXY round-trip, http_proxy lowercase, invalid proxy clean error, NO_PROXY bypass, recv --watch through proxy, 5 MiB payload, bad relay clean error.
| Code | Name | Meaning |
|---|---|---|
| 0 | OK | Success |
| 1 | NotFound | No message (single-shot miss or watch deadline) |
| 2 | Usage | Bad flags, missing args, passphrase on argv |
| 10 | CryptoLocal | Local crypto failure |
| 11 | RelayUnreachable | Network error (DNS, TCP, TLS) |
| 12 | Collision | Bootstrap slot collision |
| 13 | Auth | Relay rejected write token (401/403) |
| 14 | SizeCap | File exceeds 10 MiB |
| 15 | CapsuleUnwrap | Wrong passphrase or corrupt capsule |
| 16 | RelayOverloaded | Relay returned 429 or 503 |
| 17 | BootstrapMITM | Bootstrap AEAD open failed |
| 18 | BootstrapAuthFail | Bootstrap auth failure |
| 19 | BootstrapTimeout | Timeout waiting for peer |
| 20 | Internal | Unclassified internal error |
| 21 | E2EUnwrap | Content-AEAD open failed |
| 22 | IdentityMiss | No E2E identity entry for pair |
| 23 | IdentityStore | OS identity store backend error |
| 24 | PlatformUnsupported | No identity store on this OS |
| 130 | Interrupted | Ctrl-C during --watch |
Use in scripts:
deaddrop recv /tmp/out.txt
case $? in
0) echo "got it" ;;
1) echo "no message yet" ;;
11) echo "relay unreachable" ;;
15) echo "wrong passphrase" ;;
130) echo "interrupted" ;;
*) echo "error: $?" ;;
esacSingle-shot recv probes the last 3 minute-buckets. The relay's
slot TTL (default 1 hour) is a cleanup safety net, not a delivery
window. If the receiver runs recv more than ~3 minutes after
send, single-shot will miss — use --watch instead.
--passphrase=foo or --passphrase foo on the command line exits
with code 2. Passphrases leak into ps, /proc/*/cmdline, shell
history. Use --passphrase-fd or --passphrase-env.
Same reasoning. Use $DEADDROP_DEPLOY_SECRET env var or
--deploy-secret-fd 3 with a heredoc:
deaddrop send --deploy-secret-fd 3 ~/file.txt 3<<<"hex:$SECRET"DEADDROP_DEPLOY_SECRET is needed by both send and recv (it
derives the slot address). DEADDROP_WRITE_TOKEN is only needed
for send and bootstrap.
After deaddrop bootstrap, subsequent send/recv automatically
use E2E wrapping (wire version 0x04). No flags needed.
--require-e2e is default-on (D-71): any send/recv against a
capsule with no identity entry exits 22 (IdentityMiss). Two cases
have no identity entry and therefore require --no-require-e2e:
keygencapsules (§3 Option A) — a shared symmetric secret, never paired, so there is no per-pair identity. This is a current, supported workflow, not legacy.- pre-v0.1.5 capsules — created before the identity layer existed.
In both cases --no-require-e2e selects the legacy 0x01 wire path
(relay-opaque transport encryption, but no content-layer AEAD). It
prints a deprecation warning. For full E2E, rebootstrap (Option B).
The capsule file contains the wrapped PSK. Anyone with the capsule
AND the passphrase can decrypt your messages. Store it with
chmod 600 (keygen does this automatically). Don't commit it to git.
Linux session keyring is inherited by tmux/screen child processes. Cached passphrases and identity keys are accessible after detach/reattach — this is intentional.
On macOS, tmux/iTerm/Terminal all run as the same user with access to the same login keychain — no inheritance to worry about. The ACL "Always Allow" choice you made for the deaddrop binary applies regardless of which terminal launched it.
Containers may not have access to the host keyring. If deaddrop
runs inside a container and needs passcache or E2E identity:
- Ensure the
keyctlsyscall is allowed (not blocked by seccomp) - Or use
--passcache=noneand--no-require-e2e
A deaddrop binary downloaded via Safari, curl, or AirDrop is
quarantined by macOS. First run shows "deaddrop cannot be opened
because the developer cannot be verified." Either build from source
(no quarantine), or strip the attribute:
xattr -d com.apple.quarantine ./deaddropBuilding from source on the same Mac is cleaner because it avoids the prompt entirely and Keychain ACL prompts will name the local build path consistently.
You clicked "Allow" on the first ACL prompt instead of "Always Allow." The fix is to delete the entry and re-run, then pick "Always Allow":
# passcache:
security delete-generic-password -s deaddrop
# identity (per pair):
security delete-generic-password -s deaddrop-identity \
-a 'deaddrop:pair:<hex16>'Exit code 24 is reserved for platforms with no identity store
backend (FreeBSD, OpenBSD, etc.). macOS Keychain is always present;
if you see exit 24 on a Mac, something else is wrong (binary built
with the wrong build tags?). On macOS the relevant identity-related
errors are 22 (IdentityMiss — locked keychain or no entry) and 23
(IdentityStore — Keychain backend error).
Maximum 10 MiB per message. For larger files, split first:
split -b 9M largefile.tar.gz part_
for f in part_*; do deaddrop send "$f"; doneSender and receiver clocks must agree within ~3 minutes for
single-shot recv (they derive minute-bucket addresses from wall
clock). Use NTP. The --watch mode is immune to moderate skew
since it polls continuously.
deaddrop keygen <path> create capsule
deaddrop fingerprint [--identity] print fingerprint
deaddrop send <file> encrypt + upload
deaddrop recv [file] download + decrypt (stdout if no file)
deaddrop recv --watch [file] poll until message arrives
deaddrop bootstrap --role=initiator start pairing handshake
deaddrop bootstrap --role=responder join pairing handshake
Environment variables:
DEADDROP_RELAY relay base URL
DEADDROP_DEPLOY_SECRET anti-enumeration secret (hex: or b64: prefix)
DEADDROP_WRITE_TOKEN relay write auth token
DEADDROP_CAPSULE capsule file path (default: ~/.deaddrop/capsule)
HTTPS_PROXY / http_proxy HTTP proxy for all relay traffic
NO_PROXY comma-separated hosts to bypass proxy
SSL_CERT_FILE custom CA bundle (for self-signed relay TLS)