Guided Setup with owpctl

owpctl installs, configures, diagnoses, upgrades and removes OpenWatchParty. It manages its own hardened Compose project and adopts your existing Jellyfin without rewriting its deployment files.

Download

Platform Asset
Linux x86_64 owpctl-linux-x86_64
Linux arm64 owpctl-linux-aarch64
macOS (Apple silicon) owpctl-macos-aarch64
macOS (Intel) owpctl-macos-x86_64
Windows x86_64 owpctl-windows-x86_64.exe
# Linux x86_64 example
curl -fLO https://github.com/mhbxyz/OpenWatchParty/releases/latest/download/owpctl-linux-x86_64
curl -fLO https://github.com/mhbxyz/OpenWatchParty/releases/latest/download/owpctl-linux-x86_64.sha256
sha256sum -c owpctl-linux-x86_64.sha256
chmod +x owpctl-linux-x86_64
sudo install -m 0755 owpctl-linux-x86_64 /usr/local/bin/owpctl

On macOS, verify with shasum -a 256 -c. Release assets also contain Sigstore and provenance bundles for independent verification.

Graphical Setup

owpctl setup --web

This uses user scope and requires Docker access for that user. For system scope, use sudo owpctl --scope system setup --web and open the one-time URL printed in the terminal if it does not launch a browser. The illustrated walkthrough shows where to create a temporary Jellyfin API key, what to enter in the assistant and how to verify the result.

The command opens a one-time URL bound to 127.0.0.1. Preview plan parses the Jellyfin URL and lists the planned operations without installing anything; it does not test connectivity or validate the administrator token. A token is not required for the preview. Install validates Docker and Jellyfin, installs or upgrades the plugin, configures authentication, deploys the signed session-server image and verifies health before stopping the assistant.

Open the printed URL once and keep the page open. Reloading it or opening it again returns Invalid or consumed setup token. If this happens before installation, stop the setup command and rerun it for a fresh session. The web assistant stops after installation or 30 minutes. It does not write the supplied administrator API token to its configuration files. Close the page and revoke the temporary API key in Jellyfin after setup and diagnostics.

install, upgrade and configure write only the plugin settings owpctl manages: the JWT secret, audience and issuer, the token and invite lifetimes, and the session server URL, and it turns off unauthenticated access and the auto-detected session server. Every other plugin setting, such as hiding Jellyfin’s SyncPlay button, keeps the value it had before the update. A setting the new plugin version no longer has, or now stores with a different type, takes that version’s default.

Remote Browser Access

When owpctl setup --web runs over SSH, its loopback URL belongs to the remote machine, not your computer. Keep that setup process running and create an SSH local forward in another terminal on your computer. For example, if the printed URL uses port 43123:

ssh -N -L 127.0.0.1:43123:127.0.0.1:43123 user@jellyfin-host

Replace the host and both port numbers with your server and the printed port. Use the same local and remote port so the assistant’s origin check still matches. Open the original one-time URL in your local browser, then keep that page and the SSH forward open until setup finishes. Do not publish the setup port or share the URL/token. Alternatively, use headless setup below.

Headless Setup

Create the configuration:

sudo owpctl --scope system setup \
  --non-interactive \
  --jellyfin-url https://jellyfin.example.com

Store a temporary Jellyfin admin API token in a protected file, review the plan, then install:

sudo install -m 0600 /dev/null /run/owp-jellyfin-token
sudo sh -c 'read -r token; printf %s "$token" > /run/owp-jellyfin-token'
sudo owpctl --scope system install --dry-run --api-token-file /run/owp-jellyfin-token
sudo owpctl --scope system install --yes --api-token-file /run/owp-jellyfin-token
sudo rm -f /run/owp-jellyfin-token

Diagnostics

Every owpctl command prints a human-readable summary by default. Passing --json switches the output to machine-readable JSON for scripting and automation.

owpctl status
owpctl doctor --api-token-file /run/owp-jellyfin-token
owpctl doctor --json --api-token-file /run/owp-jellyfin-token
owpctl doctor --bundle /tmp/owp-support.json --api-token-file /run/owp-jellyfin-token

doctor verifies Docker, Jellyfin, plugin metadata, session health, JWT issuance and an authenticated WebSocket ping/pong. It never prints the token or JWT. --bundle writes a redacted support file (the report, the desired configuration and the installation state, with the secret fingerprint removed) that can be shared when asking for help.

Maintenance

owpctl upgrade --dry-run --api-token-file /run/owp-jellyfin-token
owpctl upgrade --yes --api-token-file /run/owp-jellyfin-token
owpctl backup
owpctl logs                  # follow the session server logs
owpctl logs --tail 200 --no-follow
owpctl configure --set session.log-level=debug --api-token-file /run/owp-jellyfin-token
owpctl configure --rotate-jwt-secret --yes --api-token-file /run/owp-jellyfin-token
owpctl uninstall --yes --keep-config --api-token-file /run/owp-jellyfin-token

install, upgrade and configure retain plugin settings that owpctl does not manage. Upgrade compatibility is conservative: fractions cannot replace an integer setting, and changed arrays or objects retain the installed plugin’s value because its JSON does not expose the .NET schema. An invalid configuration root aborts without posting a replacement. Configuration debug output redacts all values, including unknown future secrets.

Asymmetric Pairing

owpctl setup defaults to hybrid mode, which accepts shared-secret HS256 tokens and trusted RS256 tokens. Pairing registers the plugin public RSA key in the session-server trust store, activates RS256 issuance, then restarts the managed server in asymmetric mode without injecting the shared secret.

sudo owpctl --scope system pair \
  --jellyfin-url https://jellyfin.example.com \
  --api-token-file /run/owp-jellyfin-token \
  --trust-store /var/lib/openwatchparty/trust-store.json

List or revoke trusted keys:

sudo owpctl --scope system trust --store /var/lib/openwatchparty/trust-store.json list
sudo owpctl --scope system trust --store /var/lib/openwatchparty/trust-store.json revoke --kid KEY_ID

The RSA private key remains in Jellyfin’s plugin data directory with owner-only permissions. The session server stores public keys only. pair reads or creates the plugin’s current signing key and is safe to repeat; it does not rotate that key. Revoking a trusted key rejects later authentication attempts using tokens signed by it. Already-authenticated WebSocket sessions are not immediately disconnected by a trust-store edit; their existing expiry and reconnect rules still apply. There is no automated signing-key rotation command, so plan key replacement and pairing before revoking the active key.

Managed Files

System scope:

/etc/openwatchparty/owpctl.toml
/etc/openwatchparty/secrets.env
/var/lib/openwatchparty/state.json
/var/lib/openwatchparty/compose.yaml
/var/lib/openwatchparty/trust-store.json
/var/lib/openwatchparty/backups/

uninstall removes only resources marked as owned in state.json. Jellyfin itself and unrelated plugin repositories are never removed.


Back to top

OpenWatchParty - Synchronized watch parties for Jellyfin