Small Proxmox-side companion for the TRNG API on w33t.io.
This repository builds a Debian LXC container that talks to an Infinite Noise TRNG over USB, pulls whitened bytes from the infnoise driver, samples the driver's health output, and posts refill batches to the portfolio site's ingest endpoint.
- builds and installs
infnoise - runs a timed refill job with
systemd - sends entropy batches to
https://w33t.io/api/trng/refill - reports health data so the public status page can show entropy-per-bit, estimated K, and recent device activity
The public API is meant to serve from a prefetched pool in Cloudflare D1. This sidecar is the piece that keeps that pool topped off.
ct/infnoise-trng.sh- Proxmox helper script that creates a container and runs the installerinstall/infnoise-trng-install.sh- in-container setup scriptscripts/trng-push.py- refill clientsystemd/- service and timer unitsudev/- FTDI device rule
- Proxmox host can pass the USB device into the container
- the Infinite Noise device presents as FTDI vendor
0403and product6015 - the Cloudflare side already has a
TRNG_DBbinding and aTRNG_INGEST_TOKENsecret
Run the helper directly on the Proxmox host and pin it to the current release tag (v0.1.6). This section is kept in sync with VERSION by scripts/update-release-version.sh:
INFNOISE_LXC_REF="v0.1.6" bash <(curl -fsSL https://raw.githubusercontent.com/w33ts/infnoise-lxc/main/ct/infnoise-trng.sh)Or, if you prefer two commands:
export INFNOISE_LXC_REF="v0.1.6"
bash <(curl -fsSL https://raw.githubusercontent.com/w33ts/infnoise-lxc/main/ct/infnoise-trng.sh)What happens:
- the helper creates a Debian 13 LXC
- it writes the
/dev/bus/usbbind mount andlxc.cgroup2.devices.allowentries into the CT config, installs a host-sideudevrule for the FTDI device, reloads host USB rules, then restarts the CT so USB access is applied cleanly - it downloads the matching release tarball from GitHub
- it copies the installer payload into the container
- it runs the in-container installer and enables
infnoise-trng.timer
After the container is created, the Proxmox console should autologin as root. You can also enter it from the host with pct enter <CTID>. Edit /etc/default/infnoise-trng inside it, set the ingest token, and start the timer.
You can override the release asset URL for testing:
export INFNOISE_LXC_REF="v0.1.6"
export INFNOISE_LXC_TARBALL_URL="https://github.com/w33ts/infnoise-lxc/releases/download/v0.1.6/infnoise-lxc-v0.1.6.tar.gz"
bash <(curl -fsSL https://raw.githubusercontent.com/w33ts/infnoise-lxc/main/ct/infnoise-trng.sh)If the helper clears the terminal and exits with:
/dev/fd/62: line 364: SSH_CLIENT: unbound variable
you were hitting an upstream community-scripts helper bug triggered when SSH_CLIENT is unset. ct/infnoise-trng.sh now initializes that variable before sourcing the upstream helper, so current versions run correctly from the Proxmox console, Web UI shell, and non-SSH sessions.
If you are running an older helper revision, use:
SSH_CLIENT='' INFNOISE_LXC_REF="v0.1.6" bash <(curl -fsSL https://raw.githubusercontent.com/w33ts/infnoise-lxc/main/ct/infnoise-trng.sh)If the helper exits with:
Unknown option: lxc.cgroup2.devices.allow
400 unable to parse option
you are running an older revision that tried to pass a low-level LXC config key through pct set. Current versions write both the USB bind mount and lxc.cgroup2.devices.allow: c 189:* rwm directly to /etc/pve/lxc/<CTID>.conf, then restart the container so the USB permission takes effect.
To repair an already-created container manually from the Proxmox host:
printf '%s\n' 'lxc.cgroup2.devices.allow: c 189:* rwm' >> /etc/pve/lxc/<CTID>.conf
printf '%s\n' 'lxc.mount.entry: /dev/bus/usb dev/bus/usb none bind,optional,create=dir' >> /etc/pve/lxc/<CTID>.conf
pct stop <CTID>
pct start <CTID>If the helper fails right after Configuring USB passthrough and pct start exits with 255, the usual cause is the older mp0: /dev/bus/usb,mp=/dev/bus/usb bind mount. That mount is strict about the host path existing at start time, so the CT can fail to boot when /dev/bus/usb is temporarily unavailable. The current helper uses lxc.mount.entry: /dev/bus/usb dev/bus/usb none bind,optional,create=dir instead, which keeps the CT bootable and still exposes the USB bus when it is present.
If the installer prints Failed to send reload request: No such file or directory during the udev step, you were hitting a container without a running udevd control socket. Current versions detect that case and skip the reload instead of surfacing a misleading failure.
If infnoise can see /dev/bus/usb but still cannot open the device, older revisions may have missed the host-side udev permission rule. Current versions install /etc/udev/rules.d/99-infnoise-host.rules on the Proxmox host and run udevadm control --reload-rules && udevadm trigger --subsystem-match=usb before starting the CT.
If the console lands on a login: prompt instead of autologging in, you are running an older release that did not install a console-getty.service autologin override. Current versions configure the console to open directly as root, while pct enter <CTID> continues to work from the Proxmox host.
Also make sure the environment variable and bash command are separated. This is invalid:
export INFNOISE_LXC_REF="v0.1.6"bash <(curl ...)- Create a Debian 13 container.
- Pass the USB device through to the container.
- On the Proxmox host, install a host
udevrule so the unprivileged CT can open the FTDI device:
printf '%s\n' 'SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6015", MODE="0666"' | sudo tee /etc/udev/rules.d/99-infnoise-host.rules >/dev/null
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=usb- Download and extract a release tarball inside the container.
- Run:
INSTALL_ROOT=/path/to/infnoise-lxc-v0.1.6 sudo /path/to/infnoise-lxc-v0.1.6/install/infnoise-trng-install.sh- Copy
.env.exampleto/etc/default/infnoise-trngand fill in the token. - Enable the timer:
sudo systemctl enable --now infnoise-trng.timerThe installer expects an environment file at /etc/default/infnoise-trng.
TRNG_INGEST_URL="https://w33t.io/api/trng/refill"
TRNG_INGEST_TOKEN="replace-me"
TRNG_SOURCE="proxmox-infnoise"
TRNG_BATCH_BYTES="8192"
INFNOISE_BINARY="/usr/local/bin/infnoise"
INFNOISE_HEALTH_TIMEOUT_SECONDS="3"
INFNOISE_REPO_URL="https://github.com/13-37-org/infnoise.git"
INFNOISE_REF="0.3.0"The timer runs every 30 seconds by default.
Each run:
- reads a batch of whitened bytes from
infnoise - captures health output from
infnoise --debug --no-output - posts both to the Cloudflare ingest endpoint
If the device is unavailable or the API rejects the refill, the unit fails and the problem is visible through systemctl status and the journal.
systemctl status infnoise-trng.timer infnoise-trng.service
journalctl -u infnoise-trng.service -n 100 --no-pager
python3 /opt/infnoise-trng/trng-push.py
/usr/local/bin/infnoise --debug --no-output- Proxmox host installs require
INFNOISE_LXC_REFto be set to an explicit tag. - Tagging
v*publishesinfnoise-lxc-<tag>.tar.gzand a.sha256checksum as GitHub release assets. - The GitHub release body includes install commands for the exact published tag.
- The release package is built by
scripts/release-package.shand contains the helper, installer, service files, udev rule, env template, and docs. - CI validates the shell scripts and verifies that the release package can be built before merge.
RELEASING.mddocuments the tag-and-publish workflow.
- This sidecar uses the driver's normal whitened output. It does not expose raw
--rawbits to the public API. - Health values come from the driver's own debug reporting, which is enough for the status page and refill monitoring.
- The helper script mounts
/dev/bus/usbinto the container withlxc.mount.entry ... bind,optional,create=dirand adds the needed cgroup permission, but you may still need to adjust the exact passthrough on your host if your USB topology changes.
MIT