Wiki contents
Configuration

Email recovery

Configure SMTP for email verification and account recovery.

Email is optional; recovery codes and password changes work without it. Install dependencies with npm ci, apply migration 023_account_recovery.sql, restart the server and refresh clients. The application supports the existing owner/runtime role separation and default table privileges. Fresh installs include migration 023 in postgres/schema.sql; existing snapshots remain compatible.

Variable Meaning
PUBLIC_ORIGIN Canonical origin used in email links, e.g. https://tabletop.example.com. No path, credentials, query or fragment. HTTPS required except localhost development. Never derived from request headers.
SMTP_HOST SMTP hostname. Omit to disable email recovery.
SMTP_PORT Defaults to 587. Port 465 uses implicit TLS; all other ports require STARTTLS. Certificate verification remains enabled.
SMTP_FROM Sender email address authorized by your provider; a bare address, not a display-name string.
SMTP_USER Optional SMTP authentication username; must be supplied with a password.
SMTP_PASSWORD_FILE Preferred secret file. Takes precedence over SMTP_PASSWORD; trailing newlines are removed.
SMTP_PASSWORD Optional environment fallback for the SMTP password. Never commit a real value.

When SMTP_HOST is supplied, invalid/incomplete settings fail startup. An unreachable provider is reported as a generic server-side delivery failure; the application does not log recipient addresses, link tokens, message bodies or SMTP credentials. Outbound network access to the chosen SMTP port is required. No inbound SMTP listener, local mail server or new web port is introduced.

Bare-metal Node.js installation

Set these values in the project .env when launching with npm start, which loads that file. Alternatively, supply them through the service manager; a direct node server.js invocation must explicitly load the environment. Replace the example origin, SMTP host, sender and login with your own, and use the port specified by your provider:

PUBLIC_ORIGIN=https://tabletop.example.com
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_FROM=tabletop@example.com
SMTP_USER=your-smtp-username
SMTP_PASSWORD_FILE=/etc/open-tabletop/smtp_password

Create the password file using a local editor. It contains only the SMTP/app password as plain text, for example the dummy value below (replace it with the generated password):

abcdefghijklmnop

Do not include quotes, SMTP_PASSWORD=, JSON or other configuration. A trailing newline is fine. Use an absolute path, make the file readable by the account running the application, and restrict access (for example, mode 600 with that account as owner). Parent directories must also allow that account to reach the file. Do not commit the file or paste its contents into logs or support requests. SMTP_PASSWORD can be supplied as an environment alternative; a configured password file takes precedence. No Docker secret mount is needed on bare metal.

Restart the application through its existing service/process manager after changing these settings. For a foreground npm start process, stop and start it again. No new inbound port is required; allow outbound connections to the provider's SMTP port.

Docker Compose installation

Compose forwards the settings from .env. Use the same provider settings as above, but the password path must be inside the container. To use a file-backed password, create secrets/smtp_password.txt with only the password, as described above, and use a docker-compose.override.yml such as:

services:
  app:
    environment:
      SMTP_PASSWORD_FILE: /run/secrets/smtp_password
    secrets:
      - smtp_password
secrets:
  smtp_password:
    file: ./secrets/smtp_password.txt

Keep that file outside version control and readable only by the appropriate operator/runtime user. Recreate the application container so it receives the updated environment and secret mount:

docker compose up -d --force-recreate app

An ordinary container restart does not load changed Compose environment values. If this is also a code upgrade, rebuild/deploy the updated application image using the normal upgrade procedure.

SMTP provider setup

Use your provider's documented SMTP hostname, port and authentication username. The application uses implicit TLS on port 465 and requires STARTTLS on other ports, commonly 587. Set SMTP_FROM to an address your provider authorizes for sending. The public website origin and sender address need not have identical hostnames. For example, a site at https://tabletop.example.com can send from tabletop@example.com.

Check your provider's documentation for SMTP access requirements. It may require a dedicated app password or SMTP credential instead of your normal account password, and SMTP access may depend on your account plan. Where supported, create a dedicated credential for Open Tabletop with only the access needed to send mail, and store its password in the configured password file.

Configure the provider's sender/domain verification and DNS requirements with that provider. Test actual delivery, spam-folder placement and expired links before relying on email recovery.

Delivery and recovery smoke test

  1. Sign in and open Account security, then request verification for the displayed email address.
  2. Open the received link in the same signed-in browser and select Continue. The account should now show a verified recovery email. Existing addresses are not automatically verified.
  3. In a signed-out browser, select Recover account / reset password, enter that verified email, and follow the emailed link. Existing password accounts must choose and confirm a new password; passwordless accounts may remain passwordless. Both retain the same account identity.
  4. Confirm the old sessions no longer work and save a new set of recovery codes after recovery.

Email links expire after 30 minutes and work once. Allow at least 60 seconds between email requests. The public recovery form deliberately returns the same response for unknown/unverified addresses; a success message alone does not confirm delivery. If email is unavailable, check that SMTP_HOST reached the app process. For failed delivery, check outbound network access, the sender address, the app-password permissions and spam folders. Server logs show a generic [recovery-mail] delivery failed message; provider delivery logs may offer more detail. Never disable TLS certificate checks.

Native services and release versions

For the Linux or Proxmox installer, edit /etc/open-tabletop/open-tabletop.env, place the SMTP password in a file readable by open-tabletop, then run sudo systemctl restart open-tabletop. The systemd service does not load a project .env.

The account-recovery code and migration 023 are under Unreleased in this checkout. The pinned 0.20.0 image does not gain recovery from environment variables alone; deploy an application revision that includes the feature. Normal automatic migration applies 023 when the owner connection is configured.

For Linux Compose file secrets, ensure the app's UID 100/GID 101 can read the SMTP file too; see secret-file permissions. Merge the SMTP override with any existing override instead of duplicating services or environment keys.

Sources checked: docs/ACCOUNT_SECURITY.md, server/recovery-mail.js, docker-compose.yml. Reviewed September 29, 2026 against the working source. Published releases may differ; check the changelog for your version.