docs+plugin: HTTP-only transport cleanup, install guide, review fixes
- docs/install.md: new end-to-end guide for non-technical users (gateway install, app install, LAN/TLS/remote connection, push, options, troubleshooting); docs/setup.md now points to it - README: new 'Install the gateway' section; pairing section updated for HTTP transport (8791, QR scan on Android) - rename IRIS_WS_HOST -> IRIS_HTTP_HOST (clean rename, no compat fallback); drop dead DEFAULT_PORT=8790 - setup.py: advertise https:// in the printed/QR server URL when IRIS_HTTP_CERT is set - ws_probe.py/e2e.py: default --url http://127.0.0.1:8791, env IRIS_WS_URL -> IRIS_HTTP_URL, honor explicit port + https scheme - plugin.yaml: IRIS_HTTP_* env names, description no longer says 'WebSocket server' - docs 03/09/12/19: fix stale WS-era refs (ws_server.py cites, 8790 smoke test, WSS->HTTPS, 'HTTP fallback' reframed as the only transport) - AGENTS.md: symlink name android -> iris (matches actual install) - test: adapter reads IRIS_HTTP_HOST/CERT/KEY from env; legacy IRIS_WS_* names are not consulted (95/95 pass)
This commit is contained in:
1 parent
a61b47a947
commit
b1c9bac7d8
18 files changed
+472
-317
No files matched your search
+246
@@ -0,0 +1,246 @@
|
||||
# Install — Gateway & App
|
||||
|
||||
A step-by-step guide for getting **Iris** (the Android / Desktop app) talking
|
||||
to your **hermes gateway**. Written for people who just want to *use* it, not
|
||||
build it. If you only want the short version, the [README](../README.md) has
|
||||
the three commands that matter.
|
||||
|
||||
The whole setup has two halves:
|
||||
|
||||
1. **The gateway** — a small plugin that runs *inside* your existing hermes
|
||||
install and opens a door for the app to connect through.
|
||||
2. **The app** — on your phone or desktop, where you enter the gateway's
|
||||
address and a pairing token.
|
||||
|
||||
> **Old guides?** Earlier versions of Iris used a WebSocket on port `8790`
|
||||
> (`ws://…/ws`). The transport is now plain HTTP on port **`8791`**
|
||||
> (see [`19-http-fallback-transport.md`](19-http-fallback-transport.md)).
|
||||
> The app still accepts old `ws://` URLs and converts them automatically, but
|
||||
> new setups should use the `http://` URL printed by `hermes gateway setup`.
|
||||
|
||||
---
|
||||
|
||||
## What you need
|
||||
|
||||
| Where | What |
|
||||
| --- | --- |
|
||||
| Gateway host (any always-on computer: home server, Raspberry Pi, laptop) | [hermes-agent](https://github.com/NousResearch/hermes-agent) installed with its venv (`cd hermes-agent && uv sync`) |
|
||||
| Phone / desktop | Android 8+ or Linux / macOS / Windows |
|
||||
| Only if you build the app yourself | JDK 17 (+ Android SDK for Android) — see [`12-toolchain.md`](12-toolchain.md) |
|
||||
|
||||
---
|
||||
|
||||
## Part 1 — Install the gateway plugin (one-time)
|
||||
|
||||
Iris is a regular hermes **platform plugin**, so it installs with the normal
|
||||
plugin command. This repo is a *monorepo* (the plugin lives in the
|
||||
`gateway-plugin/` subfolder, next to the app), so you point the installer at
|
||||
that subfolder with a `#subfolder` suffix:
|
||||
|
||||
```bash
|
||||
hermes plugins install git@gitea.zephyre.one:ARIA/iris_x_hermes.git#gateway-plugin
|
||||
```
|
||||
|
||||
That's it. The installer clones the repo, copies just the `gateway-plugin/`
|
||||
folder into `~/.hermes/plugins/`, and asks whether to enable it now (say
|
||||
**yes**).
|
||||
|
||||
Notes:
|
||||
|
||||
- Any git URL works with the `#gateway-plugin` suffix — e.g.
|
||||
`https://gitea.zephyre.one/ARIA/iris_x_hermes.git#gateway-plugin` if you
|
||||
prefer HTTPS.
|
||||
- **Developing from a checkout?** Skip the install and symlink instead — the
|
||||
plugin then always tracks your working tree:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.hermes/plugins
|
||||
ln -s "$PWD/gateway-plugin" ~/.hermes/plugins/iris
|
||||
```
|
||||
|
||||
- Check it was picked up:
|
||||
|
||||
```bash
|
||||
hermes gateway status # the Iris platform should be listed
|
||||
```
|
||||
|
||||
## Part 2 — Gateway setup (one-time)
|
||||
|
||||
Run the interactive setup:
|
||||
|
||||
```bash
|
||||
hermes gateway setup
|
||||
```
|
||||
|
||||
It walks you through four things:
|
||||
|
||||
| Prompt | What it means | Default |
|
||||
| --- | --- | --- |
|
||||
| **Iris pairing token** | A long random secret the app must present to connect. Generated for you; stored in `~/.hermes/.env` as `IRIS_TOKEN`. **It is printed only once** — write it down. | auto-generated |
|
||||
| **HTTP host** | Which network address the gateway listens on. `127.0.0.1` = only this machine. For a phone on your home network, use the machine's **LAN IP** (e.g. `192.168.1.10`). | `127.0.0.1` |
|
||||
| **Port** | The port the app connects to. | `8791` |
|
||||
| **Push backend** | How offline notifications are delivered: `ntfy` (default, stays on your own infrastructure) or `fcm` (Google). See [Part 5](#part-5--push-notifications-optional). | `ntfy` |
|
||||
|
||||
When it finishes it prints two things you need for the app:
|
||||
|
||||
- **Server URL** — e.g. `http://192.168.1.10:8791`
|
||||
- **Pairing QR + URL** — an `iris://pair?…` string with a scannable QR code
|
||||
|
||||
Then start the gateway:
|
||||
|
||||
```bash
|
||||
hermes gateway # (or: hermes gateway restart after changes)
|
||||
```
|
||||
|
||||
## Part 3 — Install the app
|
||||
|
||||
### Android
|
||||
|
||||
Build a debug APK on any machine with JDK 17 + the Android SDK:
|
||||
|
||||
```bash
|
||||
cd app
|
||||
./gradlew :androidApp:assembleDebug
|
||||
# → app/androidApp/build/outputs/apk/debug/androidApp-debug.apk
|
||||
```
|
||||
|
||||
Copy the APK to the phone (cable, LAN share, or any file transfer) and open
|
||||
it — Android will ask to allow installs from unknown sources.
|
||||
|
||||
*Shortcut for developers with a USB-connected phone:*
|
||||
`./gradlew :androidApp:installDebug` installs it directly.
|
||||
|
||||
### Desktop
|
||||
|
||||
```bash
|
||||
cd app
|
||||
./gradlew :desktopApp:jpackage # → app/desktopApp/build/…/ (native app, JRE bundled)
|
||||
```
|
||||
|
||||
On Linux the launcher may print a `pure virtual method called` warning —
|
||||
it's a known, harmless jpackage bug (JDK-8348560); the app works fine.
|
||||
|
||||
## Part 4 — Connect the app
|
||||
|
||||
Open the app. The first screen is **Connect**. You need the **Server URL**
|
||||
and the **pairing token** from Part 2.
|
||||
|
||||
### Option A — Same home network (no encryption, simplest)
|
||||
|
||||
Works out of the box on a trusted home network:
|
||||
|
||||
1. **Server URL:** the one printed by `hermes gateway setup`,
|
||||
e.g. `http://192.168.1.10:8791`.
|
||||
- On a phone, use the gateway's **LAN IP** — not `127.0.0.1` (that only
|
||||
means "this device" and won't reach your server).
|
||||
- If you set the host to `127.0.0.1` during setup, re-run
|
||||
`hermes gateway setup` and enter the LAN IP instead.
|
||||
2. **Pairing token:** the long token from the setup output (or
|
||||
`grep IRIS_TOKEN ~/.hermes/.env` on the gateway host).
|
||||
3. **Test & Connect.**
|
||||
|
||||
> **Android shortcut:** the Connect screen has a **Scan QR** button — point
|
||||
> the camera at the QR printed by `hermes gateway setup` and the URL + token
|
||||
> fill themselves in. (Desktop has no camera, so it's manual entry.)
|
||||
|
||||
### Option B — Encrypted (TLS) — recommended for anything beyond your LAN
|
||||
|
||||
Plain `http://` is fine on a home network you trust, but for remote access
|
||||
you want the traffic encrypted. The gateway can serve `https://` itself:
|
||||
|
||||
1. Create a certificate + key. Two flavors:
|
||||
- **CA-signed** (Let's Encrypt, or your own CA): works out of the box.
|
||||
- **Self-signed** (e.g. `openssl req -x509 -newkey rsa:2048 -nodes
|
||||
-keyout iris.key -out iris.crt -days 3650 -subj "/CN=iris"
|
||||
-addext "subjectAltName=DNS:iris.example.com,IP:192.168.1.10"`):
|
||||
the certificate **must** carry a SAN entry matching the host you'll
|
||||
type in the app.
|
||||
2. Put the paths in `~/.hermes/.env` on the gateway host:
|
||||
|
||||
```ini
|
||||
IRIS_HTTP_CERT=/path/to/iris.crt
|
||||
IRIS_HTTP_KEY=/path/to/iris.key
|
||||
```
|
||||
|
||||
3. `hermes gateway restart`.
|
||||
4. In the app, use the **`https://`** URL, e.g. `https://iris.example.com:8791`.
|
||||
|
||||
**Self-signed certificates:** the app won't trust them automatically (by
|
||||
design). On first connect it shows the certificate's SHA-256 fingerprint and
|
||||
asks you to confirm it — exactly like an SSH host key. Compare the
|
||||
fingerprint with the one on the gateway host
|
||||
(`openssl x509 -fingerprint -sha256 -noout -in iris.crt`), confirm, and it's
|
||||
pinned in the app's secure storage from then on. If the certificate ever
|
||||
changes, you'll be asked to confirm again. No system trust-store installs
|
||||
needed.
|
||||
|
||||
### Reaching the gateway from outside your home network
|
||||
|
||||
Pick one (in order of preference):
|
||||
|
||||
- **Tailscale / WireGuard (recommended).** Install Tailscale on the gateway
|
||||
host; the app connects to the stable tailnet IP, e.g.
|
||||
`http://100.x.y.z:8791`. No public exposure at all — and since the traffic
|
||||
travels inside the encrypted mesh, plain `http://` is acceptable here.
|
||||
- **Reverse proxy / tunnel** (Caddy, Cloudflare Tunnel, ngrok). Terminate TLS
|
||||
at the edge and forward to `127.0.0.1:8791` on the gateway host.
|
||||
- **Public bind + TLS + strong token** (`IRIS_HTTP_HOST=0.0.0.0` + Option B).
|
||||
Last resort — the port is then reachable from the internet; the token and
|
||||
TLS are what protect it.
|
||||
|
||||
## Part 5 — Push notifications (optional)
|
||||
|
||||
Push wakes a backgrounded or offline phone so you see replies even when the
|
||||
app is closed. Nothing is lost either way — on reconnect the app syncs its
|
||||
outbox.
|
||||
|
||||
- **ntfy (default)** — the phone generates its own topic automatically; the
|
||||
gateway publishes to it. Set `NTFY_SERVER_URL` to a **self-hosted ntfy**
|
||||
for reliability (the public `ntfy.sh` SSE endpoint is flaky). Push metadata
|
||||
stays on your own infrastructure — this is the private option.
|
||||
- **FCM (opt-in, `IRIS_PUSH_BACKEND=fcm`)** — standard and reliable, but push
|
||||
metadata (notification title, device token) is routed through **Google's
|
||||
servers**. Needs a Firebase project + `google-services.json` in the app
|
||||
build. Without it, FCM is inert and ntfy is the path.
|
||||
|
||||
Details: [`08-push.md`](08-push.md).
|
||||
|
||||
---
|
||||
|
||||
## Gateway options (reference)
|
||||
|
||||
Everything is configured in `~/.hermes/.env` on the gateway host (or via the
|
||||
prompts of `hermes gateway setup`). After changes: `hermes gateway restart`.
|
||||
|
||||
| Variable | What it does | Default |
|
||||
| --- | --- | --- |
|
||||
| `IRIS_TOKEN` | Pairing token the app must present. | — (required) |
|
||||
| `IRIS_HTTP_HOST` | Bind address. `127.0.0.1` = local only; LAN IP = same network; `0.0.0.0` = all interfaces. | `127.0.0.1` |
|
||||
| `IRIS_HTTP_PORT` | Port the app connects to. | `8791` |
|
||||
| `IRIS_HOME_CHANNEL` | Default chat for cron/notification delivery. | `default` |
|
||||
| `IRIS_ALLOWED_USERS` | Comma-separated device ids allowed to connect (empty = token-only auth). | empty |
|
||||
| `IRIS_ALLOW_ALL_USERS` | Allow any paired device (**dev only**). | `false` |
|
||||
| `IRIS_PUSH_BACKEND` | `ntfy` or `fcm`. | `ntfy` |
|
||||
| `IRIS_FCM_SERVICE_ACCOUNT` | Path to Firebase service-account JSON (FCM). | — |
|
||||
| `IRIS_FCM_SERVER_KEY` | Legacy FCM server key (fallback). | — |
|
||||
| `NTFY_SERVER_URL` | ntfy server. Self-hosting recommended. | `https://ntfy.sh` |
|
||||
| `NTFY_AUTH_TOKEN` | Auth token for a private ntfy topic (real trust boundary). | — |
|
||||
| `IRIS_HTTP_CERT` / `IRIS_HTTP_KEY` | TLS cert/key paths → serves `https://` (see Part 4, Option B). | — |
|
||||
|
||||
Security model (tokens, device allowlist, transport):
|
||||
[`09-pairing-security.md`](09-pairing-security.md).
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Likely cause / fix |
|
||||
| --- | --- |
|
||||
| `auth failed` on connect | Wrong token. Check `IRIS_TOKEN` in `~/.hermes/.env` (setup prints it only when it generates it). |
|
||||
| Connection refused | Gateway not running (`hermes gateway status`); wrong URL (port `8791`, LAN IP instead of `127.0.0.1` from a phone); firewall blocking the port. |
|
||||
| Phone can't reach the gateway | Gateway bound to `127.0.0.1` — re-run `hermes gateway setup` and set the LAN IP; or the phone is on a different network/VLAN. |
|
||||
| TLS handshake fails | Cert has no SAN matching the URL host; or the pinned fingerprint is stale after a cert change (re-confirm in the app). |
|
||||
| Push not arriving | Backend not configured (check `~/.hermes/logs/gateway.log`); ntfy.sh flakiness — self-host ntfy. |
|
||||
| Start over on a phone | `adb shell pm clear dev.iris.app` wipes the app's pairing state. |
|
||||
|
||||
Logs: `~/.hermes/logs/gateway.log` or `hermes logs --follow`.
|
||||
Reference in new issue
Block a user