Adds an OpenSpec change scoping the relocation of BRouter from the co-located flagship (cx23, 4 GB RAM, 40 GB SSD, Europe segments only) to a dedicated Hetzner Robot host in the same datacenter, with private connectivity over Hetzner vSwitch #80672 (VLAN 4000). This first PR only lays the network prerequisite: - Terraform: a Hetzner Cloud Network (10.0.0.0/16) with a cloud subnet (10.0.0.0/24) hosting the flagship at 10.0.0.2, and a vSwitch subnet (10.0.1.0/24) bridged to Robot VLAN 4000. The dedicated host's VLAN sub-interface (10.0.1.10 on enp4s0.4000) is configured out-of-band via netplan and is not Terraform-managed. - lifecycle { ignore_changes = [user_data] } on the flagship server to prevent the Hetzner provider's post-1.45 user_data hash drift from triggering a spurious full-server replacement on unrelated applies. - OpenSpec change with proposal, design, specs (delta for brouter-integration / infrastructure / observability / security-hardening), and tasks; Section 1 (pre-flight) is checked off with operator notes. Verification: ping both directions across the vSwitch is 0% loss, sub-ms latency; dedicated host's VLAN config persists across reboot (verified ~60 s to restore private reachability). Follow-up PRs will land the BRouter host compose project, Planner shared-secret header, CD workflow retarget, observability wiring, and the cutover. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2.5 KiB
2.5 KiB
MODIFIED Requirements
Requirement: BRouter API proxy
The Planner backend SHALL proxy all BRouter API calls. Clients SHALL NOT communicate with BRouter directly. The proxy SHALL attach a X-BRouter-Auth: <token> header to every upstream request using the BROUTER_AUTH_TOKEN environment variable.
Scenario: Proxied route request
- WHEN the routing host client requests a route computation
- THEN the Planner backend forwards the request to BRouter over the configured upstream URL with the
X-BRouter-Authheader set, applies rate limiting, and returns the response
Scenario: Missing auth token at startup
- WHEN the Planner starts in production without
BROUTER_AUTH_TOKENset - THEN the Planner logs a fatal error and refuses to start
Requirement: BRouter Docker deployment
BRouter SHALL run as a Docker container on a dedicated Hetzner host reached over a private Hetzner vSwitch, with planet-wide RD5 segments mounted as a volume. The BRouter container SHALL NOT be exposed on any public network interface.
Scenario: BRouter container starts
- WHEN the
docker compose up -dcommand runs in~trails/brouter/on the dedicated host - THEN the BRouter container is reachable only on the vSwitch-bound IP and can compute routes using the mounted planet-wide RD5 segments
Scenario: Public network isolation
- WHEN a request is sent to the dedicated host's public IP on the BRouter port
- THEN the request is refused at the host firewall or times out; BRouter does not respond
Scenario: JVM memory sizing
- WHEN the BRouter container starts
- THEN the JVM is launched with
-Xmx8g(or equivalent) so that the heap does not exceed 8 GB on the 32 GB host
ADDED Requirements
Requirement: Shared-secret auth on BRouter
The BRouter deployment SHALL require a shared-secret header on every request. Requests without a valid X-BRouter-Auth header SHALL be rejected before reaching the BRouter process.
Scenario: Valid token
- WHEN a request arrives at the BRouter host with the correct
X-BRouter-Authheader - THEN the Caddy sidecar forwards the request to BRouter and returns its response
Scenario: Missing or wrong token
- WHEN a request arrives without an
X-BRouter-Authheader or with an incorrect value - THEN the Caddy sidecar responds with HTTP 403 and does not forward the request to BRouter
Scenario: Token not logged
- WHEN Caddy emits an access log line for a BRouter request
- THEN the
X-BRouter-Authheader value is redacted or omitted from the log line