Guardian is an access-control layer for Plex Media Server. It polls the Plex sessions API, matches each stream against per-user and per-device policy, and terminates the sessions that fail.
Warning
Looking for a maintainer. Reach out on Discord or in Discussions.
Do not expose Guardian directly to the internet. Run it on a LAN, behind a VPN, or behind a reverse proxy with SSO.
| Area | Capabilities |
|---|---|
| Access control | Approve, reject or hold devices; global default plus per-user overrides; LAN/WAN and CIDR allowlists over IPv4 and IPv6; weekly time schedules; time-limited temporary grants |
| Limits | Global and per-user concurrent stream caps, with an option to exclude devices on a temporary grant |
| Monitoring | Live Plex and Plexamp sessions, device fingerprints, stream quality and progress, searchable session history |
| Notifications | SMTP email, Apprise (100+ services) and in-app alerts for new devices, blocks, location changes and user notes |
| Administration | Settings export/import, automatic cleanup of inactive devices, CLI recovery scripts |
| User portal | Plex users sign in to see their own devices, the policies that apply to them, and to leave notes on rejected devices |
- A reachable Plex Media Server and a Plex authentication token
- Docker with Compose, or Node.js to run from source
mkdir -p guardian && cd guardian
curl -o docker-compose.yml https://raw.githubusercontent.com/HydroshieldMKII/Guardian/main/docker-compose.example.yml
docker compose up -dThe web UI listens on port 3000 by default
git clone https://github.com/HydroshieldMKII/Guardian.git
cd Guardian
docker compose -f docker-compose.dev.yml up -d --buildUnder Docker → Compose, create a stack from docker-compose.example.yml, adjust the volume and port, and deploy.
| Variable | Default | Purpose |
|---|---|---|
TRUST_PROXY_HOPS |
1 |
Number of proxies in front of Guardian. Determines which address in X-Forwarded-For is treated as the client. |
APP_URL |
unset | Public address Guardian is reached on, for example https://guardian.example.com. Used to build password reset links. Required for password resets; ignored otherwise. |
DATABASE_PATH |
/app/data/plex-guard.db |
SQLite database file. |
Important
Export your settings first: Settings → Admin Tools → Export Settings.
docker compose pull && docker compose up -dLost admin access
docker compose exec guardian node backend/src/scripts/list-admins.js
docker compose exec guardian node backend/src/scripts/update-admin.js "USERNAME" "NEW_PASSWORD"Locked out by captcha
docker compose exec guardian node backend/src/scripts/disable-captcha.jsCannot connect to Plex — check that the server is reachable from the container, the token is valid, and that SSL settings match the server.
Notifications not arriving — use the test buttons in Settings, then check credentials and spam filtering.
Reset emails not arriving — confirm SMTP works with the test button, confirm APP_URL is set, and confirm the admin account has an email address.
Otherwise, ask on Discord or open an issue.
cd backend && npm ci && npm run start:dev # port 3001
cd frontend && npm ci && npm run dev # port 3000Run before opening a pull request:
(cd backend && npm run lint:ci && npm run typecheck && npm run test:cov && npm run build)
(cd frontend && npm run typecheck && npm run test:cov && npm run build)Open an issue with the bug or feature template, or a pull request with the checklist filled in. Report security issues through a private advisory, not a public issue.
Released under the PolyForm Noncommercial License 1.0.0. Fork it, change it and share it for any noncommercial purpose, keeping the copyright notice with it. Commercial use is not covered. The software comes with no warranty.








