Install with Node.js
Run the app directly with your own PostgreSQL and Redis services.
Prepare the services
These instructions use Node.js 24, the runtime used by the production Dockerfile, plus npm, Git, OpenSSL, PostgreSQL, and Redis. Install and start PostgreSQL and Redis before starting the app. The app has no browser build step.
Download the source
git clone https://github.com/optimuspryne/open-tabletop.git
cd open-tabletop
npm ci --omit=dev
cp .env.example .env
Complete the database and administrator setup below before running npm start.
Use the configuration and migration files from the same revision as the application.
PostgreSQL
Use separate database logins for migrations and normal application traffic. For a new
local database, open an administrator psql session, for example
sudo -u postgres psql, and run the following. Each
\password command prompts for a new password; keep the two passwords
separately.
CREATE ROLE tabletop LOGIN;
\password tabletop
CREATE DATABASE tabletop OWNER tabletop;
CREATE ROLE tabletop_app LOGIN;
\password tabletop_app
\connect tabletop
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
GRANT CREATE, USAGE ON SCHEMA public TO tabletop;
GRANT CONNECT ON DATABASE tabletop TO tabletop_app;
GRANT USAGE ON SCHEMA public TO tabletop_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO tabletop_app;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO tabletop_app;
ALTER DEFAULT PRIVILEGES FOR ROLE tabletop IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO tabletop_app;
ALTER DEFAULT PRIVILEGES FOR ROLE tabletop IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO tabletop_app;
\quit
For a managed database, use its administrator connection and equivalent role/database setup. Configure PostgreSQL to accept password-authenticated connections from the app. Do not run these fresh-install commands over existing roles or databases.
In .env, replace the example passwords with the ones you chose.
Percent-encode special characters in URL usernames and passwords.
DATABASE_URL=postgresql://tabletop_app:APP_PASSWORD@127.0.0.1:5432/tabletop
MIGRATE_DATABASE_URL=postgresql://tabletop:OWNER_PASSWORD@127.0.0.1:5432/tabletop
REDIS_URL=redis://127.0.0.1:6379
ASSETS_DIR=./saved-assets
NODE_ENV=production
The owner connection applies pending numbered migrations at startup. Default privileges
above also cover tables created by future migrations. The runtime connection uses
tabletop_app.
If you manage migrations yourself, set AUTO_MIGRATE=false. Apply
postgres/schema.sql only to a fresh database; for an existing database, apply
pending numbered migrations in order. Current source includes migration
023 for account recovery; release 0.20.0 ends at
022. See Backups and upgrades.
DATABASE_URL_FILE and MIGRATE_DATABASE_URL_FILE can hold the
corresponding connection URLs instead. Keep configuration and secret files readable only
by the operator and application account.
Configure the initial administrator
Create a password file as the account that will run the app:
mkdir -p secrets
(umask 077; openssl rand -hex 24 > secrets/admin_password.txt)
Set all three bootstrap values in .env:
BOOTSTRAP_ADMIN_USERNAME=admin
BOOTSTRAP_ADMIN_EMAIL=you@example.com
BOOTSTRAP_ADMIN_PASSWORD_FILE=./secrets/admin_password.txt
The generated password is the file's content. Bootstrap creates an administrator only when
the users table is empty. It never resets an existing account. The copied
.env.example already contains a username and email, so leaving out the
password-file setting causes a partial-configuration startup error.
For an existing account, administrator recovery explains the promotion command. Promotion does not reset its password.
Start and connect
npm start
npm start loads the project .env. A direct
node server.js launch needs its environment supplied separately. Open
http://localhost:2567, or use the server's LAN address from another device.
Sign in with the configured administrator. Use separate accounts to test multiplayer play.
The process runs in the foreground. For an installed systemd service with generated credentials and update commands, use the Linux installer. See Networking and HTTPS before exposing the app beyond your LAN.
Redis and storage
Production uses Redis for shared authentication and upload rate limits. Configure
REDIS_URL or REDIS_URL_FILE; requests protected by Redis return
503 when it is unavailable. RATE_LIMIT_STORE=memory explicitly selects an
in-process store and is intended for local development.
Back up PostgreSQL and ASSETS_DIR together. Uploaded files live on disk;
accounts, asset metadata, room settings, and saved games live in PostgreSQL.
Save Table checkpoints a game's pieces and hands.
Sources checked: package.json, postgres/grants_app_role.sql, migrate.js, server/bootstrap-admin.js. Reviewed September 29, 2026 against the working source. Published releases may differ; check the changelog for your version.