Wiki contents
Installing and hosting

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.