Sportarr on PMSS
Sportarr follows the sports leagues you pick and fetches new events from the sources you configure, served at your own Pulsed Media seedbox address behind its own login. The steps below create that login while no port is open, so its default of no login at all is gone before any other account on the server can reach it. It runs in rootless Docker inside your account. Tested on one Pulsed Media seedbox on 24 October 2026 with sportarr/sportarr 4.1.11.1121; the parts that were not tested are marked where they appear. Read the login cookie point under Privacy before installing it on a shared seedbox.
Privacy
Level: MEDIUM. Using Sportarr reduces your privacy.
- Its login cookie reaches other accounts' pages. Sportarr sets its login cookie for the whole server address (
path=/), not for/user-USERNAME/sportarr/. On a shared seedbox every account's pages are served from that same address, so your browser also sends the cookie with requests to other accounts' pages on that server. Whether another account could reuse it was not tested. Treat it as a risk: run Sportarr on a server no one else has an account on, such as a dedicated server, or accept that risk on a shared one. - Sportarr's config file has
SendAnonymousUsageDataset to true by default. What it sends, and turning it off, were not tested. - Metadata lookups go to the Sportarr project's API at
sportarr.net(src/appsettings.jsonin release 4.1.11.1121). - An indexer or download client you add receives what you search for and fetch with it.
Requirements
| Need | Sportarr on PMSS |
|---|---|
| Memory | Not measured in the test. |
| Disk | The image is 1.62 GB and took about 14 minutes to download in the test. Step 3 also uses the Whisparr image (362 MB) as a helper. Docker keeps images in your home folder, so they count toward your disk quota. |
| Server | A dedicated server, because of the login cookie (see Privacy). On a shared seedbox only if you accept that risk. |
| Own login | Yes. Set in step 3, while no port is published. |
| Address | https://SERVER/user-USERNAME/sportarr/ through your own web server. Sportarr's URL base setting carries the path, so the proxy fragment needs no map-urlpath.
|
| Other apps | An indexer and a download client to fetch anything; connecting them was not part of the test. |
Install
Replace USERNAME with your account name and PORT with a free port between 2000 and 38000 that ss -tln does not list. Other accounts on the same server can connect to 127.0.0.1. With its default settings Sportarr has no login, and in the test its initialize.json, the file its web interface reads the API key from, was served to an anonymous request from inside its own network. So Sportarr starts once with no port published, gets its login, and only then gets its port. The test ran these steps for a throwaway account in a scratch folder; the commands below are the same with your own folders.
1. Make the folder and the login. The password is random, stays in a file only you can read, and never appears on a command line.
mkdir -p ~/docker/sportarr/config chmod 700 ~/docker/sportarr PASS=$(openssl rand -base64 18 | tr -dc 'A-Za-z0-9' | head -c 20) printf 'PUID=0\nPGID=0\nUMASK=022\nTZ=Etc/UTC\n' > ~/docker/sportarr/app.env printf 'SPORTARR_PASS=%s\nSPORTARR_USER=admin\n' "$PASS" > ~/docker/sportarr/login.env unset PASS chmod 600 ~/docker/sportarr/app.env ~/docker/sportarr/login.env
admin is the login name; any name works.
2. Start it with no port published, and wait for its config. The image is pinned to the digest that was tested.
docker run -d --name sportarr --env-file ~/docker/sportarr/app.env \ -v ~/docker/sportarr/config:/config \ sportarr/sportarr@sha256:5747ba701adac29fdf3c5139e4a9437c4b9d4f61ce8cddfe7a8b8194bd8fc46a ls ~/docker/sportarr/config/config.xml
Repeat the last command until it lists the file. In the test that took about 2.5 minutes after the start while Sportarr applied 106 database migrations; docker ps showed it as unhealthy during and after that, which did not stop the steps below.
3. Set the path and the login from a helper container. The Sportarr image has curl but no jq, so a short-lived helper container that shares Sportarr's network makes the change. The test used the Whisparr image as the helper, because it has curl and jq; it is removed again when the step ends (--rm).
cat > ~/docker/sportarr/set-login.sh <<'EOF'
umask 077
B=http://127.0.0.1:1867
K=$(sed -n 's:.*<ApiKey>\(.*\)</ApiKey>.*:\1:p' /cfg/config.xml)
printf 'header = "X-Api-Key: %s"\n' "$K" > /dev/shm/c.cfg; unset K
curl -s -K /dev/shm/c.cfg -o /dev/shm/s.json $B/api/settings
jq '.hostSettings = (.hostSettings|fromjson|.urlBase="/user-USERNAME/sportarr"|tojson)
| .securitySettings = (.securitySettings|fromjson|.authenticationMethod="forms"|.authenticationRequired="enabled"|.username=$ENV.SPORTARR_USER|.password=$ENV.SPORTARR_PASS|tojson)' /dev/shm/s.json > /dev/shm/s2.json
echo "PUT: $(curl -s -K /dev/shm/c.cfg -X PUT -H 'Content-Type: application/json' --data-binary @/dev/shm/s2.json -o /dev/shm/r.json -w '%{http_code}' $B/api/settings)"
rm -f /dev/shm/c.cfg /dev/shm/s.json /dev/shm/s2.json /dev/shm/r.json
EOF
docker run --rm -i --network container:sportarr \
-v ~/docker/sportarr/config:/cfg:ro \
--env-file ~/docker/sportarr/login.env \
--entrypoint sh \
ghcr.io/hotio/whisparr@sha256:63ce3b7f8d2fde7310a40f1ad81b1734e4443ba0f8218bd2d2aaf988fff94fcc < ~/docker/sportarr/set-login.sh
It prints PUT: 200. Sportarr's settings API returns two of its sections as JSON text inside JSON, which is why the script unpacks them with fromjson and packs them again with tojson.
4. Restart it and check the login is on, still with no port.
docker restart sportarr
cat > ~/docker/sportarr/check.sh <<'EOF'
B=http://127.0.0.1:1867/user-USERNAME/sportarr
for i in $(seq 1 60); do c=$(curl -s -o /dev/null -w '%{http_code}' $B/ping); [ "$c" = 200 ] && break; sleep 3; done; echo "ping=$c"
echo "settings without login: $(curl -s -o /dev/null -w '%{http_code}' $B/api/settings)"
curl -s $B/initialize.json | head -c 120; echo
EOF
docker run --rm -i --network container:sportarr --entrypoint sh \
ghcr.io/hotio/whisparr@sha256:63ce3b7f8d2fde7310a40f1ad81b1734e4443ba0f8218bd2d2aaf988fff94fcc < ~/docker/sportarr/check.sh
In the test this printed ping=200 after about 2 minutes, settings without login: 401, and an initialize.json beginning {"apiRoot":"","apiKey":"", with the key empty. Before step 3 the same request was answered without a login.
5. Start it again with its port on 127.0.0.1. The settings stay in the config folder. Sportarr takes about 2 minutes to answer after each start.
docker rm -f sportarr docker run -d --name sportarr --env-file ~/docker/sportarr/app.env \ -p 127.0.0.1:PORT:1867 \ -v ~/docker/sportarr/config:/config \ sportarr/sportarr@sha256:5747ba701adac29fdf3c5139e4a9437c4b9d4f61ce8cddfe7a8b8194bd8fc46a
6. Add the proxy fragment as ~/.lighttpd/custom.d/sportarr.conf, with your USERNAME and PORT:
$HTTP["url"] =~ "^/user-USERNAME/sportarr(/|$)" {
auth.require = ()
setenv.set-request-header = ( "Authorization" => "" )
proxy.server = ( "" => ( ( "host" => "127.0.0.1", "port" => PORT ) ) )
proxy.header = ( "upgrade" => "enable" )
}
auth.require = () lets requests past your panel login to Sportarr's own login. The setenv.set-request-header line keeps your panel password from being sent to Sportarr, which has its own login and does not need it; without the line, a browser that has logged into your panel also sends that password to Sportarr. The line was tested on 24 October 2026 with a small test app, not in the Sportarr test above. Check the syntax with /usr/sbin/lighttpd -t -f ~/.lighttpd.conf; your web server picks up the file within about a minute (Lighttpd Custom Configuration).
Configure
- Open
https://SERVER/user-USERNAME/sportarr/and log in asadminwith the password fromgrep SPORTARR_PASS ~/docker/sportarr/login.env. After the first login Sportarr opens a setup wizard; one of its steps offers to secure the app, and the login from step 3 is already on. - Keep the login on. Every account on the server can reach the port on
127.0.0.1. - The install maps only the config folder into the container. For Sportarr to see your media folders, add a
-vline for each one to the step 5 command, thendocker rm -f sportarrand run it again. That variant was not part of the test. - Adding
--restart unless-stoppedto the step 5 command brings Sportarr back when your Docker daemon restarts, as described on Rootless DOCKER. The test ran without it.
Integrate
Connecting indexers and download clients was not part of the test; the setup wizard has steps for both. Other programs talk to Sportarr with its API key, the ApiKey value in ~/docker/sportarr/config/config.xml. In the test a login session also authorized Sportarr's API.
Test
docker ps --filter name=sportarrshows the container as Up.https://SERVER/user-USERNAME/sportarr/shows Sportarr's sign-in page.- Requests without a login straight to the port are refused, which is what another account on the server sees:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:PORT/user-USERNAME/sportarr/api/settings
curl -s http://127.0.0.1:PORT/user-USERNAME/sportarr/api/auth/check; echo
curl -s http://127.0.0.1:PORT/user-USERNAME/sportarr/initialize.json | head -c 120; echo
In the test the first returned 401, the second {"authenticated":false}, and the third an empty apiKey. The start page itself returns 200, because it is the app's page code; it then sends the browser to the sign-in page. A wrong password at sign-in returned 401. Through the panel address the results matched, and /user-USERNAME/ itself still asked for the panel login.


Uninstall
docker rm -f sportarr rm ~/.lighttpd/custom.d/sportarr.conf touch ~/.lighttpd/custom
Deleting a fragment changes no remaining file, so touch ~/.lighttpd/custom makes your web server restart without it within about a minute (Lighttpd Custom Configuration explains why). docker rmi sportarr/sportarr@sha256:5747ba701adac29fdf3c5139e4a9437c4b9d4f61ce8cddfe7a8b8194bd8fc46a frees the image's 1.62 GB. If you do not run Whisparr, docker rmi ghcr.io/hotio/whisparr@sha256:63ce3b7f8d2fde7310a40f1ad81b1734e4443ba0f8218bd2d2aaf988fff94fcc frees the helper image's 362 MB.
Deleting the data is your choice. rm -rf ~/docker/sportarr deletes the login file, the two scripts and the config folder with Sportarr's settings and database. Media folders you mapped from elsewhere are not touched.
Troubleshooting
- The browser console shows 404 errors for
/assets/…jsat the server root: some parts of Sportarr's interface load their script files from the root of the address instead of from/user-USERNAME/sportarr/. In the test 15 such files failed to load; the interface still signed in and showed its Leagues page. No fix was tested. config.xmldoes not appear anddocker psshows unhealthy: Sportarr is still applying its database migrations on the first start. Wait; in the test it took about 2.5 minutes.- Step 4 prints
ping=with anything other than200: Sportarr had not answered within the script's 3 minutes. Run the check again. docker pullordocker runfails before Sportarr starts: see the troubleshooting section of Rootless DOCKER.
See also
- Self-Hosted Apps on PMSS — other applications for rootless Docker, with their path settings and login defaults
- Whisparr on PMSS — the guide for the image used as the helper in step 3
- Lighttpd Custom Configuration — proxy fragments and the panel login
- Rootless DOCKER — running containers in your account
- Dedicated server — a server of your own, where Sportarr's login cookie reaches no other account