Skip to main content

The documentation here is for an unreleased version of Recyclarr.

Visit the documentation site for the Current Version instead.

Client and Server

Recyclarr has two programs:

  • The server (recyclarr-server) does the work. It reads your configuration, talks to Sonarr and Radarr, runs syncs, and sends notifications.
  • The CLI (recyclarr) is a client. Each command sends a request to a server and shows the result. Other programs can send the same requests through the HTTP API.

The server reads your YAML configuration and settings.yml when it starts. If either is not valid, the server does not start. Restart the server after you change them.

A persistent server also updates guide data while it runs. When an update brings new guide data, the server reads your YAML configuration files again, so an edit you have not restarted for can take effect at that point. Restart the server to apply your edits right away.

Persistent Server​

A persistent server keeps running until you stop it. The Docker image runs one, and recyclarr serve starts one on your own machine.

A persistent server:

A persistent server needs an API key and does not start without one.

For CLI commands to use a persistent server, set server.base_url in cli.yml or set the RECYCLARR_SERVER_URL environment variable. The Docker image sets the variable for you.

Temporary Server​

If no server address is set, each CLI command starts its own temporary server. The temporary server listens only on the local machine, handles that one command, and stops when the command ends. It does not run the built-in schedule, opens no management port, and does not keep its jobs after it stops. It writes log files to logs/server/ in the data directory and sends notifications. It downloads guide data only when its cached copy is out of date, so most commands start without network access.

This is the default when you run recyclarr outside Docker without any extra setup. You do not need to set an API key: the CLI creates a new one-time key for each command and gives it to the temporary server.

Server API Key​

Every request to the server's API (any path under /api) must include the server API key. This keeps other programs on your network, or other users on your machine, from starting syncs or deleting custom formats in your Sonarr and Radarr instances. The API reference pages need no key. Health probes and metrics need no key either, but they are on the separate management port, not the API port.

Setting the Key​

The server reads its key from one of two environment variables, never from settings.yml:

Set only one of them. The server logs a fatal error and exits with a non-zero exit code when neither is set, when both are set, when it cannot read the key file, or when the key is shorter than 32 characters. This applies to recyclarr serve, the Docker image, and any other way you run a persistent server.

Use a long random value, for example:

openssl rand -hex 32

The server reads the key file again on every request, so you can rotate the key by replacing the file's contents without a restart. If the file later becomes unreadable or holds a key that is too short, the server rejects every request and logs the cause.

Sending the Key​

  • The CLI sends the key from server.api_key in cli.yml, or from RECYCLARR_API_KEY or RECYCLARR_API_KEY_FILE when either is set. Inside the Docker container, the CLI reads the same variables as the server, so docker exec commands need no extra setup.

  • Other HTTP clients send the key as a bearer token in the Authorization header:

    curl -H "Authorization: Bearer $RECYCLARR_API_KEY" http://localhost:7982/api/v1/sync/jobs

When the key is missing or wrong, the server responds with 401 Unauthorized, a WWW-Authenticate: Bearer header, and a Problem Details body. The CLI shows this message:

The Recyclarr server rejected the request: missing or wrong API key. Set server.api_key in cli.yml, or the RECYCLARR_API_KEY or RECYCLARR_API_KEY_FILE environment variable, to the key the server uses.

Kubernetes​

Store the key in a Secret, created by hand or by a tool such as External Secrets Operator, and map it to RECYCLARR_API_KEY in the container:

containers:
- name: recyclarr
image: ghcr.io/recyclarr/recyclarr:9
env:
- name: RECYCLARR_API_KEY
valueFrom:
secretKeyRef:
name: recyclarr
key: api-key

To rotate the key without restarting the pod, mount the Secret as a volume instead and point RECYCLARR_API_KEY_FILE at the file. Kubernetes updates the mounted file when the Secret changes (this does not work with subPath mounts):

containers:
- name: recyclarr
image: ghcr.io/recyclarr/recyclarr:9
env:
- name: RECYCLARR_API_KEY_FILE
value: /run/secrets/recyclarr/api-key
volumeMounts:
- name: api-key
mountPath: /run/secrets/recyclarr
readOnly: true
volumes:
- name: api-key
secret:
secretName: recyclarr

For ports, health probes, and telemetry, see the Kubernetes example.

Network Security​

The server serves plain HTTP and has no TLS settings. The API key travels unencrypted between a client and the server, and the management port needs no key at all. Decide which clients can reach each port, and add TLS where traffic crosses a network you do not trust.

  • TLS: Terminate TLS in front of the server with a reverse proxy, a tunnel, a Kubernetes Ingress, or a service mesh. Plain HTTP between that proxy and the server is fine on a network you trust.
  • API port: Publish it only to the clients that need it. CLI commands run with docker exec reach the server inside the container, so they need no published port at all.
  • Management port: It listens on the same address as the API port. In Docker, publish it only if something outside the container scrapes metrics or probes health. In Kubernetes, probes and Prometheus reach it on the pod IP, so restrict it with a NetworkPolicy.

To publish the API port only on the Docker host itself, bind it to the loopback address:

services:
recyclarr:
ports:
- 127.0.0.1:7982:7982

This NetworkPolicy lets only pods in a monitoring namespace reach the management port, while the API port stays open to the rest of the cluster. Health probes still work, because a NetworkPolicy always allows traffic from the pod's own node, where the kubelet runs. Adjust the selectors to your cluster:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: recyclarr
spec:
podSelector:
matchLabels:
app: recyclarr
policyTypes:
- Ingress
ingress:
- ports:
- port: 7982
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- port: 7983

API Reference​

Each server describes its own API on the same address and port as the API itself, so the description always matches the version you run:

  • /scalar is an interactive reference page where you can browse operations and try requests.
  • /openapi/v1.json is the OpenAPI document, for tools that generate clients or import an API.

Both paths are open without the API key. Requests you send from the /scalar page go to /api, so enter the key there before you try them. This site also has the reference under HTTP API.

Sync Jobs​

Every sync runs as a job, whether the schedule, the CLI, or the API started it. The server runs one job at a time, oldest first. Other jobs wait in a queue.

Each job has one of these statuses:

StatusMeaning
pendingWaiting in the queue
runningSyncing now
succeededThe sync finished without errors
partialThe sync finished, but some changes failed
failedThe sync failed
interruptedThe server stopped while the job was pending or running
skippedA scheduled sync was not started because another job was already active

A persistent server keeps the 50 most recent finished jobs and their results, including across restarts. When the server starts, it marks jobs that were active at shutdown as interrupted. It does not run them again.