Proxmox VE LXC helper for TeddyTafForge — one-command deploy of TafForge (and optionally TeddyCloud) on Proxmox.
Find a file
vr6syncro aad7f31ddc
All checks were successful
shellcheck / lint (push) Successful in 40s
syntax-validate / dryrun (push) Successful in 29s
chore: add Renovate config with central preset
2026-05-31 00:36:38 +02:00
.forgejo/workflows ci: README link check ignores <placeholder> URLs 2026-05-16 12:09:16 +02:00
ct fix(build.func): silent abort after first dialog (set -e + AND-list) 2026-05-20 12:41:38 +02:00
install fix: round-3 backlog + vendor refresh from upstream TeddyTafForge 2026-05-16 13:11:47 +02:00
misc fix(build.func): silent abort after first dialog (set -e + AND-list) 2026-05-20 12:41:38 +02:00
scripts/dry-test test(dry): full {scope × settings} matrix dry-test under scripts/dry-test/ 2026-05-20 13:00:59 +02:00
vendor fix: verifizierte Findings aus Analyse 2026-05-28 2026-05-29 19:12:15 +02:00
.gitignore init: Proxmox VE LXC helper for TeddyTafForge 2026-05-16 11:47:03 +02:00
CHANGELOG.md fix(build.func): silent abort after first dialog (set -e + AND-list) 2026-05-20 12:41:38 +02:00
LICENSE init: Proxmox VE LXC helper for TeddyTafForge 2026-05-16 11:47:03 +02:00
README.md test(dry): full {scope × settings} matrix dry-test under scripts/dry-test/ 2026-05-20 13:00:59 +02:00
renovate.json chore: add Renovate config with central preset 2026-05-31 00:36:38 +02:00

TeddyTafForge — Proxmox VE LXC helper

One-command deploy of TeddyTafForge — optionally together with TeddyCloud — as an unprivileged LXC on Proxmox VE.

What is TeddyTafForge?

TeddyTafForge is a web UI for building custom Tonie audio files (.taf) to play on a Toniebox. It runs alongside TeddyCloud (the open-source Toniebox server) — TafForge handles the audio import, chapter editing and TAF encoding; TeddyCloud serves the files to the box and provides the admin UI. You need both pieces, but you can run them in one LXC together or keep TafForge as a sidecar to an existing TeddyCloud install.

The wrapper bundles the TafForge install/ stack under vendor/tafforge-install/ so the helper can run without a secondary fetch — the only thing it pulls at install time is the app source (backend + frontend + plugin) from the public GitHub mirror.


Quickstart

Run on your Proxmox VE host as root:

bash -c "$(curl -fsSL https://forgejo.diefamiliekramer.de/vr6syncro/teddytafforge-proxmox/raw/branch/main/ct/teddytafforge.sh)"

A series of whiptail dialogs walks you through the choices. When the script finishes, the URL of the new instance is printed at the end and stored in the LXC's description field in the Proxmox UI.

Paranoid alternative. If you'd rather review the script before running it: curl -fsSL <url> -o /tmp/teddytafforge.sh && less /tmp/teddytafforge.sh && bash /tmp/teddytafforge.sh.


What gets installed?

You choose between two scopes in the first dialog:

Scope Contents When to pick
sidecar Only TafForge You already run TeddyCloud somewhere else (another LXC, a VM, a NAS, …)
all-in-one TafForge + TeddyCloud in the same LXC You're starting fresh and want both on one machine

In sidecar mode you'll be asked for your existing TeddyCloud's URL and, optionally, for the host path of its data directory (so the plugin can be installed cleanly via a bind mount).


Requirements

  • Proxmox VE 8.0 or newer (amd64)
  • Internet access on the PVE host
  • ~16 GB free on a rootdir-capable storage
  • A Linux bridge (vmbr0 by default)

Defaults

Option sidecar all-in-one Override
OS Debian 13 Debian 13 not configurable
CPU 2 cores 2 cores whiptail / var_cpu
RAM 2048 MB 3072 MB whiptail / var_ram
Disk 8 GB 16 GB whiptail / var_disk
Unprivileged yes yes hard-coded
Features nesting=1,keyctl=1 nesting=1,keyctl=1 hard-coded
Network DHCP / vmbr0 DHCP / vmbr0 whiptail
TafForge port 3000 3000 edit /etc/tafforge/tafforge.env after install
TeddyCloud ports n/a 80 / 443 / 8443 not configurable

Power-user ENV overrides (set before invoking the curl line):

TAFFORGE_SCOPE=all-in-one \
TAFFORGE_REF_DEFAULT=v0.2.2 \
TC_REF_DEFAULT=v0.6.2 \
CTID=200 RAM_SIZE=4096 DISK_SIZE=24 \
  bash -c "$(curl -fsSL …/ct/teddytafforge.sh)"

After installation

  • Open the UI at http://<lxc-ip>:3000/
  • Service control (inside the LXC, after pct enter <CTID>):
    • systemctl status tafforge
    • journalctl -u tafforge -f
    • In all-in-one: same with teddycloud
  • Runtime config: /etc/tafforge/tafforge.env (created by the upstream installer; edit and systemctl restart tafforge to apply)
  • Wrapper marker with the versions that were installed: /etc/tafforge/proxmox.meta

Update

The authoritative updater lives inside the LXC and is provided by the TafForge project itself — this repo only wraps it.

Recommended path (in the LXC):

pct enter <CTID>
/opt/tafforge/app/install/lxc/update-app.sh

Convenience path (from the PVE host):

bash -c "$(curl -fsSL https://forgejo.diefamiliekramer.de/vr6syncro/teddytafforge-proxmox/raw/branch/main/ct/update.sh)"

There is intentionally no automatic update timer. Pick a moment that works for you.


Sidecar setup details

If you already run TeddyCloud elsewhere and pick sidecar, the wrapper can mount your TeddyCloud's data directory into the new LXC so TafForge can drop its plugin into the TC plugins folder. The relevant dialog asks for:

  • Host path — the absolute path of the TeddyCloud data directory on the PVE host (e.g. /var/lib/teddycloud-data)
  • LXC mount point — where to mount it inside the LXC (default /mnt/teddycloud-data)

The mount is set as mp0 with backup=0 so a vzdump backup of the TafForge LXC won't try to capture your TC data along with it (your TC data should be backed up at its source).

If you skip the mount you can still use sidecar mode — TafForge will log a warning and you'll have to install the plugin into TC manually.


Uninstall

pct stop <CTID>
pct destroy <CTID>

In sidecar mode the bind mount only points at your TeddyCloud data on the host — pct destroy removes the LXC but leaves your TC data untouched. The TafForge plugin file that was dropped into <TC-data>/www/plugins/ does stay behind; delete it from TeddyCloud's UI or filesystem if you want a clean state.

In all-in-one mode both TafForge and the TeddyCloud install inside the LXC are removed — back up any custom Tonie data first.


Troubleshooting

Symptom Likely cause Fix
pct create fails with "no template" template list still empty after auto-refresh pveam update && pveam download local debian-13-standard_*_amd64.tar.zst
pveam download fails host has no internet / DNS Check /etc/resolv.conf, route, firewall
LXC has no IPv4 DHCP server didn't lease Wait 30s; if persistent, set static IPv4 in advanced mode
TafForge installer warns "UI will be unavailable" frontend build failed (out of RAM during npm run build) bump var_ram to ≥3 GB and re-run, or rebuild manually: pct exec <CTID> -- bash -c 'cd /opt/tafforge/app/frontend && npm ci && npm run build'
All-in-one install finishes but TafForge plugin not in TC TEDDYCLOUD_DATA_DIR pointed at wrong path check /opt/teddycloud/data/www/plugins/teddytafforge/ exists; if not, re-run installer (this was fixed in commit after 4cb4d3e)
apt-get update inside LXC hangs IPv6 default route broken Re-run with "Disable IPv6" answered "yes" in the dialog
TafForge UI loads but shows "TC unreachable" Wrong TEDDYCLOUD_URL Edit /etc/tafforge/tafforge.envsystemctl restart tafforge
TafForge plugin not visible in TC Plugin dir not writable / not mounted Sidecar: check mp0 mount; all-in-one: check /opt/teddycloud/data/www/plugins
TC build fails Upstream build layout changed Pin TC_REF_DEFAULT to a known-good tag (see ENV overrides above)
Installer exits silently after the first "Use defaults?" dialog Pre-2026-05-20 build with the default_settings set -e regression Pull branch/main — fixed; re-run with DEBUG=1 if it still aborts

For TafForge-internal questions (audio import, plugin layout, env vars) see the TeddyTafForge documentation.


Debug mode

If the installer behaves unexpectedly (silent exits, dialogs that don't advance, pct create failures that don't print why), re-run with DEBUG=1:

DEBUG=1 bash -c "$(curl -fsSL https://forgejo.diefamiliekramer.de/vr6syncro/teddytafforge-proxmox/raw/branch/main/ct/teddytafforge.sh)"

What changes:

  • A yellow ! DEBUG MODE — xtrace → /tmp/teddytafforge-trace-<pid>.log banner prints at the start so you know it's on.
  • A full bash -x trace of every command is written to that log file on a dedicated file descriptor — whiptail's stdio redirections cannot corrupt it.
  • Human-readable [DBG …] checkpoints print to your terminal at every meaningful state transition (scope selected, settings collected, pre-flight checks, pct argument vector).
  • On any failure the ERR handler resets the terminal before printing, so the red error line is no longer eaten by whiptail's alt-screen repaint. You get the failing command, the exit code, a FUNCNAME stack trace and the path to the xtrace log.
  • The DEBUG flag is forwarded into the LXC and propagates into the in-container installer, so the whole chain is traced end-to-end.

When you report a bug, attach both the on-screen stack trace and the last ~50 lines of the trace log. Together they pinpoint the exact command, arguments and variable state at the moment of failure.


Security notes

  • The LXC is unprivileged by default. Don't switch to privileged unless you have a specific reason.
  • nesting=1,keyctl=1 is required so systemd inside the LXC behaves correctly. No other privileged features are enabled.
  • The root password defaults to empty / login disabled — SSH key authentication is the intended login path. Provide a key in the dialog, or use pct enter <CTID> from the host.
  • curl … | bash is convenient but a security trade-off. Review the script first if you don't trust the chain.

What this repo does not do

  • It does not back up your LXC — that's vzdump / Proxmox Backup Server.
  • It does not terminate TLS for TafForge — put a reverse proxy (Traefik, Caddy, NGINX, …) in front if you want HTTPS.
  • It does not auto-update — see the "Update" section above.
  • It does not monitor — bring your own observability.

Versioning

  • This repo follows Semantic Versioning. The Quickstart one-liner pulls branch/main, which is what most users want.
  • TAFFORGE_REF_DEFAULT and TC_REF_DEFAULT can be overridden to pin the app versions (see "Power-user ENV overrides" above).
  • The wrapper version + the refs it installed are written to /etc/tafforge/proxmox.meta inside the LXC.

Contributing

Issues and pull requests welcome at forgejo.diefamiliekramer.de/vr6syncro/teddytafforge-proxmox.

Before submitting a script change, please run shellcheck locally:

shellcheck -x ct/*.sh install/*.sh misc/*.func

CI runs the same check plus a --dry-run smoke test that exercises the whiptail flow without calling pct.

Local dry test (the full matrix)

The CI smoke test walks the default sidecar path. For a richer local verification — all four {scope × settings} combinations with title-aware whiptail and DEBUG=1 xtrace — run:

bash scripts/dry-test/matrix.sh

It mocks every PVE binary (pveversion, pvesm, pveam, pct, pvesh, dpkg, id) plus whiptail (FD-correct, title-aware so the sidecar mount-loop terminates), runs start() → build_container() → description() end-to-end under DRY_RUN=1, and reports PASS/FAIL for each combo. Per-run logs end up in /tmp/teddytafforge-dry-test-runN.log, dialog traces in /tmp/teddytafforge-whiptail.log, xtrace in /tmp/teddytafforge-trace-<pid>.log. Useful when bisecting whether a helper change broke a non-default path.


Credits & license

Released under the MIT License.