A multiarch tang Docker image, based on Alpine Linux.
50K+
A Tang server in a container, based on Debian 12. Tang provides the network half of NBDE (Network Bound Disk Encryption): a client bound with Clevis can unlock its LUKS volume automatically as long as it can reach the Tang server, and only then.
Tang itself holds no secrets belonging to the client — it never sees the passphrase or the key. It only participates in a key exchange that succeeds when the client is on the expected network.
/db volume.docker run -d --name tang \
-p 8080:8080 \
-v tang-db:/db \
docker_tang
On the first start Tang generates a fresh key pair in /db. Verify the server
answers:
curl http://localhost:8080/adv
Bind a client to it with Clevis, using the address the client will actually reach:
clevis luks bind -d /dev/sda2 tang '{"url":"http://tang.example.com:8080"}'
Clevis shows the key thumbprint and asks for confirmation. Compare it against the server before accepting — that check is what stops an attacker from substituting their own Tang server.
| Variable | Default | Purpose |
|---|---|---|
ENABLE_IPv4 | 1 | Listen on IPv4. Set to any other value to disable. |
ENABLE_IPv6 | 1 | Listen on IPv6. Set to any other value to disable. |
IPv6-only operation:
docker run -d -e ENABLE_IPv4=0 -p 8080:8080 -v tang-db:/db docker_tang
Disabling both protocols leaves the container running with no listener; the healthcheck then trivially passes because it checks nothing.
| Path | Contents |
|---|---|
/db | Tang signing and key-exchange keys (.jwk files) |
A host directory works just as well as a named volume:
docker run -d --name tang -p 8080:8080 -v /path/to/tang/db:/db docker_tang
The files are written as root, since this image does not drop privileges.
Back this volume up. Losing /db means every client bound to this server can
no longer unlock automatically and has to be rebound with its recovery passphrase.
Tang is served on port 8080 inside the container over plain HTTP.
There is no long-running Tang daemon. start-servers runs socat listeners that
fork a tangd process per connection:
socat TCP4-LISTEN:8080,reuseaddr,fork for IPv4socat TCP6-LISTEN:8080,ipv6only=1,reuseaddr,fork for IPv6socat passes the client address into the REMOTE_ADDR environment variable so
tangd can log it. The healthcheck (check-servers, every 5 s) requests /adv
over each enabled protocol via loopback.
Rotate by renaming the current keys in /db so their filename starts with a dot,
then generating new ones:
docker exec tang sh -c 'cd /db && for k in *.jwk; do mv "$k" ".$k"; done'
docker exec tang /usr/libexec/tangd-keygen /db
Hidden keys are no longer advertised to new clients but still accept existing bindings, which gives already-bound clients time to be rebound. Delete the hidden files only once every client has been rebound.
/etc/docker-entrypoint.d/99-extra-scripts are a leftover from
padhi-homelab/docker_tang, the
Alpine-based image this one was forked from. Its base image ran an entrypoint
runner and dropped privileges through DOCKER_UID
(background);
the Debian base image here has neither, so those scripts never run.Forked from padhi-homelab/docker_tang and rebased on Debian. Upstream also ships a compose setup under padhi-homelab/services.
docker build -t docker_tang .
This project uses pre-commit for style and quality checks, Conventional
Commits for the history, and Renovate for dependency updates.
MIT — see LICENSE.
Content type
Image
Digest
sha256:bd5a10a8f…
Size
57.8 MB
Last updated
about 9 hours ago
docker pull ricariel/tang