Repository navigation
Security Notes
A few things are already in place for running this on the open internet, not just a
LAN/Tailscale: security response headers (CSP, X-Frame-Options, etc.) on every
response, hardened session cookie flags, CSRF protection on every admin action, a
login lockout after 5 failed admin-login attempts (5 min cooldown, applies to 2FA
codes too if enabled), optional two-factor authentication (see the Daily Use / Admin
Panel Guide), generic error pages instead of default framework ones, and
optional ProxyFix support (PORTAL_BEHIND_PROXY) for correct behavior behind a
reverse proxy. None of this replaces putting a real reverse proxy/WAF/TLS in front if
you expose this beyond a VPN - it just means the app itself isn't the weak link.
If you turn on Jellyfin sign-in (Settings → User accounts), be aware of exactly what that does: it publishes a Jellyfin login form wherever this portal is reachable. On a LAN or Tailscale that's fine; on the open internet you are now accepting Jellyfin credentials over whatever transport this portal is served on, so the TLS advice below stops being optional. Passwords are only ever passed straight through to Jellyfin and are never stored, logged, or put in the session cookie — but that doesn't help if the connection itself is plaintext. It's off by default for this reason. Failed sign-ins are rate-limited separately from the admin login, so neither can lock the other out.
If you're considering exposing this beyond a private network (Tailscale/LAN), two things worth doing first:
-
Put a TLS-terminating reverse proxy in front of it. This app has no built-in
HTTPS - exposed raw, your admin password and session cookie would travel in
plaintext on login. Caddy gets you automatic
Let's Encrypt certs with a few lines of config; then set
PORTAL_BEHIND_PROXY=trueandPORTAL_FORCE_HTTPS_COOKIES=true. - Keep the admin panel itself behind something like Tailscale or Cloudflare Access, even if the public status page is reachable by anyone. The admin panel can now restart or shut down the host machine - that's exactly the kind of action worth an extra gate beyond a single password, on top of (not instead of) enabling two-factor authentication.
The external notification API (POST /api/notify/admin, POST /api/notify/user —
see the Daily Use / Admin Panel Guide) is a new
authenticated surface, off in practice until you generate a key on
Notifications → Channels. It's guarded by a single shared secret checked against the
X-Api-Key header, not by the admin session/CSRF mechanism the rest of the panel
uses — deliberately, since it's meant to be called machine-to-machine (currently: the
sibling Games Portal project) rather than from a browser with a cookie. Treat this key
like any other credential: anyone who has it can push a message through whichever
channels you have configured, or queue one for any signed-in visitor. Regenerating it
from the same page invalidates the old value immediately.
These two intervals are independent — don't confuse them: the health checker polls each
service's check_url on its own schedule, unrelated to how often a visitor's browser
reloads the public page.
Also see the auto-update-specific security notes in Updating & Rollback.