*arr cannot connect
Check that putiorr and the *arr container share a Docker network. Use Host putiorr, Port 9091, and SSL off.
AI agent guide
If a user sent you this page, read it first, inspect their existing Docker Compose stack, collect only the missing inputs, then install and validate putiorr for their Radarr, Sonarr, Lidarr, and Prowlarr setup.
Give this compact brief to an assistant or sub-agent, then let it use the rest of this page for the full setup details.
Read https://ptheofan.github.io/putiorr/agent-setup.html first.
Goal: install putiorr as a Transmission-compatible put.io bridge.
Use Docker Compose with ghcr.io/ptheofan/putiorr:latest.
Mount persistent config at /data/putiorr-config.
Mount the host download target, for example /volume/downloads, as /downloads in putiorr and every *arr container.
Do not configure Remote Path Mapping when paths match.
Use PUTIORR_TARGET_DIR=/downloads and PUTIORR_LISTEN_PORT=9091.
Add PUTIORR_PROFILES_JSON to seed Radarr, Sonarr, and Lidarr profiles on first startup.
Keep putiorr on the same Docker network as Radarr, Sonarr, and Lidarr.
In each *arr app add a Transmission client:
Host putiorr, Port 9091, SSL off, Directory /downloads.
Category radarr/sonarr/lidarr.
URL Base /radarr/transmission, /sonarr/transmission, or /lidarr/transmission.
Connect put.io through the putiorr UI using OAuth or Direct Token.
Validate with each *arr Test button and a small completed grab.
A user can give this URL to Codex or another assistant:
https://ptheofan.github.io/putiorr/agent-setup.html.
Treat this page as the authoritative setup brief for putiorr.
Do the setup with the user, not by guessing their storage or
secrets. The stable defaults are one putiorr service, one
persistent config mount, and one shared download target mounted
at /downloads inside putiorr and every *arr app.
17010:9091 unless the user explicitly wants that host port.putiorr and port 9091.Ask for these values or inspect them from the user's existing Compose files before editing anything.
| Input | Default or example | Why it matters |
|---|---|---|
| Compose project path | docker-compose.yml |
Where the putiorr service and shared network should be added. |
| *arr service names | radarr, sonarr, lidarr |
Confirms which apps need profiles and download-client values. |
| putiorr config host path | /volume1/docker/putiorr-config |
Stores SQLite state and UI-saved put.io credentials. |
| Download target host path | /volume/downloads |
Must be mounted into putiorr and each *arr app at /downloads. |
| Media library host paths | /volume/media/movies, /volume/media/series, /volume/media/music |
Final import locations for Radarr, Sonarr, and Lidarr. |
| put.io auth method | Hosted OAuth relay or Direct Token | Determines whether the user connects through the browser flow or pastes a token in the UI. |
| RPC auth | Unset by default | If set, the same username and password must be entered in each *arr download client. |
Add putiorr beside the existing *arr services, or attach it to the same external Docker network. A published port is optional for browser access and is not required for container-to-container RPC.
services:
putiorr:
image: ghcr.io/ptheofan/putiorr:latest
restart: unless-stopped
environment:
TZ: Europe/Athens
PUTIORR_LISTEN_HOST: 0.0.0.0
PUTIORR_LISTEN_PORT: 9091
PUTIORR_STATE_PATH: /data/putiorr-config/putiorr.sqlite
PUTIORR_TARGET_DIR: /downloads
PUTIORR_PROFILES_JSON: >-
[
{
"name": "Radarr",
"type": "radarr",
"slug": "radarr",
"putio_folder_name": "putiorr",
"downloadAt": "/downloads",
"rpc_path": "/radarr/transmission/rpc",
"enabled": true
},
{
"name": "Sonarr",
"type": "sonarr",
"slug": "sonarr",
"putio_folder_name": "putiorr",
"downloadAt": "/downloads",
"rpc_path": "/sonarr/transmission/rpc",
"enabled": true
},
{
"name": "Lidarr",
"type": "lidarr",
"slug": "lidarr",
"putio_folder_name": "putiorr",
"downloadAt": "/downloads",
"rpc_path": "/lidarr/transmission/rpc",
"enabled": true
}
]
PUTIORR_WORKERS: "4"
PUTIORR_CLEANUP_REMOTE_FILES: "true"
volumes:
- /volume1/docker/putiorr-config:/data/putiorr-config
- /volume/downloads:/downloads
Make sure each importer also has the same download target mount.
The left side may change for the user's host, but the right side
should stay /downloads everywhere.
services:
radarr:
volumes:
- /volume/downloads:/downloads
- /volume/media/movies:/movies
sonarr:
volumes:
- /volume/downloads:/downloads
- /volume/media/series:/series
lidarr:
volumes:
- /volume/downloads:/downloads
- /volume/media/music:/music
Use PUTIORR_PROFILES_JSON to create the initial RR
profiles automatically on first startup, so the user does not have
to create Radarr, Sonarr, and Lidarr profiles in the UI.
>-.putiorr service environment when the container starts.download_profile_id is supplied./downloads. Do not seed host paths such as /volume/downloads into profile downloadAt.PUTIORR_PROFILES_JSON: >-
[
{
"name": "Radarr",
"type": "radarr",
"slug": "radarr",
"putio_folder_name": "putiorr",
"downloadAt": "/downloads",
"rpc_path": "/radarr/transmission/rpc",
"enabled": true
},
{
"name": "Sonarr",
"type": "sonarr",
"slug": "sonarr",
"putio_folder_name": "putiorr",
"downloadAt": "/downloads",
"rpc_path": "/sonarr/transmission/rpc",
"enabled": true
},
{
"name": "Lidarr",
"type": "lidarr",
"slug": "lidarr",
"putio_folder_name": "putiorr",
"downloadAt": "/downloads",
"rpc_path": "/lidarr/transmission/rpc",
"enabled": true
}
]
The profile fields map directly to the startup seed:
name is the UI display name, type and
slug identify the app, putio_folder_name
is the put.io folder, downloadAt is the container
download target, and rpc_path is the endpoint used by
the matching *arr app.
If the user already has a populated SQLite state database, do not
assume changing PUTIORR_PROFILES_JSON will update
existing profiles. Use the UI or the profile API instead.
After the container starts, open the putiorr UI and confirm the seeded RR profiles. If seed JSON was not used, create one profile per importer. The UI's field guide should be used to confirm paths before saving.
| Profile field | Radarr | Sonarr | Lidarr |
|---|---|---|---|
| App preset | Radarr | Sonarr | Lidarr |
| Display name | Radarr | Sonarr | Lidarr |
| Put.io destination folder | putiorr |
putiorr |
putiorr |
| Shared download folder | /downloads |
/downloads |
/downloads |
| RPC endpoint path | /radarr/transmission/rpc |
/sonarr/transmission/rpc |
/lidarr/transmission/rpc |
| Host from *arr container | putiorr |
putiorr |
putiorr |
| Port | 9091 |
9091 |
9091 |
Link each RR profile to a download profile after creating custom download profiles. The default download profile is acceptable for a first setup.
Add a Transmission download client in Radarr, Sonarr, and Lidarr.
The Name can be putiorr; the Host is the Docker
service name putiorr when containers share a network.
| Field | Radarr | Sonarr | Lidarr |
|---|---|---|---|
| Name | putiorr |
putiorr |
putiorr |
| Host | putiorr |
putiorr |
putiorr |
| Port | 9091 |
9091 |
9091 |
| Use SSL | Off | Off | Off |
| Category | radarr |
sonarr |
lidarr |
| Directory | /downloads |
/downloads |
/downloads |
| URL Base | /radarr/transmission |
/sonarr/transmission |
/lidarr/transmission |
Keep Completed Download Handling enabled. Prowlarr usually does not need its own putiorr profile because Radarr, Sonarr, and Lidarr send accepted grabs to putiorr.
docker compose ps and confirm putiorr and the *arr apps are healthy.GET /api/profiles or in the UI before configuring the *arr apps./downloads and Category radarr, sonarr, or lidarr./downloads/<category> from inside the relevant *arr container.Check that putiorr and the *arr container share a Docker network. Use Host putiorr, Port 9091, and SSL off.
Check path identity first. The same host folder must be mounted as /downloads in putiorr and the importer.
Use the Direct Token tab in the putiorr UI, or configure a self-hosted callback with PUTIORR_PUBLIC_URL.