Files
RustProxy/docs/DOCKER_DISCOVERY.md
2026-10-22 19:20:57 +02:00

107 lines
10 KiB
Markdown

# Docker discovery and generated Vhosts
RustProxy discovers published Docker services through a **separate read-only Docker agent** on each Docker host. The RustProxy core does not need Docker-socket access. The agent observes Docker containers; RustProxy turns enabled assignments into dynamic, ordinary HTTP Vhosts.
## Set up a Docker host
Install the **optional Docker agent on each Linux Docker host**, not on the RustProxy server. It is distributed as a separate `rustproxy-docker-agent` DEB/RPM package and is **not built as FreeBSD `pkg`**. Docker Engine, systemd and access to `/var/run/docker.sock` are required at runtime.
### Option A: prebuilt DEB/RPM (recommended)
After configuring the signed APT/DNF RustProxy repository (see [Installation](INSTALL.md)):
```bash
# Debian / Ubuntu
sudo apt update && sudo apt install rustproxy-docker-agent
# Or on RHEL / Rocky / Alma / Fedora
sudo dnf install rustproxy-docker-agent
```
For offline/local installation use `sudo apt install ./rustproxy-docker-agent_<version>-<release>_amd64.deb` or `sudo dnf install ./rustproxy-docker-agent-<version>-<release>.x86_64.rpm`. The post-install script generates a random token and self-signed TLS certificate on first install, creates a systemd service, and preserves credentials across upgrades. It does not print the token to unattended installation logs.
```bash
sudo rustproxy-docker-agent info # endpoint, TLS fingerprint, validity, token status
sudo rustproxy-docker-agent info --show-token # full secret token: run locally as root
sudo systemctl status rustproxy-docker-agent
```
### Option B: build and install manually (optional)
```bash
cd docker-agent
go test ./...
sudo ./install.sh
```
Go 1.22+ is required only for the manual build, not for a DEB/RPM installation. The manual installer uses the same Go CLI to create credentials and TLS identity and displays the token interactively. Detailed custom systemd setup and migration between manual/package-managed services are in [docker-agent/README.md](../docker-agent/README.md).
### Connect to RustProxy
1. Allow port `9876` **only from the RustProxy server** in the Docker-host firewall. The default example listens on `0.0.0.0:9876`.
2. In **Settings → Docker agents**, create an agent with an endpoint such as `https://10.10.0.21:9876`, its Bearer token and certificate SHA-256 fingerprint, base domain, selected listener IDs, and optional certificate/ACL/default backend IP.
3. Use **Docker vhosts → Refresh agents** and check that discovery succeeds before publishing.
The self-signed certificate is persistent. RustProxy pins its exact fingerprint; if replaced, update the pin. A trusted CA-issued certificate can use normal CA and hostname verification instead. Plain HTTP is available only by explicit opt-out and exposes the token in transit.
To inspect or rotate credentials after installation:
```bash
sudo rustproxy-docker-agent info --json
sudo rustproxy-docker-agent print-fingerprint
sudo rustproxy-docker-agent rotate-token
sudo systemctl restart rustproxy-docker-agent
sudo rustproxy-docker-agent show-token # secret: update it in RustProxy settings
```
A token change invalidates the previous token after service restart. The agent logs certificate details and **redacted** token status at startup. The Docker socket is root-equivalent access; isolate the service account and host even though the HTTP inventory endpoint is read-only.
## What discovery reports
- Running containers with **Docker-published, non-loopback TCP ports**; it does not turn an internal-only container port into a directly reachable service.
- Usable Docker-host interface/IP addresses and each published host binding, allowing an explicit backend address selection when the host has multiple networks.
- Default technical hostname from the Docker container name (including a Compose `container_name` or its generated container name), without image name or port suffix. Existing publications using the previous auto-generated port-suffixed name switch to the container name during reconciliation; manually selected hostnames and aliases are preserved. The agent does not install applications, change Docker network rules or deploy TLS on their behalf.
Agent inventory polling is separate from the panel's live status refresh. A new agent may initially show **WAITING** until the first poll, not a failure. **Refresh agents** requests an immediate agent update. Actual failures report a reason; a temporary agent outage can preserve the last successful inventory while a successful missing-service observation can lead to a generated route returning `503` until the service returns.
## Publish a discovered application
In **Docker vhosts**, select the service and set:
| Option | Guidance |
|---|---|
| **Hostname / aliases** | By default, the sanitized Docker container name expands under the agent base domain, without an image or port suffix. A custom short name or full FQDN overrides it, and aliases remain configurable. Containers exposing multiple published TCP ports require distinct manually assigned hostnames to publish both ports. Configure public DNS separately. |
| **Backend IP/port** | Pick a detected, reachable Docker-host address or the configured automatic option. Docker host/firewall binding must permit RustProxy to connect. |
| **HTTP / HTTPS upstream** | Match the container's actual service protocol; review origin TLS verification and Host behavior. |
| **Frontend listeners / certificate** | Selected through the agent defaults and RustProxy configuration; ensure certificate covers the generated name. |
| **Frontend protocols** | HTTP/1.1 is always available. Enable/disable HTTP/2 and HTTP/3 independently per Docker vhost (both enabled by default). H2/H3 require corresponding frontend listener support; switching them does not change the selected HTTP/HTTPS backend scheme. H3 disabled also removes its advertisement. |
| **Force HTTPS / WebSockets** | Enable only when needed and when the right frontend listeners exist. |
| **Cache / compression / transforms** | Optional; obey the global limits and privacy policy of the application. |
| **Health / ACL / timeouts** | Select up to eight reusable ACL profiles per app or inherit the agent's defaults. A searchable multi-select previews the profile ID, default action, IP rules and country filters; selected profiles appear as removable badges. Optional inline ACL remains independently enforced. Explicit denies and country blocks beat merged allows. Test allowed and blocked clients. |
To deliberately assign a domain not covered by the agent's **named frontend certificate**, enable **Accept certificate/domain mismatch** immediately below **Backend host IP** in the per-service editor and confirm the risk. This records `allow_certificate_mismatch: true` on that publication only. Without consent, the server rejects the incompatible mapping. The client browser may still reject the TLS handshake; a matching SAN certificate is strongly preferred. The agent's own outbound TLS fingerprint validation is unaffected.
Use the per-service **Publish** on/off switch to expose or remove the generated Vhost; toggling it saves immediately. Test the resulting hostname with **Open app**. Edits to an already published service use its own **Apply changes** action; switching Publish off removes the proxy publication but does not stop the Docker container. Hidden rows in the page are only a browser view preference, not a security policy.
### Live HTTP request logs
For each published Docker Vhost, **Live logs** appears directly beside **Open app**. It opens RustProxy's authenticated **Live access logs** dialog with this publication's generated Vhost ID already selected. Logs for every hostname alias of the same publication are shown together. The filter stays selected even when no requests have yet been recorded; you can switch back to **All vhosts** inside the dialog. The action waits until an agent status refresh has provided the server-generated Vhost ID, so it may be disabled briefly immediately after publishing.
These are **HTTP requests processed by RustProxy**, not the application's Docker container stdout/stderr. The viewer uses RustProxy's bounded in-memory live request history; requests appear when completed, not as a container terminal stream. Stored Docker stdout/stderr are not retrieved from the agent. The dialog is administrator-only, and no Docker log-reading endpoint is exposed.
### Per-vhost traffic statistics
Every published vhost on an enabled Docker agent has a **Traffic statistics** disclosure directly below **Configure vhost**. It starts collapsed, uses the same six status/requests/active/errors/latency/traffic-per-second tiles and **Lifetime request rate** chart as an ordinary Vhost, and can be opened individually. The **Expand all statistics / Collapse all statistics** toolbar button toggles every published Docker vhost at once (including rows hidden by search or the local Hide action). The chosen disclosure state survives live list refreshes during the current panel session; it resets on sign-out.
Counters come from RustProxy's generated Vhost metrics, not the Docker agent or just the upstream backend: they include requests handled at the proxy frontend, even those rejected before reaching a backend. The request-rate graph is sampled in the browser from cumulative counters **since the panel session started observing this host**; its history is not stored on disk. Traffic/s is the observed delta of ingress plus egress bytes. Missing metrics show `-`. Live updates follow the administration status stream/polling settings; expanding the statistics does not prevent Docker inventory refreshes.
## Troubleshooting
- **WAITING:** first poll not yet observed; refresh and inspect the agent endpoint.
- **Agent error:** verify firewall, TLS fingerprint/CA, bearer token, service state, advertised host and TCP route.
- **503 generated Vhost:** verify running container, published TCP port, selected IP/bind address, backend protocol and health check.
- **Wrong application hostname:** check base-domain expansion, aliases, DNS and conflicting ordinary Vhosts.
- **Docker service not listed:** agent reports only eligible running containers with published non-loopback TCP bindings.
For agent operations and its security model see `docker-agent/README.md`. For normal routing, health and cache controls see [Vhosts](VHOSTS.md) and [Cache](CACHE.md).