A small Go tool that wraps the `/etc/hosts` + `once deploy --disable-tls` recipe needed to host a Once app on a single-label `<name>.local`. Adds the hosts entry, runs the deploy, polls /up, and on removal cleans the hosts line that the Once UI orphans (including the orphan-only case, where the app is already gone). Bubble Tea TUI for interactive use; non-interactive CLI for scripts. Curated apps live in /etc/once-add/apps.toml; seeded with Writebook + Campfire on first run. |
||
|---|---|---|
| cmd/once-add | ||
| internal | ||
| .gitignore | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| README.md | ||
once-add
Deploy and remove a Once app at a single-label <name>.local
host. Adds the right /etc/hosts entry, runs once deploy --disable-tls, and
(on removal) cleans the /etc/hosts line that the Once UI orphans.
Why it's needed
Once's binary is statically linked (pure-Go resolver), so its post-deploy
GET /up verify resolves /etc/hosts + real DNS only — never mDNS — and the
TUI install forces TLS on (no Let's Encrypt cert for a private .local). Either
one makes Once roll back the container. once-add runs the working recipe:
echo "127.0.0.1 <name>.local" | sudo tee -a /etc/hosts # so Once's verify resolves it
once deploy <image> --host <name>.local --disable-tls # TLS off; http verify passes
For other machines on your LAN to reach the site you'll also need an mDNS
publisher running on the box (something that announces <name>.local over
Avahi). Without one, the site is only reachable from the hosting box itself.
Install
curl -fsSL https://github.com/28allday/once-add/releases/latest/download/once-add \
-o once-add && sudo install -m 755 once-add /usr/local/bin/once-add && rm once-add
Usage
Runs as root (it edits /etc/hosts); self-elevates with sudo if needed.
once-add # interactive wizard (Add / Remove)
once-add book ghcr.io/basecamp/writebook # add (non-interactive)
once-add remove book # remove app + its /etc/hosts entry
once-add remove book --data # also delete the data volume (irreversible)
once-add remove # interactive remove picker
Add wizard: pick a curated app (or a custom image) → name it → deploy →
reachable at http://<name>.local.
Remove runs once remove <host> and then clears the /etc/hosts line
once-add added (the Once UI removes the container but orphans that line). Data
volumes are kept by default — pass --data (or tick the toggle in the wizard)
to delete them too. If the app is already gone, the orphaned /etc/hosts line
is cleaned up anyway.
Curated apps
Edit /etc/once-add/apps.toml to add entries — no rebuild needed. once-add
seeds a default file (Writebook, Campfire) on first run if it's missing.
[[app]]
name = "Writebook"
image = "ghcr.io/basecamp/writebook"
description = "Books & documentation"
suggested = "book"
Build
CGO_ENABLED=0 go build -o once-add ./cmd/once-add # static binary
go test ./...
Licence
MIT.