Entire site was built using Codex, Opus and Gemini. Using it daily, I havenβt found any issues in functionality so far, but Iβll update the README if I come across any bugs that Iβm unable to fix. The UI is mobile-first, as I needed an Iphone app to control radarr, sonarr and qbittorrent with push notifications. I have only added features which I wanted to use myself to use from mobile, not all the options and features present in arr stack and qbittorrent is added. UI may not be the best, but I have opted for functionality and cramped as much info as possible in the dashboard and activity feed pages, so that I can get all the info at a glance on mobile.
Helprr is a self-hosted web dashboard (PWA) that connects to Sonarr, Radarr, Prowlarr, Jellyfin, TMDb, AniList and qBittorrent.
It polls those services on an interval and can send Web Push notifications for common events (downloads starting/completing/failing, health warnings, upcoming releases, etc.) with per-device notification preferences. Provides pages to discover new content using TMDb and AniList APIs, and add it to Sonarr/Radarr. The UI is password-protected with per-user accounts (an initial admin is seeded from APP_PASSWORD on first run; admins manage additional users in-app), and the app can be used on mobile as PWA for push notifications or desktop or just in browser.
End Goal: A simple, mobile-friendly app to monitor and control your media server with push notifications, without needing to pay subscriptions for mobile apps.
- Password-protected UI with per-user accounts (initial admin seeded from
APP_PASSWORD; admins manage other users in-app) - Connect/configure Sonarr, Radarr, qBittorrent from Settings
- Dashboard + Activity feed + Calendar views
- Notifications inbox + per-device notification preferences
- PWA service worker (Serwist in production; lightweight push-only worker in development)
- Next.js (App Router) on port 3050
- Prisma + PostgreSQL
- Web Push (
web-push) with VAPID keys
- Node.js 20+
- PostgreSQL 16+ (or Docker)
- Redis 7+ (or Docker)
Copy .env.example to .env.local (for local dev), or set these in your deployment environment:
| Variable | Required | Purpose |
|---|---|---|
DATABASE_URL |
yes | PostgreSQL connection string used by Prisma |
REDIS_URL |
yes | Redis connection string used for caching and login rate limiting β getRedisClient() throws if unset |
REDIS_PASSWORD |
yes | Redis AUTH password (sets --requirepass in docker-compose, sent as the client AUTH password) β getRedisClient() throws if unset |
APP_PASSWORD |
yes | Seeds the bootstrap admin password on first boot (not checked at login afterward β login verifies the per-user hash in the DB) |
JWT_SECRET |
yes | Signs the auth cookie β getJwtSecret() throws if unset, so the app will not serve authenticated requests without it |
HELPRR_ADMIN_USERNAME |
optional | Bootstrap admin login username (default admin) |
HELPRR_ADMIN_PASSWORD_RESET |
optional | Set true to force-reset the admin password from APP_PASSWORD on next boot (recovery); remove it afterward |
NEXT_PUBLIC_VAPID_PUBLIC_KEY |
optional | Public VAPID key (enables push notifications; must be available at build time for Docker builds) |
VAPID_PRIVATE_KEY |
optional | Private VAPID key (server-side) |
VAPID_SUBJECT |
optional | VAPID subject, e.g. mailto:you@example.com |
TZ |
optional | Timezone for displaying dates/times (defaults to UTC) |
DATABASE_URL, REDIS_URL, REDIS_PASSWORD, APP_PASSWORD, and JWT_SECRET are all required for startup β the app throws on boot (or on the first request that touches Redis/auth) if any are missing. Note that APP_PASSWORD only seeds the bootstrap admin on first boot; it is not used as a live login password.
If VAPID vars are not set, Helprr will still run, but push notifications are disabled.
- Install dependencies
npm ci- Start PostgreSQL and Redis (example using docker-compose)
docker compose up -d helprr-db helprr-redis- Configure
.env.local
Example (adjust credentials/host to match your Postgres setup):
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/helprr
REDIS_URL=redis://localhost:6379
REDIS_PASSWORD=change-me-redis
APP_PASSWORD=change-me
JWT_SECRET=change-me-too
TZ=Asia/Kolkata
# Optional: enable push notifications
VAPID_SUBJECT=mailto:you@example.com
NEXT_PUBLIC_VAPID_PUBLIC_KEY=...
VAPID_PRIVATE_KEY=...- Initialize the database schema
npm run db:generate
npm run db:push- Run the dev server
npm run devThe repository includes a docker-compose.yml with a Postgres container and the Helprr app.
- Set environment variables (recommended via a local
.envfile that is not committed)
POSTGRES_PASSWORD(optional override; defaults topostgres)DATABASE_URL(optional override; defaults to the internal compose URL)REDIS_URL(optional override; defaults toredis://helprr-redis:6379)REDIS_PASSWORD(required; sets the Redis--requirepasspassword and the client AUTH password β the app fails to start without it)APP_PASSWORD(seeds the bootstrap admin password on first boot)JWT_SECRET(required; signs the auth cookie β the app fails to start without it)HELPRR_ADMIN_USERNAME(optional; bootstrap admin login username, defaultadmin)HELPRR_ADMIN_PASSWORD_RESET(optional; settrueto force-reset the admin password fromAPP_PASSWORD, then remove)TZ(optional override; defaults toUTC)NEXT_PUBLIC_VAPID_PUBLIC_KEY(build-time)VAPID_PRIVATE_KEYVAPID_SUBJECT
- Build and run
docker compose up --buildNotes:
- The image build expects
NEXT_PUBLIC_VAPID_PUBLIC_KEYto be available as a build arg. - The container entrypoint runs
npx prisma db push --skip-generatebefore starting Next.js.
You can generate a VAPID keypair with:
npx web-push generate-vapid-keysUse the public key as NEXT_PUBLIC_VAPID_PUBLIC_KEY and the private key as VAPID_PRIVATE_KEY.
In the app, go to Settings and set:
- Sonarr: base URL + API key
- Radarr: base URL + API key
- qBittorrent: base URL + password (stored as the connection
apiKey) + optional username (defaults toadmin)
Helprrβs polling service will skip any service that is not configured.
npm run dev
npm run build
npm run start
npm run db:generate
npm run db:push
npm run db:migrate
npm run lint- Set strong values for
APP_PASSWORDandJWT_SECRETin production. - Passwords are stored as per-user scrypt hashes in the database; login checks the hash, not
APP_PASSWORD.APP_PASSWORDonly seeds the first admin account on initial boot β changing it later and restarting does nothing on its own. - Lost or compromised admin password? Set
HELPRR_ADMIN_PASSWORD_RESET=true(alongside the desiredAPP_PASSWORD) and restart to re-hash the admin password, then remove the flag (otherwise every reboot re-appliesAPP_PASSWORD). This resets only the bootstrap admin β admins change other users' passwords in-app (Settings β Users). - A password reset does not sign out existing sessions. To lock out someone who already has a session, also revoke sessions in Settings β Sessions (and/or disable the account).











