Two streams of fixes shipped together.
Headless persistence (root cause of "Fatal: Unable to find display or
encoder during startup")
- bin/sunshine-stream-undo.sh: stop removing HEADLESS-1 on disconnect.
Create-on-connect / destroy-on-disconnect raced with Sunshine's startup
encoder probe and made every restart fail with a fatal-but-misleading
warning. The output now lives across stream sessions; sunshine-stream-
do.sh just resizes it per client.
- files/headless-prestart.conf: systemd-user drop-in that runs
'hyprctl output create headless' (non-fatal) before Sunshine starts, so
HEADLESS-1 exists before the encoder probe.
- lib/headless.sh: install_headless_prestart_dropin resolves the actual
unit name (sunshine.service or app-dev.lizardbyte.app.Sunshine.service)
and lands the drop-in under ~/.config/systemd/user/<unit>.d/.
- lib/service.sh: enable_sunshine_service calls install_headless_prestart_
dropin when STREAM_MODE=headless. Placed after ensure_sunshine_unit_
present so the unit name is settled when the drop-in is written.
- install.sh: comment noting the drop-in install is deferred to the
service-enable step.
Web UI lockdown + tunnel-friendly certs
- lib/config.sh: emits origin_web_ui_allowed = pc. Sunshine rejects web UI
requests from anywhere other than localhost regardless of bind address.
Streaming/pairing (47989) stays LAN-accessible. Inline comment documents
the SSH tunnel recipe.
- lib/certs.sh: add DNS:localhost and IP:127.0.0.1 to host cert SANs so
the tunneled https://localhost:47990 URL doesn't trigger a hostname
mismatch. Idempotency check now requires those SANs too.
Misc.
- files/sunshine.service: fallback unit also gains the prestart ExecStartPre.
- lib/service.sh: ensure_sunshine_unit_present aliases the reverse-DNS
Sunshine unit as sunshine.service when sunshine-bin's short-name unit
isn't installed.
Replaces Sunshine's self-signed cert with one minted from a private root CA
whose key material lives in 1Password. Every host running install.sh fetches
the CA via 'op read', mints itself a host cert with SANs for <hostname>.lan
and the current LAN IP, and installs the CA into the system trust store.
Bootstrap (run once, anywhere)
- scripts/cert-bootstrap.sh: generates a 4096-bit RSA root CA (10y validity),
uploads it as a Secure Note titled "Omarchy-Stream Root CA" in the Private
vault with two fields: cert (text) and key (concealed). Refuses to overwrite
an existing item without --force.
Per-host (lib/certs.sh)
- fetch_and_install_certs: reads op://Private/Omarchy-Stream Root CA/{cert,key}
to a tmpfs-staged temp dir (XDG_RUNTIME_DIR), mints a host cert via openssl
with serverAuth + clientAuth EKU, drops cert/key at ~/.config/sunshine/
credentials/{cacert,cakey}.pem, installs the CA at
/etc/ca-certificates/trust-source/anchors/omarchy-stream-ca.pem and runs
update-ca-trust.
- Idempotent: skips re-mint when on-disk cert is signed by the current CA,
has the expected SANs, and isn't within 30 days of expiry. Override with
FORCE_CERTS=1 or --force-certs.
install.sh
- Adds --no-certs, --force-certs flags; sources lib/certs.sh; runs cert step
after permissions/config and before firewall so the service restart at the
end of install picks up the new cert.
client/install-macos.sh
- After installing Moonlight, if `op` is available and signed in, fetches the
CA and adds it as a trusted root to /Library/Keychains/System.keychain via
`security add-trusted-cert -d -r trustRoot`. Skips cleanly when op isn't
ready.
uninstall.sh
- Adds --remove-ca-trust to delete the system trust anchor. By default the
CA is left in place since other tools may rely on it.
verify.sh
- Adds checks for: cert signed by omarchy-stream CA, cert >30 days from
expiry, CA present in system trust store.
Docs
- README "Trusted TLS certs via 1Password" section: bootstrap flow, per-host
flow, client trust matrix (Linux / macOS / iOS / Android / Apple TV),
re-pairing note (first cert install on a host invalidates pinned Moonlight
fingerprints), config env vars.
- client/README gains per-platform CA-trust install steps with concrete
`op read` + platform-specific commands.