Files
overlord/README.md
T

565 lines
17 KiB
Markdown
Raw Normal View History

2026-03-05 15:25:52 -06:00
<p align="center">
2026-05-07 21:06:09 -05:00
<img src="https://raw.githubusercontent.com/vxaboveground/Overlord/refs/heads/main/Overlord-Server/public/assets/overlord.png" alt="Overlord" width="280" />
2026-03-05 15:25:52 -06:00
</p>
2026-03-05 00:04:26 -06:00
# Overlord
# [TELEGRAM SERVER JOIN NOW NO EXCUSES WE GIVE SUPPORT AND IT'S FUN](https://t.me/Onimai)
2026-03-05 00:04:26 -06:00
Hello, I made this project for fun.
2026-05-07 21:06:09 -05:00
The server is TypeScript on Node/Bun. The client is Go. Operators talk to the server through a web panel or the Electron desktop app, and agents connect over encrypted WebSockets.
Docker is the easiest way to run it.
2026-03-10 10:02:50 -05:00
---
2026-03-07 11:35:31 +00:00
2026-03-10 10:02:50 -05:00
- [Quick Start (Docker)](#quick-start-docker)
2026-05-07 21:06:09 -05:00
- [Windows](#windows)
- [Linux](#linux)
- [macOS](#macos)
2026-03-10 10:02:50 -05:00
- [No Docker (.bat / .sh)](#no-docker-bat--sh)
- [Production Package Scripts](#production-package-scripts)
2026-05-13 18:30:18 -05:00
- [WebRTC Streaming](#webrtc-streaming)
2026-07-08 20:34:25 -05:00
- [OIDC / SSO Login](#oidc--sso-login)
- [Login Branding](#login-branding)
2026-03-10 10:02:50 -05:00
- [Docker Notes (TLS, reverse proxy, cache)](#docker-notes-tls-reverse-proxy-cache)
2026-03-07 11:35:31 +00:00
2026-03-10 10:02:50 -05:00
---
2026-03-07 11:35:31 +00:00
2026-03-10 10:02:50 -05:00
## Quick Start (Docker)
2026-03-07 11:35:31 +00:00
2026-05-07 21:06:09 -05:00
Pick your OS below. Each section is self-contained: install Docker, get the project, start it.
2026-03-07 11:35:31 +00:00
2026-05-07 21:06:09 -05:00
> Windows and macOS use `docker-compose.windows.yml`. Linux uses the default `docker-compose.yml` (host networking).
2026-05-07 21:06:09 -05:00
After the first start, open `https://localhost:5173`. Default login is `admin` / `admin` unless you set `OVERLORD_USER` / `OVERLORD_PASS`. First startup writes generated secrets to `data/save.json` (inside the container: `/app/data/save.json`) — keep that file private and back it up.
2026-05-07 21:06:09 -05:00
---
2026-03-07 15:14:00 -06:00
2026-03-10 10:02:50 -05:00
### Windows
2026-03-07 15:14:00 -06:00
<details>
2026-05-07 21:06:09 -05:00
<summary>Step-by-step: Windows</summary>
<br>
**1. Install Docker Desktop**
Either from the website:
2026-03-07 15:14:00 -06:00
2026-03-10 10:02:50 -05:00
- https://docs.docker.com/desktop/setup/install/windows-install/
2026-03-07 15:14:00 -06:00
2026-05-07 21:06:09 -05:00
Or with winget:
2026-03-07 15:14:00 -06:00
2026-03-10 10:02:50 -05:00
```powershell
winget install -e --id Docker.DockerDesktop
```
2026-03-05 00:04:26 -06:00
2026-05-07 21:06:09 -05:00
Start Docker Desktop once, then verify:
2026-03-07 16:19:04 -06:00
2026-03-10 10:02:50 -05:00
```powershell
docker --version
docker compose version
```
2026-03-07 16:19:04 -06:00
2026-05-07 21:06:09 -05:00
**2. Get the project**
2026-05-07 21:06:09 -05:00
```powershell
git clone https://github.com/vxaboveground/Overlord.git
cd Overlord
```
**3. Start it**
```powershell
docker compose -f docker-compose.windows.yml up -d
```
2026-05-07 21:06:09 -05:00
**4. Open the panel**
2026-05-07 21:06:09 -05:00
```text
https://localhost:5173
```
2026-05-07 21:06:09 -05:00
**5. Update later**
2026-03-07 16:19:04 -06:00
2026-05-07 21:06:09 -05:00
```powershell
docker compose -f docker-compose.windows.yml down
docker compose -f docker-compose.windows.yml pull
docker compose -f docker-compose.windows.yml up -d
```
2026-03-07 16:19:04 -06:00
2026-05-07 21:06:09 -05:00
**6. Stop**
```powershell
docker compose -f docker-compose.windows.yml down
```
</details>
---
### Linux
<details>
<summary>Step-by-step: Linux (Debian / Ubuntu / Kali)</summary>
<br>
**1. Install Docker**
Official docs: https://docs.docker.com/engine/install/debian/
2026-03-07 16:19:04 -06:00
2026-03-10 10:02:50 -05:00
Set up Docker's apt repository:
2026-03-07 16:19:04 -06:00
2026-03-10 10:02:50 -05:00
```bash
# Add Docker's official GPG key:
2026-03-10 10:02:50 -05:00
sudo apt update
sudo apt install ca-certificates curl
2026-03-10 10:02:50 -05:00
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
2026-03-07 16:19:04 -06:00
# Add the repository to Apt sources:
2026-03-10 10:02:50 -05:00
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
2026-03-10 10:02:50 -05:00
Signed-By: /etc/apt/keyrings/docker.asc
EOF
2026-03-05 00:04:26 -06:00
2026-03-10 10:02:50 -05:00
sudo apt update
```
2026-05-07 21:06:09 -05:00
On a derivative distro (e.g. Kali), replace the codename expansion with the matching Debian codename, e.g. `bookworm`.
2026-03-10 10:02:50 -05:00
2026-05-07 21:06:09 -05:00
Install Docker:
2026-03-10 10:02:50 -05:00
```bash
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
2026-03-10 10:02:50 -05:00
```
2026-05-07 21:06:09 -05:00
Make sure the daemon is running:
2026-03-10 10:02:50 -05:00
```bash
sudo systemctl status docker
2026-03-10 10:02:50 -05:00
```
2026-05-07 21:06:09 -05:00
**2. Grab the compose file**
Make a folder for it, drop in the file, and you're done:
```bash
mkdir overlord && cd overlord
wget https://raw.githubusercontent.com/vxaboveground/Overlord/refs/heads/main/docker-compose.yml
```
No `wget`? Use `curl`:
```bash
mkdir overlord && cd overlord
curl -O https://raw.githubusercontent.com/vxaboveground/Overlord/refs/heads/main/docker-compose.yml
```
**3. Start it**
```bash
docker compose up -d
```
The image is pulled automatically from `ghcr.io/vxaboveground/overlord:latest` on first run.
**4. Open the panel**
```text
https://localhost:5173
or
https://IP:5173
```
**5. Update later**
From the same folder:
```bash
docker compose down
docker compose pull
docker compose up -d
```
**6. Stop**
```bash
docker compose down
```
</details>
2026-05-07 21:06:09 -05:00
---
2026-03-10 10:02:50 -05:00
### macOS
<details>
2026-05-07 21:06:09 -05:00
<summary>Step-by-step: macOS</summary>
<br>
2026-05-07 21:06:09 -05:00
**1. Install Docker Desktop**
Either from the website:
2026-03-10 10:02:50 -05:00
- https://docs.docker.com/desktop/setup/install/mac-install/
2026-05-07 21:06:09 -05:00
Or with Homebrew:
2026-03-10 10:02:50 -05:00
```bash
brew install --cask docker
```
Start Docker Desktop once, then verify:
```bash
docker --version
docker compose version
```
2026-05-07 21:06:09 -05:00
**2. Get the project**
2026-05-07 21:06:09 -05:00
```bash
git clone https://github.com/vxaboveground/Overlord.git
cd Overlord
```
**3. Start it**
macOS uses the same compose file as Windows:
```bash
docker compose -f docker-compose.windows.yml up -d
```
2026-05-07 21:06:09 -05:00
**4. Open the panel**
```text
https://localhost:5173
```
**5. Update later**
```bash
2026-05-07 21:06:09 -05:00
docker compose -f docker-compose.windows.yml down
docker compose -f docker-compose.windows.yml pull
docker compose -f docker-compose.windows.yml up -d
```
**6. Stop**
```bash
docker compose -f docker-compose.windows.yml down
```
</details>
2026-05-07 21:06:09 -05:00
---
2026-03-10 10:02:50 -05:00
## No Docker (.bat / .sh)
2026-05-07 21:06:09 -05:00
If you don't want Docker, use the included scripts.
2026-03-10 10:02:50 -05:00
2026-05-07 21:06:09 -05:00
Prerequisites:
2026-03-10 10:02:50 -05:00
- Bun in PATH
- Go 1.21+ in PATH
### Windows
Development mode (starts server + client):
```bat
2026-06-12 09:14:49 -05:00
scripts\start-dev.bat
2026-03-10 10:02:50 -05:00
```
Production mode (build + run server executable):
```bat
2026-06-12 09:14:49 -05:00
scripts\start-prod.bat
2026-03-10 10:02:50 -05:00
```
Build client binaries (adds client builds to the build queue):
2026-03-10 10:02:50 -05:00
```bat
2026-06-12 09:14:49 -05:00
scripts\build-clients.bat
2026-03-10 10:02:50 -05:00
```
### Linux / macOS
Make scripts executable once:
```bash
2026-06-12 09:14:49 -05:00
chmod +x scripts/*.sh scripts/*.command
2026-03-10 10:02:50 -05:00
```
2026-05-07 21:06:09 -05:00
Development mode (server in background, client in foreground):
2026-03-10 10:02:50 -05:00
```bash
2026-06-12 09:14:49 -05:00
./scripts/start-dev.sh
2026-03-10 10:02:50 -05:00
```
2026-05-07 21:06:09 -05:00
Only server, or only client:
2026-03-10 10:02:50 -05:00
```bash
2026-06-12 09:14:49 -05:00
./scripts/start-dev.sh server
./scripts/start-dev.sh client
2026-03-10 10:02:50 -05:00
```
Production mode:
```bash
2026-06-12 09:14:49 -05:00
./scripts/start-prod.sh
2026-03-10 10:02:50 -05:00
```
2026-05-07 21:06:09 -05:00
---
2026-03-10 10:02:50 -05:00
## Production Package Scripts
Build a production-ready package where the server can still build client binaries at runtime.
Windows:
2026-03-05 00:04:26 -06:00
```bat
2026-06-12 09:14:49 -05:00
scripts\build-prod-package.bat
2026-03-05 00:04:26 -06:00
```
2026-05-07 21:06:09 -05:00
Output: `release/`
Linux / macOS:
2026-03-05 00:04:26 -06:00
```bash
2026-06-12 09:14:49 -05:00
./scripts/build-prod-package.sh
2026-03-05 00:04:26 -06:00
```
2026-05-07 21:06:09 -05:00
Output: `release/prod-package/`
2026-03-05 00:04:26 -06:00
2026-05-07 21:06:09 -05:00
---
2026-03-10 10:02:50 -05:00
2026-05-13 18:30:18 -05:00
## WebRTC Streaming
The remote desktop viewer has a **Transport** dropdown with three modes:
- **Canvas** (default): H.264 / JPEG / block frames over the existing WebSocket, decoded into a `<canvas>`. Highest latency, works anywhere the WS does.
- **WebRTC P2P**: browser ↔ agent direct. The server only relays SDP and ICE candidates over the existing WS — MediaMTX is not involved. Lowest latency. Fails when both sides are behind aggressive symmetric NAT.
- **WebRTC Relayed**: agent publishes to a MediaMTX sidecar via WHIP, browser plays via WHEP. The server proxies signaling so the existing JWT auth + per-client RBAC still apply. Lowest-effort fallback when P2P can't punch through.
### Building agents with WebRTC
WebRTC is **opt-in per agent build**. In the builder UI, tick the **WebRTC** checkbox before clicking Build. Without it, the Pion stack (~6 MB of Go modules) is not compiled in — any WebRTC start attempt from the operator returns `webrtc support not compiled in` and the viewer falls back to Canvas. The Canvas path always works regardless of the build setting.
The build tag (`overlord_webrtc`) is also available if you build agents outside the UI:
```bash
go build -tags overlord_webrtc ./cmd/agent
```
### MediaMTX sidecar
Compose starts an `overlord-mediamtx` service for Relayed mode. It needs:
- Port `8189/udp` and `8189/tcp` reachable from operators (WebRTC ICE traffic). The Windows / macOS compose publishes these; Linux uses host networking and shares the host's interfaces directly.
- No auth config — the Overlord server proxies every WHIP/WHEP request through `/api/webrtc/...` and enforces the existing operator JWT + RBAC there.
If you only ever want P2P, you can comment out the `mediamtx:` service in your compose file — only Relayed mode depends on it.
### LAN / public access
2026-07-12 23:14:29 -05:00
MediaMTX automatically discovers addresses assigned directly to its network interfaces. This covers ordinary Linux host-network and many LAN deployments, but it cannot reliably infer a public address created by NAT, port forwarding, a cloud load balancer, or a reverse proxy. It also cannot discover which public DNS name you intend operators to use.
2026-05-13 18:30:18 -05:00
2026-07-12 23:14:29 -05:00
Before using **WebRTC Relayed** from another machine, make sure MediaMTX advertises an address that both agents and operators can reach:
2026-05-13 18:30:18 -05:00
2026-07-12 23:14:29 -05:00
- **Linux with host networking and no public NAT:** normally nothing is required; MediaMTX sees the host's interfaces automatically.
- **Public server behind NAT, port forwarding, or a cloud public-IP mapping:** set the public IP or a DNS name that resolves to it.
- **Windows / macOS Docker Desktop:** set the host's reachable LAN/public address because automatic interface discovery sees the container network, not necessarily the Docker host.
- **Same-machine testing on Docker Desktop:** retain `127.0.0.1` in the list.
2026-05-13 18:30:18 -05:00
2026-07-12 23:14:29 -05:00
Set `OVERLORD_WEBRTC_ADDITIONAL_HOSTS` as a comma-separated list in the shell or in a `.env` file next to the compose file:
2026-05-13 18:30:18 -05:00
2026-07-12 23:14:29 -05:00
```env
# LAN example
OVERLORD_WEBRTC_ADDITIONAL_HOSTS=192.168.1.42
# Public DNS plus LAN access
OVERLORD_WEBRTC_ADDITIONAL_HOSTS=stream.example.com,192.168.1.42
# Docker Desktop: same host plus other LAN machines
OVERLORD_WEBRTC_ADDITIONAL_HOSTS=127.0.0.1,192.168.1.42
```
Ensure inbound UDP `8189` is forwarded to the MediaMTX host/container; TCP `8189` is the slower fallback. Recreate the sidecar after changing the setting:
```bash
# Linux
docker compose up -d --force-recreate mediamtx
# Windows / macOS Docker Desktop
docker compose -f docker-compose.windows.yml up -d --force-recreate mediamtx
```
To verify the selected route, open `chrome://webrtc-internals` during a relayed stream and confirm that the chosen remote candidate points to the expected server address and preferably uses UDP.
Automatic public-IP discovery is possible with STUN, but it is not a complete replacement for this setting: it can require random UDP ports, does not discover your intended domain, and can fail behind restrictive or symmetric NAT. For predictable production deployments, explicitly setting the reachable IP/domain and forwarding fixed UDP port `8189` is recommended.
2026-05-13 18:30:18 -05:00
### Advanced MediaMTX customization
The compose file passes a minimal set of `MTX_*` environment variables to MediaMTX — enough for Overlord to work. To change anything else (codecs, paths, ICE servers, etc.), either:
- Add more `MTX_*` variables to the `mediamtx` service's `environment:` block (every option in MediaMTX's docs is supported as an env var), or
- Provide a full `mediamtx.yml` via a bind mount:
```yaml
mediamtx:
# ...existing config...
volumes:
- ./mediamtx.yml:/mediamtx.yml:ro
```
Make sure the file exists on the host *before* the container starts — Docker will otherwise auto-create an empty directory at that path and fail with "not a directory".
---
2026-07-08 20:34:25 -05:00
## OIDC / SSO Login
Overlord supports generic OIDC login for homelab identity providers such as Authentik, Authelia, Keycloak, Zitadel, and Dex. Local username/password login stays enabled as a fallback.
Configure your OIDC provider with this redirect URI:
```text
https://YOUR_OVERLORD_HOST/api/oidc/callback
```
Then set the relevant environment variables:
```env
OVERLORD_OIDC_ENABLED=true
OVERLORD_OIDC_LABEL=Sign in with SSO
OVERLORD_OIDC_ISSUER=https://auth.example.com/application/o/overlord/
OVERLORD_OIDC_CLIENT_ID=overlord
OVERLORD_OIDC_CLIENT_SECRET=change-me
OVERLORD_OIDC_REDIRECT_URI=https://overlord.example.com/api/oidc/callback
OVERLORD_OIDC_DEFAULT_ROLE=viewer
OVERLORD_OIDC_ALLOWED_DOMAINS=example.com
OVERLORD_OIDC_ADMIN_GROUPS=overlord-admins
OVERLORD_OIDC_OPERATOR_GROUPS=overlord-operators
OVERLORD_OIDC_VIEWER_GROUPS=overlord-viewers
```
New OIDC users are linked by the provider's `issuer + sub` identity. Email/username linking to an existing local account is disabled by default; enable `OVERLORD_OIDC_ALLOW_EMAIL_LINK=true` only if you trust your provider's verified email claims.
---
## Login Branding
Self-hosted and enterprise deployments can brand the login screen with environment variables:
```env
OVERLORD_LOGIN_BRAND_NAME=Acme SOC
2026-07-08 21:47:57 -05:00
OVERLORD_NAV_BRAND_NAME=Acme Console
OVERLORD_BRAND_ACCENT_COLOR=#14b8a6
2026-07-08 20:34:25 -05:00
OVERLORD_LOGIN_TITLE=Welcome to Acme Overlord
OVERLORD_LOGIN_SUBTITLE=Sign in with your Acme identity
OVERLORD_LOGIN_LOGO_URL=/assets/acme-logo.png
OVERLORD_LOGIN_LOGO_ALT=Acme logo
2026-07-08 21:47:57 -05:00
OVERLORD_NAV_LOGO_URL=/assets/acme-nav-logo.png
OVERLORD_NAV_LOGO_ALT=Acme logo
OVERLORD_LOGIN_HERO_IMAGE_URL=/assets/acme-login.jpg
OVERLORD_LOGIN_HERO_IMAGE_ALT=Acme operations center
OVERLORD_LOGIN_FOOTER_TEXT=Authorized Acme access only
OVERLORD_LOGIN_SUPPORT_TEXT=Need access help?
OVERLORD_LOGIN_SUPPORT_URL=https://help.example.com
2026-07-08 20:34:25 -05:00
OVERLORD_LOGIN_ICON_CLASS=fa-solid fa-shield-halved
```
2026-07-08 21:47:57 -05:00
Logo, hero, and support URLs accept absolute `http(s)` URLs or root-relative paths. If no logo URL is set, the UI uses `OVERLORD_LOGIN_ICON_CLASS`. The same options can also be managed from Settings → Branding.
2026-07-08 20:34:25 -05:00
---
2026-03-10 10:02:50 -05:00
## Docker Notes (TLS, reverse proxy, cache)
2026-05-07 21:06:09 -05:00
Notes on configs and workarounds.
2026-03-10 10:02:50 -05:00
### BuildKit cache for faster rebuilds
2026-05-07 21:06:09 -05:00
`docker-compose.yml` ships with `build.cache_from` and `build.cache_to` pointing at `.docker-cache/buildx`. Local builds reuse it automatically — no extra setup.
2026-03-10 10:02:50 -05:00
### Runtime client build cache
2026-03-05 00:04:26 -06:00
2026-03-10 10:02:50 -05:00
The compose setup uses a persistent volume for runtime client builds:
2026-03-05 00:04:26 -06:00
2026-05-07 21:06:09 -05:00
- Volume: `overlord-client-build-cache`
- Mount: `/app/client-build-cache`
- Env: `OVERLORD_CLIENT_BUILD_CACHE_DIR` (default `/app/client-build-cache`)
2026-03-10 10:02:50 -05:00
### Certbot TLS
2026-05-07 21:06:09 -05:00
To use Let's Encrypt certificates in production Docker:
2026-03-10 10:02:50 -05:00
2026-05-07 21:06:09 -05:00
1. Set `OVERLORD_TLS_CERTBOT_ENABLED=true`
2. Set `OVERLORD_TLS_CERTBOT_DOMAIN=your-domain.com`
3. Mount letsencrypt into the container read-only, e.g. `/etc/letsencrypt:/etc/letsencrypt:ro`
2026-03-10 10:02:50 -05:00
2026-05-07 21:06:09 -05:00
Default cert paths:
2026-03-10 10:02:50 -05:00
2026-05-07 21:06:09 -05:00
```
cert: /etc/letsencrypt/live/<domain>/fullchain.pem
key: /etc/letsencrypt/live/<domain>/privkey.pem
ca: /etc/letsencrypt/live/<domain>/chain.pem
```
2026-03-10 10:02:50 -05:00
2026-05-07 21:06:09 -05:00
Override with:
2026-03-10 10:02:50 -05:00
2026-05-07 21:06:09 -05:00
- `OVERLORD_TLS_CERTBOT_LIVE_PATH`
- `OVERLORD_TLS_CERTBOT_CERT_FILE`
- `OVERLORD_TLS_CERTBOT_KEY_FILE`
- `OVERLORD_TLS_CERTBOT_CA_FILE`
2026-03-10 10:02:50 -05:00
2026-05-07 21:06:09 -05:00
### Reverse proxy TLS offload
2026-03-10 10:02:50 -05:00
2026-05-07 21:06:09 -05:00
If your platform terminates TLS before traffic reaches Overlord (Render, Caddy, nginx, etc.), set:
2026-03-10 10:02:50 -05:00
2026-05-07 21:06:09 -05:00
```
2026-03-13 15:37:18 -05:00
OVERLORD_TLS_OFFLOAD=true
OVERLORD_HEALTHCHECK_URL=http://localhost:5173/health
OVERLORD_PUBLISH_HOST=127.0.0.1
```
2026-05-07 21:06:09 -05:00
When enabled:
2026-03-13 15:37:18 -05:00
2026-05-07 21:06:09 -05:00
- Container serves internal HTTP on `0.0.0.0:$PORT`
- External URL stays `https://...` through your platform proxy
- Health checks should use `http://localhost:$PORT/health` inside the container
- Don't expose the internal container HTTP port directly to the internet
2026-03-13 15:37:18 -05:00
2026-05-13 23:49:17 -05:00
### Source IP behind a domain / reverse proxy
If the dashboard, audit log, or IP bans show all agents as `172.x.x.x` (or some other proxy/bridge IP), something between the agent and Bun is rewriting the source IP. Two independent flags govern this:
- `OVERLORD_TLS_OFFLOAD` — TLS terminates at the proxy; Overlord runs plain HTTP internally.
- `OVERLORD_TRUST_PROXY` — honor `X-Forwarded-For` / `X-Real-IP` / `CF-Connecting-IP` so dashboard/audit/IP-bans see the real client. Auto-enabled when `TLS_OFFLOAD=true`.
Common shapes:
| Setup | `TLS_OFFLOAD` | `TRUST_PROXY` |
|---|---|---|
| Domain, no proxy (Linux host networking; certbot inside Overlord; Cloudflare DNS-only) | `false` | `false` |
| Domain, proxy does TLS (Render, nginx terminating TLS → http upstream) | `true` | auto (`true`) |
| Domain, proxy in front but Overlord still does TLS (Cloudflare orange-cloud Full Strict; nginx with `proxy_pass https://`) | `false` | `true` |
Only enable `OVERLORD_TRUST_PROXY` when a trusted reverse proxy is in front. If Overlord is directly exposed and you enable it, agents can spoof their source IP by sending their own `X-Forwarded-For` header, breaking IP bans and audit accuracy. The upstream proxy also has to be configured to inject the header (Cloudflare does by default; nginx/Caddy/Traefik need explicit directives).
If you're using `docker-compose.windows.yml` or `docker-compose.quickstart.yml` (Docker Desktop bridge networking) with **no** reverse proxy, Docker itself rewrites source IPs to the bridge gateway and there is no header to recover from — `TRUST_PROXY` cannot help. Either switch to Linux host networking or put a real reverse proxy in front.
2026-05-07 21:06:09 -05:00
### Notes
2026-05-07 21:06:09 -05:00
- Keep `HOST=0.0.0.0` inside the container. Limit exposure with `OVERLORD_PUBLISH_HOST`, not the bind host.
- If your `.env` secret/password contains `$`, escape it as `$$` to avoid Docker Compose variable-expansion warnings.