Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ hide:
---

:::danger
:fire: :fire: The API, and all of Maintainerr for that matter, does not have an authentication method. There are certain API calls, that if you make your instance public facing, will expose your entire settings configuration. This could include all of your service's API keys. Proceed with extreme caution if you choose to expose Maintainerr to the public. See the [Security & Authentication](/security) page for guidance on protecting your instance. :fire: :fire:
:fire: :fire: The API, and all of Maintainerr for that matter, does not have an authentication method. There are certain API calls, that if you make your instance public facing, will expose your entire settings configuration. This could include all of your service's API keys. Proceed with extreme caution if you choose to expose Maintainerr to the public. See the [Security & Authentication](./Security.md) page for guidance on protecting your instance. :fire: :fire:

:::

Expand Down
24 changes: 9 additions & 15 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,8 @@ All configuration is done inside the application. No extra config files are requ

When you first access the web UI, you should be redirected to the settings page. If that does not happen, try refreshing the page.

:::note
All Base URL settings are to be entered without the leading slash.

- Right: `tautulli`
- Wrong: `/tautulli`

:::

:::info Exposing Maintainerr to the internet
Maintainerr has no built-in login, so anyone who can reach it can read the credentials you enter below. Running it locally or reaching it over a VPN is fine and needs nothing extra. Only if you plan to put it directly on the internet, add an authenticating reverse proxy in front first - see [Security & Authentication](/security).
Maintainerr has no built-in login, so anyone who can reach it can read the credentials you enter below. Running it locally or reaching it over a VPN is fine and needs nothing extra. Only if you plan to put it directly on the internet, add an authenticating reverse proxy in front first - see [Security & Authentication](./Security.md).
:::

## General
Expand All @@ -44,7 +36,7 @@ Maintainerr's normal Plex setup uses Plex authentication and server discovery in

After you authenticate with a Plex **admin** account, Maintainerr validates the token, loads the servers available to that account, and lets you choose from discovered connection candidates. This is the recommended setup because Maintainerr can use the discovered server details directly and keep automatic reconnection behavior enabled.

:::tip
:::note
Proper DNS is preferred. Plex discovery and failover can depend on resolvable Plex endpoints, and Docker users in particular may run into intermittent connection or discovery problems when container DNS is unstable. If possible, make sure your environment has working DNS resolution for Plex-related hostnames and service names.
:::

Expand All @@ -54,9 +46,7 @@ Proper DNS is preferred. Plex discovery and failover can depend on resolvable Pl
| Server | Shows the currently selected discovered server, or lets you choose one from the discovered server list. |
| Refresh icon | Re-runs Plex server discovery for the authenticated account. Use this if the server list is stale or discovery failed the first time. |

:::tip
`Test Connection` is disabled until you are authenticated and have either selected a discovered server or enabled manual override with saved settings.
:::
`Test Connection` stays disabled until you are authenticated and have either selected a discovered server or enabled manual override with saved settings.

<details>
<summary>Server list is empty (VPS, cloud host, or custom networking)</summary>
Expand All @@ -71,7 +61,7 @@ Fix it on the Plex side by publishing a reachable address:

Back in Maintainerr, press the **Refresh icon** next to the server selector; the server appears in the list.

:::tip
:::note
If Maintainerr and Plex share a Docker network, you can instead skip discovery and point Maintainerr at Plex's **internal** address (e.g. `http://plex:32400`) with manual connection override below.
:::

Expand Down Expand Up @@ -139,6 +129,10 @@ Seerr configuration is required if you want to use Seerr-related rule parameters

Radarr's configuration is required to use its parameters in rules and to remove or unmonitor movies.

:::note
Enter the `Base URL` for Radarr and Sonarr without a leading slash - `radarr`, not `/radarr`.
:::

| Setting | Description |
| -------------- | -------------------------------------------------------------- |
| Server Name | A friendly name to help identify the server |
Expand Down Expand Up @@ -220,7 +214,7 @@ How it works:
- Removal is best-effort: a failure to reach the download client never blocks the Radarr/Sonarr deletion itself, so treat it as cleanup assistance rather than guaranteed download-client reconciliation. For more advanced usage; look elsewhere.
- `Test Connection` verifies the URL and credentials against the qBittorrent Web UI before saving.

:::tip Troubleshooting: "403 Forbidden" after a successful login
:::note Troubleshooting: "403 Forbidden" after a successful login
A `403 Forbidden` on the connection test (or in the logs) means qBittorrent accepted the credentials but its Web UI security then blocked the request — it is **not** a wrong username/password. The usual cause is that Maintainerr and qBittorrent run on different IPs (e.g. separate Docker containers). In qBittorrent go to **Options → Web UI → Security** and add Maintainerr's IP or subnet to **"Bypass authentication for clients in whitelisted IP subnets"**. A reverse proxy or host-header validation can also cause it.
:::

Expand Down
17 changes: 9 additions & 8 deletions docs/Installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -293,14 +293,15 @@ services:

A list of all available environment variables are below. No other env variables are officially supported by Maintainerr. These are added either into the compose file or your docker run command.

| Variable | Default Value | Description |
| ------------ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TZ | _host timezone_ | Controls date formatting in logs. |
| UI_HOSTNAME | 0.0.0.0 | The listen host of the web server. Can be set to :: for IPv6. |
| UI_PORT | 6246 | The listen port of the web server. |
| BASE_PATH | | If reverse proxying with a subfolder you'll want to set this. Must be in the format of `/subfolder`. |
| LOG_LEVEL | info | Overrides the persisted log level for the current container process only. Accepted values are `debug`, `verbose`, `info`, `warn`, `error`, and `fatal`. |
| GITHUB_TOKEN | | GitHub Personal Access Token for higher API rate limits |
| Variable | Default Value | Description |
| -------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TZ | _host timezone_ | Controls date formatting in logs. |
| UI_HOSTNAME | 0.0.0.0 | The listen host of the web server. Can be set to :: for IPv6. |
| UI_PORT | 6246 | The listen port of the web server. |
| BASE_PATH | | If reverse proxying with a subfolder you'll want to set this. Must be in the format of `/subfolder`. |
| LOG_LEVEL | info | Overrides the persisted log level for the current container process only. Accepted values are `debug`, `verbose`, `info`, `warn`, `error`, and `fatal`. |
| GITHUB_TOKEN | | GitHub Personal Access Token for higher API rate limits |
| CORS_ALLOWED_ORIGINS | | Comma-separated list of origins allowed to call the API cross-origin, e.g. `https://maintainerr.example.com`. Same-origin access (the bundled UI, including via localhost) always works and never needs this; only set it if a separate front end on a different origin calls the API. |

:::tip
If `BASE_PATH` is set, remember to prefix health-check probe paths accordingly (for example `/maintainerr/api/health/ready`).
Expand Down
5 changes: 3 additions & 2 deletions docs/Security.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ Maintainerr is built to keep your data on your own hardware and to be careful wi
- **Everything stays local.** All configuration and state lives in a single SQLite database in your data directory (`/opt/data`). There is no cloud component, no telemetry, and no analytics - Maintainerr never phones home. The only outbound traffic goes to the services you configure (your media server, the \*arrs, Seerr, and so on) and to the metadata providers (TMDB/TVDB) used to match your library.
- **Outbound connections use verified TLS.** Calls to your services and to metadata providers use HTTPS with normal certificate verification, which the app never disables on its own. Notification email can use TLS and can optionally be PGP-encrypted.
- **Secrets are kept out of the logs.** Every log line passes through a sanitizer that masks API keys, tokens, `Authorization` headers, and credential-bearing URLs, so secrets do not leak into log files or error dumps.
- **The rules engine cannot run code or shell out.** Rules are evaluated by a typed comparator, never `eval`-ed. Database access is fully parameterized, so there is no SQL-injection surface, and the server runs no shell commands.
- **The rules engine cannot run code or shell out.** Rules are evaluated by a typed comparator, never `eval`-ed. Database access is fully parameterized, so there is no SQL-injection surface, and the server runs no shell commands. Settings you submit are schema-validated before they are saved.
- **Cross-origin access is locked down.** In production the API sends no CORS headers by default, so another website cannot read it from your browser. If you serve a separate front end from a different origin, allow it explicitly with `CORS_ALLOWED_ORIGINS`.
- **Destructive actions are deliberately conservative.** Deletes are tied to explicit collection and rule actions, and the folder-cleanup path is fail-closed: it refuses unexpected paths, rejects symlinks and `..` traversal, canonicalizes with `realpath`, and only removes a folder once it has proven the folder is empty and safely inside the intended directory.
- **Non-root, pinned container image.** The official image runs as a non-root user, is built in multiple stages from a digest-pinned base, and pins security-sensitive dependencies.
- **The container is hardened.** The official image runs as a non-root user with least-privilege file permissions, is built in multiple stages from a digest-pinned base, and pins security-sensitive dependencies.

**One important caveat:** the credentials you enter (Plex token, \*arr and Seerr keys, qBittorrent and SMTP passwords, notifier tokens) are stored **unencrypted** in that SQLite database - Maintainerr does not encrypt data at rest. So the database file, and any backup of it, is as sensitive as the credentials it holds: keep the data directory private, restrict its permissions, and encrypt your backups. And because Maintainerr has no login of its own, none of this replaces putting it behind an authenticating reverse proxy when you expose it (the rest of this page).

Expand Down