TrayPage Docs

Security notes

What to take care of when self-hosting. Why the viewer host is separate, and how to handle the fact that anyone can currently sign up.

When you self-host, you are responsible for the security configuration. Pay particular attention to these two points.

Keep the viewer host separate

Page content in TrayPage is arbitrary HTML written by users and AI agents, and it can include scripts. If that HTML were served from the same host (origin) as the app, scripts in a page could reach the app's cookies and sessions.

So TrayPage shows page content from a viewer host that is separate from the app, inside a sandboxed iframe with restricted permissions. In every setup, prepare two host names (domains).

SettingExample
APP_ORIGINhttps://traypage.example.com
VIEWER_ORIGINhttps://view.traypage.example.com

What to follow:

  • Use different host names for the two. If possible, use a separate domain, which also keeps the viewer out of the app's cookie scope.
  • The viewer host only returns shared page content. If you see the app's UI on the viewer host, the configuration is wrong.
  • On Cloudflare, set workers_dev to false once you have custom domains. If the workers.dev URL remains, it can be used to bypass the separation of the viewer host.
  • While no viewer host is configured (for example right after the first Cloudflare deploy), page content is served from the same host as the app. Configure it before you actually start using TrayPage.

Anyone can sign up

In the current version, anyone who can receive an emailed sign-in link can create an account. There is not yet a feature to restrict who can sign up (one is planned for a future version).

If you put TrayPage on the public internet, be aware that strangers can create accounts and workspaces. If you use it only inside your organization, restrict who can reach it:

  • Docker / VPS: limit traffic to the server to your organization with a firewall or VPN
  • Cloudflare: limit access to the app domain with something like Cloudflare Access

If you share pages with people outside your organization, though, the viewer host and the shared page URLs must be reachable from outside. Be careful about what you restrict.

Other things to check

  • Make BETTER_AUTH_SECRET and VIEWER_TICKET_SECRET long, unguessable, and different from each other. Do not commit them to a repository (use secrets on Cloudflare, and .env on Docker, which should not be under version control).
  • Keep backups of .env and any secrets in a safe place.
  • In production, remove the mail catcher (Mailpit) by removing mailpit from COMPOSE_PROFILES.
  • Update regularly (Docker / VPS, Cloudflare).