Install on Proxmox
Create an unprivileged LXC with the app and its database services.
The scripts in
proxmox/
provide a local, Community Scripts-style deployment while the app is not listed in the
Proxmox VE Community Scripts catalog. On a Proxmox VE 9 or newer host,
download only open-tabletop.sh. It fetches the app source from
https://github.com/optimuspryne/open-tabletop.git at main by
default and extracts its companion proxmox/install.sh from that same source
revision. It creates an unprivileged Debian 13 LXC with nesting enabled so Debian's Redis
systemd service can create its user namespace; the companion installs Node.js 26,
PostgreSQL 16, Redis, and the app directly inside it and enables a non-root systemd
service. Docker is not used. The Proxmox host needs git for this fetch.
Nesting does not make the container privileged, but it relaxes isolation by exposing some
host /proc and /sys information to the guest.
Sign in to the Proxmox host and download the host script from a specific pushed commit.
Set SOURCE_REF to that commit too, so the fetched app and companion match the
host script. Find the commit SHA with git rev-parse HEAD on your workstation
after committing. Replace REV, email, storage, and CTID with your values. For
NFS-backed uploads, mount the export on the Proxmox host first and set
ASSETS_HOST_PATH to a directory on it; omit that variable if uploads should
live inside the container.
ssh root@YOUR-PVE-HOST
REV=PASTE_FULL_PUSHED_COMMIT_SHA
curl -fsSLo /root/open-tabletop.sh \
"https://raw.githubusercontent.com/optimuspryne/open-tabletop/$REV/proxmox/open-tabletop.sh"
SOURCE_REF="$REV" CTID=123 ROOTFS_STORAGE=local-lvm BOOTSTRAP_ADMIN_EMAIL=you@example.com \
ASSETS_HOST_PATH=/mnt/open-tabletop-assets \
bash /root/open-tabletop.sh install
Inspect the downloaded script before executing it as root. The app and container installer come from the selected Git revision, not from the downloaded script's URL; pinning both to the same commit keeps them in sync. Only pushed commits can be fetched this way.
The script selects the next free CTID when CTID is unset and prompts for
storage and the admin email when those values are unset. Other optional settings are
TEMPLATE_STORAGE (default local),
BRIDGE (vmbr0), IP (dhcp, or an IPv4
CIDR with GATEWAY), CORES (2),
RAM_MB (2048), DISK_GB (12),
CT_HOSTNAME (open-tabletop), and
BOOTSTRAP_ADMIN_USERNAME (admin). For a new LXC, the launcher
waits for an IPv4 address and default route before package setup. If they do not appear
after about 30 seconds, it reboots the LXC once and waits again. A second failure stops
the install without deleting the container so you can inspect its DHCP and bridge
configuration. The source and installer have already been copied into the LXC, so after
fixing its network you can resume without recreating it:
SOURCE_ID=$(pct exec 123 -- sha256sum /root/open-tabletop-source.tar | cut -c1-40)
pct exec 123 -- env SOURCE_ID="$SOURCE_ID" BOOTSTRAP_ADMIN_USERNAME=admin \
BOOTSTRAP_ADMIN_EMAIL=you@example.com bash /root/open-tabletop-install.sh install
The same network check also applies when IP and GATEWAY specify
a static address. The installer creates database passwords and a strong initial admin
password; read them inside the container with
pct exec 123 -- cat /root/open-tabletop-credentials.txt. Keep that root-only
file private. The service listens on port 2567; use a reverse proxy with TLS
for internet access and set TRUST_PROXY_HOPS in
/etc/open-tabletop/open-tabletop.env to the actual proxy hop count. The
container installer retries APT index updates and fails on transient fetch errors instead
of using stale package lists. If a first install stops during package setup or while
starting PostgreSQL or Redis, it can be retried after fixing the underlying problem; its
NodeSource key import allows an existing key. This does not make arbitrary later
installation failures automatically recoverable.
Set SOURCE_REF to a branch, tag, or commit to deploy something other than
main; SOURCE_REPO can point at another Git remote. To test
committed app code that you have not pushed, copy the host script and a
source archive from your workstation instead:
git archive --format=tar --output=open-tabletop-source.tar HEAD
scp proxmox/open-tabletop.sh open-tabletop-source.tar root@YOUR-PVE-HOST:/root/
SOURCE_ARCHIVE=/root/open-tabletop-source.tar CTID=123 ROOTFS_STORAGE=local-lvm \
BOOTSTRAP_ADMIN_EMAIL=you@example.com bash /root/open-tabletop.sh install
SOURCE_ARCHIVE takes precedence over the Git fetch and must include
proxmox/install.sh. Uncommitted files are not included in a Git archive. To
test an uncommitted companion script, copy it separately and set
INSTALLER_PATH=/root/install.sh when running the host script.
To put uploads on NFS, mount the export on the Proxmox host first and set
ASSETS_HOST_PATH=/path/to/mounted/assets at initial installation. The script
bind-mounts that directory into the LXC at /var/lib/open-tabletop/assets and
checks that the app can write to it. It verifies the path is currently on an NFS
filesystem so a missing host mount cannot quietly put uploads on the Proxmox host's local
disk. Ensure that NFS mount is available before the LXC starts after a host reboot.
The LXC app user is UID/GID 1000:1000. With Proxmox's default unprivileged
mapping, that is 101000:101000 on the host and NFS server, so prepare the
export for those numeric IDs. This differs from the Docker image's 100:101. A
custom LXC ID map changes the host IDs. Proxmox container backups do not include
bind-mounted NFS data; back up that export separately.
To deploy a newer pushed commit, run
SOURCE_REF=YOUR_PUSHED_REVISION bash /root/open-tabletop.sh update 123 on the
Proxmox host (or pass a new SOURCE_ARCHIVE). Without an explicit source
selection, the launcher fetches main. Save active games and have players
leave before starting the update; the generated database dump cannot include unsaved live
hands or moves. The update creates a PostgreSQL dump under
/var/backups/open-tabletop/, installs dependencies into a new release
directory, switches the service to it, and checks HTTP readiness. Older release
directories remain available. Database migrations may not be reversible, so restore the
database dump along with an older release if an upgrade must be rolled back. For logs, run
pct exec 123 -- journalctl -u open-tabletop -n 100 --no-pager.
Sources checked: proxmox/open-tabletop.sh, proxmox/install.sh, README.md. Reviewed September 29, 2026 against the working source. Published releases may differ; check the changelog for your version.