Jump to content

Whisparr on PMSS

From Pulsed Media Wiki

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 analyticsEnabled to 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 shows https://; 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/login and log in as admin with the password from grep WHISPARR_PASS ~/docker/whisparr/login.env. Check that the address starts with https:// first.
  • The install maps only the config folder into the container. For Whisparr to see your video folders, add a -v line for each one to the step 4 command, then docker rm -f whisparr and 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-stopped to 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

  1. docker ps --filter name=whisparr shows the container as Up.
  2. https://SERVER/user-USERNAME/whisparr/ leads to Whisparr's login page.
  3. 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.

Whisparr's login page at /user-USERNAME/whisparr/ in the 24 October 2026 test.
After logging in: the empty library of a new install, 24 October 2026 test.

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, opening https://SERVER/user-USERNAME/whisparr/ without a login redirected to the login page at http://. Open https://SERVER/user-USERNAME/whisparr/login directly 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 printed 000 for about 20 seconds before 200.
  • A login attempt goes back to the login page with loginFailed=true in the address: the name or password is wrong. That is what a wrong password returned in the test. Read them again from login.env.
  • docker pull or docker run fails before Whisparr starts: see the troubleshooting section of Rootless DOCKER.

See also