- HTML 57.5%
- Python 25.3%
- Shell 10.9%
- Dockerfile 3.4%
- CSS 2.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| btpd | ||
| examples | ||
| gateway | ||
| portal | ||
| .env.example | ||
| .gitignore | ||
| bootstrap.sh | ||
| CHANGELOG.md | ||
| docker-compose.yml | ||
| LICENSE | ||
| README.md | ||
| seed-example-site.sh | ||
btp-docker
Production deploy stack for the Berkeley Transport Protocol — the post-quantum successor to HTTP + TLS.
Compress everything. Trust nothing. Encrypt always.
btp-docker is the operator-facing Docker Compose stack for the BTP
reference implementation. It bundles the origin daemon (btpd), an
HTTPS browser gateway, a discovery portal, and an optional witness
service into one repeatable deploy behind
Nginx Proxy Manager.
The protocol implementation itself lives in the separate
btp repository.
Current version: see CHANGELOG.md.
Layout
btp-docker/
├── README.md this file
├── CHANGELOG.md versioned change history
├── LICENSE Apache-2.0
├── .env.example copy to .env, edit if needed
├── .gitignore ignores data/ and .env
├── bootstrap.sh one-shot deploy / update / stop / logs
├── docker-compose.yml 4 services (3 active + 1 optional witness)
├── seed-example-site.sh generate signed example doc via container's btpctl
│
├── btpd/
│ └── Dockerfile builds btpd via --from=btp_source, with nc
│
├── gateway/
│ ├── Dockerfile builds btpctl + adds local server.py
│ ├── server.py Flask + share-link engine (Session-B hardening)
│ └── tests/test_server.py pytest suite (25 tests)
│
├── portal/
│ ├── Dockerfile nginx:alpine with envsubst template
│ ├── nginx.conf hardened CSP that actually works
│ └── html/ self-contained landing site
│ ├── index.html 12 languages + dynamic content + origin info
│ ├── connect.html full connect guide with envsubst vars
│ └── styles.css connect.html styling (palette-aligned)
│
└── examples/
├── build-example-site.sh host-side alternative (no docker exec needed)
└── example.md
Ports
| Service | Host port | Container port | Behind NPM? |
|---|---|---|---|
btpd |
3004 | 4434 | No (raw TCP — BTP wire protocol) |
portal |
3003 | 80 | Yes |
gateway |
3005 | 8088 | Yes |
witness (optional) |
3006 | 9443 | Yes |
All host ports configurable in .env.
Prerequisites
- Linux host (tested: Debian 12, Ubuntu 22.04+, Fedora 39+)
- Docker Engine 24.0+ with the buildx plugin (BuildKit) and compose v2 plugin
- Optional: Nginx Proxy Manager already running on the host
Verify:
docker version # 24.0+
docker buildx version # any recent — required for additional_contexts
docker compose version # v2.20+
Quick deploy
# 1. Get the BTP source (the Dockerfiles need it via additional_contexts)
cd /opt
git clone https://git.securityops.co/cristiancmoises/btp.git
# 2. Get this stack
git clone https://git.securityops.co/cristiancmoises/btp-docker.git
# 3. Bootstrap and seed
cd btp-docker
./bootstrap.sh
./seed-example-site.sh # produces the signed origin doc
sudo ufw allow 3004/tcp # open the BTP TCP port to the wider internet
The bootstrap script auto-detects the BTP source by trying, in order:
$BTP_SOURCE_DIRenv var (highest precedence)$BTP_SOURCEfrom.env../btp(most common after side-by-side clone)../btp-source/opt/btp
It then:
- Checks Docker + compose v2 + buildx are installed
- Verifies (and offers to create) the
npm-bridgenetwork - Creates data directories with the right ownership
- Builds and starts the stack
- Probes each service for health (max 120 s)
- Prints a summary with next-step actions
Upgrade from a prior version
cd /opt
docker compose -f btp-docker/docker-compose.yml down
# extract the new tarball next to the existing tree
tar -xzf btp-docker-<new-version>.tar.gz
# carry forward .env and data/ (bind-mounted state)
cp /opt/btp-docker/.env /opt/btp-docker-<new-version>/.env
cp -a /opt/btp-docker/data /opt/btp-docker-<new-version>/
# atomic swap with versioned backup
mv /opt/btp-docker /opt/btp-docker.<old-version>-bak
mv /opt/btp-docker-<new-ver> /opt/btp-docker
cd /opt/btp-docker
./bootstrap.sh
./seed-example-site.sh # idempotent; reuses key + doc if present
For per-version migration notes, see CHANGELOG.md.
Bootstrap script subcommands
./bootstrap.sh # full deploy + start + healthcheck
./bootstrap.sh --check # preflight only — no build, no start
./bootstrap.sh --update # rebuild (pulling base images) + restart
./bootstrap.sh --logs # tail logs from all services
./bootstrap.sh --stop # docker compose down
./bootstrap.sh --help # this summary
NPM configuration
Configure proxy hosts:
| Domain | Forward Host | Forward Port |
|---|---|---|
btp.securityops.co |
172.17.0.1 |
3003 |
btp-gw.securityops.co |
172.17.0.1 |
3005 |
w1.btp.securityops.co |
172.17.0.1 |
3006 |
For each: enable Block Common Exploits, Cache Assets, Websockets Support. SSL via Let's Encrypt with Force SSL and HTTP/2 Support.
Operating
Seeding the first signed document (fresh deploy)
After ./bootstrap.sh, data/site/ is empty so the gateway returns
502 upstream_error for /render and /raw. Run the bundled helper
once to generate an origin key, capture the BLAKE3 fingerprint from the
CLI output, and sign an example document — all via the btpctl that
ships inside the gateway container (no need for btpctl on host):
./seed-example-site.sh
Re-runs are idempotent. Use --force to re-sign with the same key, or
--regen-key to rotate the origin key (this breaks pinned clients).
The seed script uses the real btpctl CLI surface:
btpctl genkey --out FILE --ml-dsa— writes JSON{sk, pk}and prints the BLAKE3-256 fingerprint to stdout. The script parses both.btpctl doc new --ml-dsa-key FILE --title … --input … --out …— signs.btpctl doc verify FILE— sanity-check before exfiltrating from the container.
File movement to/from the container uses docker exec -i ... sh -c 'cat > F' and docker exec ... cat F (not docker cp), which avoids
a tmpfs visibility bug on certain Docker daemon versions when the
container's rootfs is read-only.
Adding a signed document
# On your build host (NOT the VPS), with btpctl in PATH:
btpctl genkey --out origin --ml-dsa
btpctl doc new --ml-dsa-key origin --title "Hello" --input hello.md --out hello.btp
# Rsync to VPS:
scp hello.btp vps:/opt/btp-docker/data/site/
btpd auto-reloads with --verify-on-load on the next request.
Origin fingerprint
Put your origin's BLAKE3-256 fingerprint in data/keys/fingerprint.txt.
This shows up on the portal homepage (in the "This BTP Origin" section)
for visitors to pin. The seed script writes this automatically.
To compute the fingerprint of an existing key out-of-band, the simplest
trick on the current CLI is to sign a throwaway doc and read the author
fingerprint from doc verify output:
echo '# probe' > /tmp/probe.md
btpctl doc new --ml-dsa-key origin --title probe --input /tmp/probe.md --out /tmp/probe.btp
btpctl doc verify /tmp/probe.btp | grep author
The genkey --ml-dsa command also prints the fingerprint at key
generation time — easiest to capture it then.
Backups
Only stateful data: data/gateway/sharelinks.db (SQLite share-link DB)
and data/keys/origin.key (the ML-DSA-87 keypair JSON). data/site/ is
reproducible from your signed documents.
# Daily DB backup
sqlite3 data/gateway/sharelinks.db ".backup '/backup/sharelinks-$(date +%F).db'"
# Origin key — copy to offline media, NEVER to cloud storage
cp data/keys/origin.key /media/usb/btp-origin-$(date +%F).key
License
Apache-2.0 (matches the BTP reference implementation). See LICENSE.
The names "BTP" and "Berkeley Transport Protocol" are registered
trademarks of Security Ops. See
TRADEMARK.md
in the main repo. Nominative fair use is fine; calling YOUR
implementation "BTP" requires passing the conformance test suite at
crates/btp/tests/conformance/.
Contact
- General: sac@securityops.co
- Bug reports: https://git.securityops.co/cristiancmoises/btp-docker/issues
- Trademark licensing: sac@securityops.co
- Security: sac@securityops.co (PGP at https://securityops.co/.well-known/security.asc)
- LinkedIn: https://linkedin.com/in/cristiancezaemoises
Part of the Security Ops ecosystem.
In Code We Trust.