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.
Moonlight clients
This directory covers installing Moonlight on the devices that connect to your Sunshine host. The host side (Sunshine on Linux) is documented in the top-level README.
Install
macOS
From a Mac that has this repo checked out:
./client/install-macos.sh
The script verifies Homebrew is present and runs brew install --cask moonlight.
It will not install Homebrew for you.
Manual equivalent:
brew install --cask moonlight
Fallback (no Homebrew): download a signed DMG from the official releases page
and drag Moonlight.app into /Applications:
Android
Install "Moonlight Game Streaming" from the Play Store:
iOS / iPadOS
Install "Moonlight Game Streaming" from the App Store:
Apple TV
Same listing on the tvOS App Store. Search "Moonlight Game Streaming" on the Apple TV itself, or use the App Store link above from an iOS device signed in to the same Apple ID.
Steam Deck / Linux
Use moonlight-qt from your distro's package manager (Flatpak on Steam Deck,
pacman/apt elsewhere). It is the same Qt-based client as macOS and Windows.
Trusting the omarchy-stream CA
If the host was installed with the cert step (default), its Sunshine web UI
uses a cert signed by a private root CA whose key is stored in 1Password. To
avoid the browser warning on https://<host>.lan:47990, install the CA on each
client device. This is a one-time step per device.
macOS
./install-macos.sh handles this automatically if op is signed in. To do it
manually:
op read --no-newline "op://Private/Omarchy-Stream Root CA/cert" > /tmp/ca.pem
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain /tmp/ca.pem
rm /tmp/ca.pem
iOS / iPadOS
- In the 1Password app, open the Omarchy-Stream Root CA item in the
Private vault. Copy the
certfield into the body of an email and send it to yourself with the file extension.crtor.pem(Mail handles inline PEM oddly; an attachment is cleanest). - Open the email on the iOS device and tap the attachment. iOS will offer to install a configuration profile.
- Settings → General → VPN & Device Management → Downloaded Profile → Install.
- Important second step: Settings → General → About → Certificate Trust Settings → enable full trust for the omarchy-stream Root CA. Without this, Safari still warns.
Android
- From 1Password, save the CA
certfield to a.crtfile on the device (Downloads folder is fine). - Settings → Security → Encryption & credentials → Install a certificate → CA certificate.
- Acknowledge the warning, select the file, give it a name.
(Path varies slightly by Android version / OEM skin — search Settings for "CA certificate" if the path above doesn't match.)
Apple TV
Cert profiles can be installed by emailing the cert to an account on the Apple TV and tapping it, or by using Apple Configurator from a Mac. For LAN-only use the self-signed warning is also tolerable — Apple TV has no browser, so the cert is only relevant if you ever inspect the host directly.
First pair
The pairing flow is the same on every client.
-
Confirm the host is healthy. On the host machine:
./install.sh --doctorSunshine must be running and reachable on the LAN.
-
On the client, open Moonlight. The host should appear automatically via mDNS as long as the client is on the same LAN. If it does not appear, use "Add Host Manually" and enter the host's LAN IP address.
-
Click or tap the host. Moonlight displays a 4-digit PIN.
-
On the host machine, open the Sunshine web UI:
https://localhost:47990Accept the self-signed certificate. Log in (credentials are set the first time you visit). Go to the PIN tab, enter the 4-digit PIN from the client, and submit. Pairing typically completes within about 5 seconds.
-
Back in Moonlight, the host now shows as "Paired". Click it to see the available apps. The default app is "Desktop", which is either a full-screen mirror of the host's display or a headless virtual display, depending on how the host is configured.
Streaming notes
-
Resolution. Moonlight lets you pick a target stream resolution per host. On a headless-configured host, that resolution is what the host actually renders at. On a mirror-configured host, the host renders at its native resolution and Moonlight downscales on the client.
-
Bitrate. Moonlight's defaults are conservative for general internet use. For LAN streaming, bump it to 50-100 Mbps.
-
Audio. By default, Moonlight captures audio from the host and plays it on the client. If you want the host's speakers/monitor to keep playing audio while you stream, enable "Play audio on host" in Moonlight's stream settings.
Troubleshooting
-
"Host not found" / host does not appear automatically. Confirm both machines are on the same LAN/VLAN. mDNS does not traverse VLANs without an mDNS reflector. Fall back to "Add Host Manually" with the host's IP.
-
Pairing PIN does not work. Two common causes: the Sunshine web UI session has timed out (log in again and re-enter the PIN), or the PIN is being entered into the wrong host (multiple Sunshine instances on the LAN). Cancel and re-trigger pair from the client to get a fresh PIN.
-
Black screen after pairing. This is a host-side problem. On the host:
./install.sh --doctor -
Mac cannot reach
brew. Homebrew is not installed (or not onPATH). Install it per https://brew.sh, open a fresh shell, then re-run./client/install-macos.sh. -
Android sees the host but cannot connect. The Android device is probably on a guest WiFi SSID that is isolated from the main LAN. Move it to the main LAN, or use "Add Host Manually" with the host IP.