Prerequisites
You need Docker and Docker Compose installed on your server. Any Linux distribution with Docker CE works. Bazarr+ also runs on macOS and Windows via Docker Desktop, though Linux is recommended for production.
That is the whole requirement, because there are two ways to run Bazarr+. You can connect Sonarr, Radarr or Sportarr and have it fetch subtitles for the library you already have, or you can run it with no library at all and search any film or show by name. Both start from the same install below. If you do run a media stack, keep its host, port and API key to hand for the connection step.
One-liner install
The fastest way to get running. This script creates a directory (default: ./bazarr-plus), writes a docker-compose.yml, and starts the containers.
curl -fsSL https://lavx.github.io/bazarr/install.sh | bash
The script asks for optional movie, TV and sports folders, and whether to add FlareSolverr or the AI translator. It detects your timezone and user/group IDs automatically. Leave all media paths empty and skip library connections for standalone Discover. Connect Sonarr, Radarr or Sportarr later under Settings > Connections. You can review the script before running it.
Docker Compose setup
For a minimal standalone install, use the homepage Compose example. The example below includes FlareSolverr and the AI translator; remove either service if you do not need it. Uncomment only the movie, TV or sports mounts you use and replace their host paths. Standalone Discover needs only /config.
services:
bazarr:
image: ghcr.io/lavx/bazarr:latest
container_name: bazarr
restart: unless-stopped
ports:
- 6767:6767
environment:
- PUID=1000
- PGID=1000
- TZ=UTC
volumes:
- ./config:/config
# Optional: uncomment only the media folders you use.
# - /path/to/movies:/movies
# - /path/to/tv:/tv
# - /path/to/sports:/sports
read_only: true
tmpfs:
- /tmp:size=512m
cap_drop:
- ALL
cap_add:
- CHOWN
- SETUID
- SETGID
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD-SHELL", "port=$$(cat /tmp/bazarr-supervisor.port 2>/dev/null || echo 6767); case \"$$port\" in \"\"|*[!0-9]*) exit 1 ;; esac; curl -sf \"http://localhost:$$port/_supervisor/status\" | grep -q '\"running\"'"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
# Recommended for the OpenSubtitles.org Provider Hub plugin: solves
# Cloudflare browser challenges when the in-process scraper is itself
# challenged. Set this container's /v1 URL in the plugin's FlareSolverr URL.
flaresolverr:
image: ghcr.io/flaresolverr/flaresolverr:latest
container_name: flaresolverr
restart: unless-stopped
environment:
- LOG_LEVEL=info
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:8191/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# AI translation via OpenRouter (free tiers available)
# Configure the API key in Settings > AI Translator
ai-subtitle-translator:
image: ghcr.io/lavx/ai-subtitle-translator:latest
container_name: ai-subtitle-translator
restart: unless-stopped
ports:
- 8765:8765
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:8765/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
Then start it:
docker compose up -d
ports mapping has to match it, for example 6868:6868. Two instances that share a network, with network_mode: host or behind one VPN container, each need a port of their own.
Container hardening
The hardening keys above (read_only, tmpfs, cap_drop, cap_add, security_opt) are what the image is built for. Bazarr+ owns its application tree as root and writes everything at runtime under /config, so freezing the rest of the filesystem costs nothing and keeps a provider plugin's worker process from rewriting the code Bazarr+ imports on its next restart. The /tmp tmpfs is what gives back the one writable path outside /config that is still needed: subtitle bundle downloads spill into it once they outgrow their in-memory buffer, the Provider Hub and sports workers put their per-request temporary directories there, and the alass shim falls back to it when the config cache cannot hold an executable. Extraction and the sync engines do not need it, they already work under /config/cache and beside the destination file. Keep the size= cap: an uncapped tmpfs may grow to half of host RAM, and it is charged to the host rather than to the container.
The three capabilities added back are the ones the startup needs while it is still root: CHOWN to hand /config to your PUID:PGID, and SETUID and SETGID to become that user. Bazarr+ itself, and every Provider Hub worker it starts, runs afterwards with no capabilities at all.
If you run the container with plain docker run instead of Compose, the same settings are:
docker run -d \
--name bazarr \
--read-only \
--tmpfs /tmp:size=512m \
--cap-drop ALL \
--cap-add CHOWN --cap-add SETUID --cap-add SETGID \
--security-opt no-new-privileges:true \
-p 6767:6767 \
-e PUID=1000 -e PGID=1000 -e TZ=UTC \
-v ./config:/config \
-v /path/to/movies:/movies \
-v /path/to/tv:/tv \
-v /path/to/sports:/sports \
ghcr.io/lavx/bazarr:latest
Drop any -v /path/to/... line for a folder you do not use: Docker creates a host folder a mount names and does not find, so a copied line invents one on your host.
/app/bazarr needs a writable filesystem, so drop read_only (or --read-only) for that container. Keep the rest.
/v1 URL (e.g. http://flaresolverr:8191/v1) in the plugin's FlareSolverr URL setting so it can solve Cloudflare challenges when needed. If you run Bazarr+ with host networking (network_mode: host), the flaresolverr hostname stops resolving: use http://localhost:8191/v1 and make port 8191 reachable on the host, either by adding a 8191:8191 ports mapping to the FlareSolverr service above or running it with host networking too.
First login
Open http://localhost:6767 in your browser. On a fresh install, a guided setup wizard opens automatically. The first thing it asks is what you want Bazarr+ to do: connect the Sonarr, Radarr or Sportarr library you already have, or run on its own with no library. That answer decides which steps it walks you through, so it never asks you for a service you do not run. Installing providers needs a restart to load them; the wizard handles that and resumes where you left off. You can leave it at any time with Set up later and configure everything from Settings instead. It does not come back on its own after that; Settings > General > Run first-time setup starts it again from the beginning.
Whichever path you take, these are the settings that matter:
- Set a password. Bazarr+ uses PBKDF2 with 600k iterations, a significant upgrade from upstream's MD5 hashing. Pick something strong.
- Choose your languages. Select the subtitle languages you want Bazarr+ to search for. You can set defaults per profile or override per series/movie later.
- Add subtitle providers. Enable built-in providers under Subtitle Hub > My Providers. You can also install providers from the Provider Hub Marketplace, which serves a versioned catalog of provider plugins. A catalog plugin can reuse a built-in id and replace the shipped provider, so the two collapse into a single card.
- Set provider priority. Use Subtitle Hub > My Providers to order providers. Bazarr+ can try them in priority order and stop early once it finds a match, saving time and API calls.
Running with no library
Bazarr+ does not need Sonarr, Radarr or Sportarr to be useful. Since v2.7.0 it opens on Discover, which works on its own: type a film or show by name, or browse what is trending, what has reached digital and what aired recently, then pick a title, search the providers, preview the subtitle and download the one you want. Nothing has to be indexed first, and there is nothing to sign up for.
Discover authenticates with a metadata key the application carries, so a fresh install can search the moment it is up. If you would rather supply your own, store a TMDB key under Subtitle Hub > My Providers > TMDB.
To run this way, take the Discover path when the wizard asks at first login and connect nothing. The languages and providers from that same wizard are all Discover needs. The Provider Hub and Subtitle Processing guides apply unchanged, and the section below is for readers who do have a library. More on what Discover is and does is on the home page.
Connecting Sonarr, Radarr or Sportarr
Go to Settings > Connections, choose Sonarr, Radarr or Sportarr, and add an instance with:
- Host and port of the instance, for example
192.168.1.10:8989 - API key, found in that application's settings
- Base URL, only needed when the application sits behind a reverse proxy with a path prefix
Click Test to verify the connection, then Save. Bazarr+ will sync that instance and start searching for missing subtitles on the next scheduled scan.
sonarr instead of an IP address. This avoids issues when IP addresses change.
Next steps
- Run Bazarr+ with no library: how Discover searches any film or show on its own, and how to supply your own metadata key
- Install Provider Hub plugins from the official catalog source
- Process subtitles with combined bilingual output, embedded-track scoring, and multi-engine sync
- Serve subtitles to other apps with the Distribution Hub multi-tenant API and named keys
- Set up AI translation to translate subtitles into any language using OpenRouter models
- Migrating from upstream? Your existing config and database carry over