Hardened Tor hidden service container. Tor + Vanguards, reproducible, post-quantum signed.
2.0K
A hardened Tor hidden service container. Tor 0.4.9.14 with the Vanguards addon on Alpine 3.23, every dependency pinned and hash-verified at build time, built for a state-level adversary threat model.
docker pull doingfedtime/hiddenforge
curl -O https://sambent.dev/sam/HiddenForge/raw/branch/master/docker-compose.yml
# edit the two lines marked <-- EDIT (your service name + your backend image)
mkdir -p ./tor-keys
docker compose up -d
# your .onion appears here once Tor bootstraps (first boot takes a couple of minutes)
docker compose exec tor cat /var/lib/tor/hidden_service/myapp/hostname
The compose file ships with every security flag pre-configured. Your backend is network-isolated and never exposed to the internet.
| Layer | Mechanism |
|---|---|
| Syscall filtering | the engine's default seccomp profile, with Tor's own Sandbox 1 filter stacked on it |
| Privilege drop | runs as the unprivileged tor user |
| Guard-discovery defence | VanguardsLiteEnabled 1, pinned so a consensus parameter cannot switch it off |
| DoS defence | proof-of-work at rendezvous + intro-point rate limiting |
| Debugger blocking | DisableDebuggerAttachment 1 |
| Disk minimisation | AvoidDiskWrites 1, keys never paged to swap |
| Log scrubbing | SafeLogging 1, no host-side log file |
| Filesystem | read-only container, tmpfs for all writable paths |
| Key-volume tampering | privileged startup refuses to follow symlinks out of the key directory |
| No relay/exit | ClientOnly 1, ExitPolicy reject *:* |
COPY states its file mode and
every destination directory is created 0755 first, so clones made under umask
007 and 022 build the same digest. The software in the image is unchanged from
2.1.0. 2.1.2 supersedes 2.1.1, which shipped two directories as mode 0644hiddenforge setup, show, status, doctor, verify-image,
sbom, backup/restore, rotate, vanity and more, plus a machine-readable
contract (version --json, info --json, manifest.json)ready is reported only after Tor has uploaded the
onion service descriptorseccomp=unconfined removed from the compose files; tor 0.4.9.14,
python3 3.12.15, openssl 3.5.9 and zlib 1.3.2-r1 pinned; no known vulnerability
at any severityUpgrading from 2.0.4? Keys and onion address carry over, but a compose file
copied from 2.0.4 needs a few changes (remove seccomp=unconfined and
ulimits.nproc, add dns: 127.0.0.1, keep a restart policy). See "Upgrading from
2.0.4" in the README.
Full changelog and every previous release: https://sambent.dev/sam/HiddenForge/releases
People's safety depends on this image being the one built from the public source. Every release is signed over its image digest two independent ways, with no transparency log and no third-party service:
2.1.2 is signed with ML-DSA-65; it carries no hardware signature, so verify with
hiddenforge verify-image --allow-pq-only.
The build is also reproducible: rebuild from the tag and you get the same digest.
Verification files and the step-by-step guide: https://sambent.dev/sam/HiddenForge
Source, issues, signatures and documentation are at https://sambent.dev/sam/HiddenForge (the maintainer's own forge).
The image is published to both this Docker Hub repository and the maintainer's
own registry at sambent.dev/sam/hiddenforge. Both serve the identical digest:
pull from whichever you prefer, and verify either against the same signatures.
The Tor layer is hardened; the application behind it is not. Onion services are almost always located because the app told someone where it lives: an outbound clearnet request, an absolute URL, a real hostname in a redirect or error page, a server banner matchable against a clearnet scan, or a leaked timezone. Keep your backend on the internal network and audit what it emits.
Licensed under the terms in the repository.
Content type
Image
Digest
sha256:1127470c8…
Size
36 MB
Last updated
4 days ago
docker pull doingfedtime/hiddenforge