Install the server.
Local, VPS or Docker.
The server is one Node.js process with SQLite databases and a media folder. It serves the API, the web player, the operator console (/admin), the creator studio (/studio) and the video files.
01How it fits together
| Address | What it serves |
|---|---|
/ | The web player (built from web/) |
/api | The viewer API used by the app and the web player |
/admin | The operator console |
/studio | The creator studio |
/media | Signed HLS playback addresses |
/s/<series> | Share pages with rich previews |
/healthz | Health check ({"ok":true}) |
02Local install
See Quick start. The same commands work on a server.
03Install on a VPS
Commands on this page are for Linux or macOS. Production servers are normally Linux; Docker also runs on Windows. On Windows, run them in WSL (Windows Subsystem for Linux) or Git Bash; PowerShell needs different syntax for some lines.
- Install Node.js 22 and ffmpeg on the server (on Debian or Ubuntu:
apt install ffmpeg). - Upload the item to the server, for example to
/opt/reelora. - Build the web player and the server.
cd /opt/reelora/web && npm ci && npm run build
cd ../server && npm ci && npm run build
- Create
.envfrom the template and fill in the two keys (next section).
cp .env.example .env
openssl rand -hex 32 # run twice: one value for ADMIN_SECRET_KEY, one for MEDIA_SIGNING_KEY
openssl rand -hex 24 # optional: ADMIN_SETUP_TOKEN for the first sign-in
- Start it and keep it running.
npm start # node --env-file-if-exists=.env dist/src/server.js, port 8080
Production runs the compiled JavaScript with plain node; nothing is compiled at run time. To keep it running, use systemd, PM2 or Docker. With PM2, start it through npm so that .env is loaded:
pm2 start npm --name reelora -- start
An example systemd unit (adjust the user and paths):
[Unit]
Description=Reelora server
After=network.target
[Service]
WorkingDirectory=/opt/reelora/server
ExecStart=/usr/bin/npm start
Restart=always
User=reelora
[Install]
WantedBy=multi-user.target
04The .env file
Only what the process needs before the console exists lives in server/.env. Everything else is set in the console. Full list on Configuration.
| Variable | What to put |
|---|---|
ADMIN_SECRET_KEY | 64 hex characters from openssl rand -hex 32. Encrypts the secrets you save in the console (Stripe key, service accounts, AI keys). Back it up: without it the stored secrets cannot be read. |
MEDIA_SIGNING_KEY | Another 64 hex characters. Signs playback addresses. Changing it invalidates links already handed out (they expire anyway). |
ADMIN_SETUP_TOKEN | Optional, 24+ characters from openssl rand -hex 24: the secret that creates the first owner at /admin. Empty = the first start prints a one-time setup code to the log instead. Remove it once the owner exists. |
TRUST_PROXY_HOPS | 1 behind Caddy or nginx, 2 with a CDN in front of that. |
The server creates .admin-secret-key and .media-signing-key in the data folder and prints a warning. Move the value into .env or your host's environment and back it up.
05Docker
The image builds the web player and the server and installs ffmpeg. Run these from the item's root folder:
docker build -t reelora -f server/Dockerfile .
docker run -d --name reelora -p 8080:8080 -v reelora-data:/app/server/data --env-file server/.env reelora
The volume reelora-data keeps the databases and media between container updates. Do not remove it.
06Reverse proxy and HTTPS
Put a TLS-terminating proxy in front of port 8080. Example Caddyfile (Caddy gets the certificate for you):
watch.example.com {
reverse_proxy localhost:8080
}
- Set
TRUST_PROXY_HOPS=1in.env(2 if a CDN sits in front of the proxy), so sign-in limits see the real client address. - Restart the server.
- In the console, set Media & CDN → Public server address to
https://watch.example.com. The status page treats an empty address as a blocker, because playback and checkout links are built from it.
With nginx, proxy all paths to http://127.0.0.1:8080 and raise client_max_body_size to at least your largest upload (console default: 500 MB).
07First sign-in to the console
Nobody can create the owner without a setup secret only you have. Use one of the two:
ADMIN_SETUP_TOKENfrom your.env, if you set it; or- the one-time setup code the first start prints in the server log when the token is empty (
journalctl -u reelora,pm2 logs reeloraordocker logs reelora).
- Open
https://<your domain>/admin, enter the token or the code and create the owner account (12+ character password). - Remove
ADMIN_SETUP_TOKENfrom.envif you used it, and restart. Once an owner exists the setup route is closed for good, and the server log warns while the token is still set. - Work through the setup checklist on the Overview: brand, public server address (Media & CDN), legal links.
- Turn on two-factor authentication for the owner (console → Security).
08Lost the owner password
On the server, in the server/ folder:
npm run reset-owner -- you@example.com
npm run reset-owner -- you@example.com --reset-2fa # also clears two-factor
It prints a new one-time password, signs that owner out everywhere and records the reset in the audit log. Shell access to the server is the authorisation; there is no web route for it. Run it without an e-mail to list the owner accounts.
09Backups
Back up regularly:
server/data/(or yourDATA_DIR): the databasesreelora.sqliteandadmin.sqlite, uploads and HLS files, and any generated key files.server/.env, above allADMIN_SECRET_KEY.
The console's stored secrets are encrypted with ADMIN_SECRET_KEY: if you lose the key, enter the secrets again (key rotation and loss). SQLite can be copied safely while the server runs:
sqlite3 data/reelora.sqlite ".backup data/backup.sqlite"
sqlite3 data/admin.sqlite ".backup data/backup-admin.sqlite"
The console can also export its settings (console → Export and import).