Better-PaaS

Security

How Better-PaaS protects your dashboard, your secrets, and your server.

Better-PaaS is built so the secure path is the default path. You don't have to be a security expert to run it safely. This page explains how it protects you and the few things you should do yourself.

The admin token

The entire control plane is protected by a single admin bearer token.

  • On first run, Better-PaaS generates a strong random token, prints it to the logs, and saves it to backend/data/admin_token.txt.
  • You paste it into the dashboard sign-in screen to log in.
  • Every API and WebSocket request must carry it:
    • HTTP: Authorization: Bearer <token>
    • WebSocket: ?token=<token>

To pin or rotate the token, set ADMIN_TOKEN in the backend environment.

Reprint the token any time
cd ~/better-paas/backend && ./server token

Treat the token like a password

Anyone with the token has full control of your Better-PaaS instance. Don't commit it, paste it into chats, or put it in client-side code.

Brute-force protection

Could an attacker just guess the token? No. Repeated bad tokens from an IP trigger an escalating lockout — the server responds with HTTP 429 and a Retry-After header, slowing guesses to a crawl. Combined with a 256-bit token, guessing is infeasible.

If you run Better-PaaS behind a reverse proxy, set TRUST_PROXY=true so the lockout keys on the real client IP instead of the proxy's.

Encryption at rest

Sensitive values are encrypted before they're written to the database using AES-256-GCM:

  • Per-app deploy tokens (gitToken)
  • Your saved GitHub token

The encryption key comes from BETTER_PAAS_SECRET_KEY, or is generated on first run at backend/data/secret.key (mode 0600).

This protects leaked database copies — an accidental commit, a stolen backup, an old snapshot. Existing cleartext values are read transparently and upgraded to ciphertext on the next write.

For stronger protection

By default the key lives next to the database, so encryption at rest doesn't stop an attacker who can already read the entire data directory. For defense against that, supply BETTER_PAAS_SECRET_KEY out-of-band (a secrets manager or systemd credential) and keep it off the host.

Network exposure

By default the API binds to all interfaces so the dashboard is reachable from a remote browser. Because every route requires the admin token, this is safe to start with.

For extra hardening, put Better-PaaS behind a reverse proxy and set LISTEN_ADDR to loopback (127.0.0.1:8080) so the API isn't directly exposed.

The data directory

backend/data/ holds your SQLite database, admin token, encryption key, and logs. It's created with 0700 permissions and is gitignored.

Never commit backend/data/

It contains secrets. It's already in .gitignore — keep it that way.

Your security checklist

A short list of things worth doing on a production instance:

Keep the admin token secret and rotate it if you suspect exposure.

Open only the ports you need on your server's firewall (typically 80, 443, and your SSH port).

Set BETTER_PAAS_SECRET_KEY out-of-band for stronger encryption at rest.

Set TRUST_PROXY=true if you run behind a reverse proxy.

Keep backups off-server so a lost server doesn't mean lost data.

Keep Better-PaaS updated — see Updates.

Next step

On this page