Whisparr on PMSS
Whisparr, an adult video library manager in the Sonarr family, runs at your own Pulsed Media seedbox address behind its own login. The steps below create that login before any port is open and switch Whisparr's analytics off in the same request. It runs in rootless Docker inside your account. Tested on one Pulsed Media seedbox on 24 October 2026 with ghcr.io/hotio/whisparr v2.2.0.231; the parts that were not tested are marked where they appear.
Privacy
Level: MEDIUM. Using Whisparr reduces your privacy. What it sends out of your account:
- Analytics are on by default. In the test, after logging in, the web interface tried to send a request to an error-reporting service (Sentry). Step 3 sets
analyticsEnabledto false, and with it off the same check saw no such request. - Metadata lookups go to
api.whisparr.com, the Whisparr project's metadata server, and update checks go to GitHub's releases API (Whisparr v2 source,WhisparrCloudRequestBuilder.cs). In the test Whisparr checked GitHub for a newer release at start. - In the test, Whisparr's redirect from its start page to its login page pointed at an
http://address, so a browser that follows it leaves HTTPS before the password is typed. Before typing your password, check that the address bar showshttps://; see Troubleshooting. - An indexer or download client you add receives what you search for and fetch with it.
Requirements
| Need | Whisparr on PMSS |
|---|---|
| Memory | Not measured in the test. |
| Disk | The image is 362 MB and took about 2 minutes to download in the test. Docker keeps it in your home folder, so it counts toward your disk quota. |
| Own login | Yes. Created in step 3, while no port is published. |
| Address | https://SERVER/user-USERNAME/whisparr/ through your own web server. Whisparr's own 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, so Whisparr starts once with no port published, gets its login from inside the container, 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, the login and the config. The API key and password are random, stay in files only you can read, and never appear on a command line.
mkdir -p ~/docker/whisparr/config chmod 700 ~/docker/whisparr KEY=$(openssl rand -hex 16) PASS=$(openssl rand -base64 18 | tr -dc 'A-Za-z0-9' | head -c 20) printf 'PUID=0\nPGID=0\nUMASK=002\nTZ=Etc/UTC\n' > ~/docker/whisparr/app.env printf 'WHISPARR_KEY=%s\nWHISPARR_PASS=%s\nWHISPARR_USER=admin\n' "$KEY" "$PASS" > ~/docker/whisparr/login.env printf '<Config>\n <BindAddress>*</BindAddress>\n <Port>6969</Port>\n <ApiKey>%s</ApiKey>\n <UrlBase>/user-USERNAME/whisparr</UrlBase>\n <AuthenticationMethod>Forms</AuthenticationMethod>\n <AuthenticationRequired>Enabled</AuthenticationRequired>\n <LaunchBrowser>False</LaunchBrowser>\n</Config>\n' "$KEY" > ~/docker/whisparr/config/config.xml unset KEY PASS chmod 600 ~/docker/whisparr/app.env ~/docker/whisparr/login.env ~/docker/whisparr/config/config.xml
admin is the login name; any name works. The config turns on the login form, but Whisparr has no user until step 3, so no port exists before then.
2. Start it with no port published. The image is pinned to the digest that was tested.
docker run -d --name whisparr --env-file ~/docker/whisparr/app.env \
-v ~/docker/whisparr/config:/config \
ghcr.io/hotio/whisparr@sha256:63ce3b7f8d2fde7310a40f1ad81b1734e4443ba0f8218bd2d2aaf988fff94fcc
docker exec whisparr curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:6969/user-USERNAME/whisparr/ping
Repeat the last command until it prints 200; in the test that took about 20 seconds after the start.
3. Create the login and switch analytics off, from inside the container. The script reads the key and password from login.env, which Docker passes in as variables.
cat > ~/docker/whisparr/set-login.sh <<'EOF'
umask 077
B=http://127.0.0.1:6969/user-USERNAME/whisparr
printf 'header = "X-Api-Key: %s"\n' "$WHISPARR_KEY" > /dev/shm/c.cfg
curl -s -K /dev/shm/c.cfg $B/api/v3/config/host/1 > /dev/shm/h.json
jq '.analyticsEnabled=false | .username=$ENV.WHISPARR_USER | .password=$ENV.WHISPARR_PASS | .passwordConfirmation=$ENV.WHISPARR_PASS' /dev/shm/h.json > /dev/shm/h2.json
echo "PUT: $(curl -s -K /dev/shm/c.cfg -X PUT -H 'Content-Type: application/json' --data-binary @/dev/shm/h2.json -o /dev/shm/r.json -w '%{http_code}' $B/api/v3/config/host/1)"
jq -c '{analyticsEnabled,authenticationMethod,authenticationRequired,username}' /dev/shm/r.json
rm -f /dev/shm/c.cfg /dev/shm/h.json /dev/shm/h2.json /dev/shm/r.json
EOF
docker exec -i --env-file ~/docker/whisparr/login.env whisparr sh < ~/docker/whisparr/set-login.sh
It prints PUT: 202 and a line with "analyticsEnabled":false and your login name. In the test the login was first set with this request minus the analytics line while no port was published, and the full request above was sent later to the running container; both returned 202.
4. Start it again with its port on 127.0.0.1. The login and settings stay in the config folder.
docker rm -f whisparr docker run -d --name whisparr --env-file ~/docker/whisparr/app.env \ -p 127.0.0.1:PORT:6969 \ -v ~/docker/whisparr/config:/config \ ghcr.io/hotio/whisparr@sha256:63ce3b7f8d2fde7310a40f1ad81b1734e4443ba0f8218bd2d2aaf988fff94fcc
5. Add the proxy fragment as ~/.lighttpd/custom.d/whisparr.conf, with your USERNAME and PORT:
$HTTP["url"] =~ "^/user-USERNAME/whisparr(/|$)" {
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 Whisparr's own login, which exists since step 3. The setenv.set-request-header line keeps your panel password from being sent to Whisparr, 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 Whisparr. The line was tested on 24 October 2026 with a small test app, not in the Whisparr 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/whisparr/loginand log in asadminwith the password fromgrep WHISPARR_PASS ~/docker/whisparr/login.env. Check that the address starts withhttps://first. - The install maps only the config folder into the container. For Whisparr to see your video folders, add a
-vline for each one to the step 4 command, thendocker rm -f whisparrand run it again. That variant was not part of the test. - Keep Authentication Required on Enabled. Every account on the server can reach the port on
127.0.0.1. - Adding
--restart unless-stoppedto the step 4 command brings Whisparr 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. Other programs talk to Whisparr with its API key, the ApiKey value in ~/docker/whisparr/config/config.xml. In the test, API requests with the key were accepted through the panel address, and on the port itself API requests carrying only a login session were refused with 401.
Test
docker ps --filter name=whisparrshows the container as Up.https://SERVER/user-USERNAME/whisparr/leads to Whisparr's login 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/whisparr/api/v3/system/status
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:PORT/user-USERNAME/whisparr/
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:PORT/user-USERNAME/whisparr/initialize.json
In the test the first returned 401 and the other two 302, a redirect to the login page. Through the panel address the results matched, and /user-USERNAME/ itself still asked for the panel login.


Uninstall
docker rm -f whisparr rm ~/.lighttpd/custom.d/whisparr.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 ghcr.io/hotio/whisparr@sha256:63ce3b7f8d2fde7310a40f1ad81b1734e4443ba0f8218bd2d2aaf988fff94fcc frees the image's 362 MB, unless you keep it for the Sportarr on PMSS helper step.
Deleting the data is your choice. rm -rf ~/docker/whisparr deletes the login file, the setup script and the config folder with Whisparr's settings and library database. Video folders you mapped from elsewhere are not touched.
Troubleshooting
- The login page opens at an
http://address: in the test, openinghttps://SERVER/user-USERNAME/whisparr/without a login redirected to the login page athttp://. Openhttps://SERVER/user-USERNAME/whisparr/logindirectly instead. A login sent from the https login page returned to an https address in the test. A setting that fixes the redirect was not tested. - Step 2 prints
000: Whisparr is still starting. In the test it printed000for about 20 seconds before200. - A login attempt goes back to the login page with
loginFailed=truein the address: the name or password is wrong. That is what a wrong password returned in the test. Read them again fromlogin.env. docker pullordocker runfails before Whisparr 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
- Lighttpd Custom Configuration — proxy fragments and the panel login
- Rootless DOCKER — running containers in your account
- Install Media Stack — Sonarr, Radarr and Prowlarr, installed by PMSS
- Seedbox — Pulsed Media seedbox plans, each with rootless Docker included