Files
hermes-webui/docs/remote-access.md
T

237 lines
9.6 KiB
Markdown

# Remote access
How to reach a self-hosted Hermes WebUI from another machine or your phone.
## Accessing from a remote machine
The server binds to `127.0.0.1` by default (loopback only). If you are running
Hermes on a VPS or remote server, use an SSH tunnel from your local machine:
```bash
ssh -N -L <local-port>:127.0.0.1:<remote-port> <user>@<server-host>
```
Example:
```bash
ssh -N -L 8787:127.0.0.1:8787 user@your.server.com
```
Then open `http://localhost:8787` in your local browser.
`start.sh` will print this command for you automatically when it detects you
are running over SSH.
---
## Accessing on your phone with Tailscale
[Tailscale](https://tailscale.com) is a zero-config mesh VPN built on
WireGuard. Install it on your server and your phone, and they join the same
private network -- no port forwarding, no SSH tunnels, no public exposure.
The Hermes Web UI is fully responsive with a mobile-optimized layout
(hamburger sidebar, sidebar top tabs in the drawer, touch-friendly controls),
so it works well as a daily-driver agent interface from your phone.
### Preferred on a single-operator or access-restricted tailnet: Tailscale Serve
[Tailscale Serve](https://tailscale.com/docs/features/tailscale-serve) exposes
the WebUI at a tailnet-only HTTPS/MagicDNS URL while Hermes keeps listening on
`127.0.0.1`. Serve owns the network front door; continue launching Hermes
WebUI through the maintained `start.sh` or systemd path.
Hermes currently sees every Serve login request as coming from the local proxy,
so password and passkey logins share one five-attempt, 60-second rate-limit
bucket across all clients. Use this path for a single operator, or restrict
access to the Serve node to the intended operator with [tailnet access-control
rules](https://tailscale.com/docs/features/access-control). On a broader
multi-user tailnet, use the SSH tunnel above or the direct-IP fallback below
until Hermes can safely attribute login attempts per Serve client. If the
shared bucket is reached, wait 60 seconds before trying again.
1. Install [Tailscale](https://tailscale.com/download) on your server and
your iPhone/Android.
2. Before publishing anything, enable application authentication. Prefer
configuring a strong password through Settings while reaching WebUI only
over loopback or an SSH tunnel; Settings stores a password hash rather than
a plaintext password. Keep the Serve cookie setting in the checkout's
owner-only `.env`:
```bash
umask 077
touch .env
chmod 600 .env
```
```dotenv
HERMES_WEBUI_SECURE=1
```
If Settings is unavailable, the same owner-only file can carry the password:
```dotenv
HERMES_WEBUI_PASSWORD='replace-with-a-long-random-password'
HERMES_WEBUI_SECURE=1
```
`start.sh` sources `.env` as shell syntax. Keep the password single-quoted
and do not use a literal single quote in this path; use Settings for an
arbitrary generated password. Serve terminates HTTPS before proxying to the
local HTTP backend, so `HERMES_WEBUI_SECURE=1` keeps the session cookie
HTTPS-only.
3. Restart WebUI through the same lifecycle owner that already manages it. A
process listening on `0.0.0.0:8787` also answers the loopback health probe,
so `start.sh` would otherwise report "already running" without applying the
new host or reloading `HERMES_WEBUI_SECURE=1`.
For a daemon started by `ctl.sh`, keep ownership with the controller:
```bash
./ctl.sh stop
./ctl.sh start 8787 --host 127.0.0.1
```
For a direct `start.sh` launch, stop the exact listener using the PID
instructions that `start.sh` prints, verify it has stopped, then run:
```bash
./start.sh 8787 --host 127.0.0.1
```
For a supervisor-managed service, run its matching stop command, update the
configured launch command with `8787 --host 127.0.0.1`, then use the same
owner to start it again:
- systemd: `systemctl --user stop hermes-webui.service`, then
`systemctl --user daemon-reload` and
`systemctl --user start hermes-webui.service`.
- launchd: `launchctl unload ~/Library/LaunchAgents/com.example.hermes-webui.plist`,
then `launchctl load` with the same plist path.
- supervisord: `sudo supervisorctl stop hermes-webui`, then
`sudo supervisorctl reread`, `sudo supervisorctl update`, and
`sudo supervisorctl start hermes-webui`.
- runit: `sv down <service-directory>`, edit
`<service-directory>/run` so its `exec` invokes
`/bin/bash /path/to/hermes-webui/start.sh 8787 --host 127.0.0.1 --foreground`,
then run `sv up <service-directory>`.
- s6: `s6-svc -d <service-directory>`, apply the same `exec` change in
`<service-directory>/run`, then run `s6-svc -u <service-directory>`.
The [supervisor guide](supervisor.md) shows the corresponding launch-command
locations. Do not launch `start.sh` directly while a supervisor owns the
service. For example, a systemd unit uses:
```ini
ExecStart=/bin/bash %h/hermes-webui/start.sh 8787 --host 127.0.0.1 --foreground
```
Keep the password (unless it is already configured through Settings) and
`HERMES_WEBUI_SECURE=1` in the checkout's `.env`; do not rely on systemd
`Environment=` entries to override that later-loaded file. Do not continue
until the selected lifecycle owner reports the new process running.
For a different trusted reverse proxy that sets `X-Forwarded-Proto: https`,
`HERMES_WEBUI_TRUST_FORWARDED_PROTO=1` is the alternative. Keep the explicit
`HERMES_WEBUI_SECURE=1` setting for Tailscale Serve.
4. Open `http://127.0.0.1:8787` locally or through an SSH tunnel and confirm
that an unauthenticated browser receives the login screen. Do not publish
the Serve endpoint until this check succeeds. Use the local HTTP URL only
for this preflight; sign in through the HTTPS Serve URL after publishing.
5. On Linux, allow the unprivileged account that runs WebUI to manage
Tailscale. This is a one-time administrator action:
```bash
sudo tailscale set --operator="$USER"
```
6. As that operator account, publish the loopback service in the background:
```bash
tailscale serve --bg 8787
```
The command prints the tailnet-only HTTPS URL to open on your phone.
Background Serve configuration persists across device reboots and
`tailscale down` / `tailscale up` restarts.
7. Verify the active mapping:
```bash
tailscale serve status
```
To remove all Serve mappings from this device, run:
```bash
tailscale serve reset
```
Serve requires HTTPS support in the tailnet. If it is not enabled yet, the
command can print an interactive consent URL for enabling the prerequisite.
Tailnet encryption and access-control rules narrow exposure, but they do not
replace `HERMES_WEBUI_PASSWORD`.
> **Serve, not Funnel:** Serve is available only inside your tailnet.
> [Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel) is
> public on the internet and is not the recommended path for Hermes WebUI.
For the full CLI and Linux permission contracts, see the official
[`tailscale serve` reference](https://tailscale.com/docs/reference/tailscale-cli/serve)
and [Linux operator permission guide](https://tailscale.com/docs/reference/troubleshooting/linux/linux-operator-permission).
The Simplified Chinese companion tracked in
[#7393](https://github.com/nesquena/hermes-webui/issues/7393) should mirror the
`HERMES_WEBUI_SECURE=1` Serve requirement when translated.
### Fallback: direct tailnet IP
If Serve is disabled for your tailnet or you cannot configure an operator,
complete the password setup and login-screen check above, bind WebUI to all
interfaces with an explicit launcher override, then access it through the
server's Tailscale IP. Because this fallback uses plain HTTP, change the cookie
setting before restarting WebUI while keeping the password non-empty:
```dotenv
HERMES_WEBUI_PASSWORD='replace-with-a-long-random-password'
HERMES_WEBUI_SECURE=0
```
Stop and restart through the same lifecycle owner described in step 3, changing
that owner's host argument to `0.0.0.0`. For a direct launch only, run:
```bash
./start.sh 8787 --host 0.0.0.0
```
Open `http://<server-tailscale-ip>:8787` in your phone's browser (find the IP
in the Tailscale app or with `tailscale ip -4` on the server).
Never bind Hermes WebUI to `0.0.0.0` without `HERMES_WEBUI_PASSWORD`.
`0.0.0.0` listens on every interface, not only Tailscale, so keep the host
firewall restricted as well. Traffic inside the tailnet is encrypted, but the
application still needs its own authentication boundary. You can add the page
to your home screen for an app-like experience.
### Community field report: ARM64 Android via AVF
A community report in [#2364](https://github.com/nesquena/hermes-webui/issues/2364)
documents Hermes Agent + WebUI running on a mid-range ARM64 Android phone inside
a Debian 12 VM via Android Virtualization Framework (AVF). The reported setup
used a Xiaomi Redmi Note 13 Pro 4G, 3.8 GiB RAM allocated to the VM, 8 visible
CPU cores, Chrome on Android at `localhost:8787`, and cloud-hosted inference.
This is not an official support baseline or provider/model benchmark, but it is
a useful compatibility signal for mobile ARM64 experiments: the WebUI rendered
smoothly in Chrome, ARM64 Debian worked for the agent stack, and the total local
footprint was about 1.7 GB. Practical caveats from the report: first install can
take longer when dependencies compile from source, Android browser tabs may
reload when switching apps, and disabling battery optimization for the terminal
or VM host may be needed for longer-running sessions.
> **Tip:** If using Docker, set `HERMES_WEBUI_HOST=0.0.0.0` in your
> `docker-compose.yml` environment (already the default) and set
> `HERMES_WEBUI_PASSWORD`.
---