ipx runs in an Arcane project of its own; docker-compose.yml is a sample (#208)

Production moved from the content project, beside audiobookshelf, immich and
Plex, to a project called ipx, where the frontend and directory of the split
(#207) will join it. The move changed ipx's network, and sign-in through the
tunnel trusts that network's gateway: the new compose file pins the subnet to
192.168.64.0/20 so the gateway stays 192.168.64.1 if the network is remade,
and config.toml's trusted_proxies names it instead of 192.168.16.1. Checked
by sending a forged Access token from a Docker bridge: it reached the token
check and was refused, which only a trusted peer does.

The repo's compose file was a copy of production's that nobody else could
run. It is now a sample: ipx alone, SQLite, folders beside the file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 03:13:00 +00:00
parent fca704f7ff
commit c2cea0fc5b
5 changed files with 35 additions and 35 deletions

View File

@@ -38,7 +38,7 @@ request it forwards through the tunnel, and ipx signs that person in.
enabled = true
bind = "0.0.0.0:8099"
trusted_header = "Cf-Access-Authenticated-User-Email"
trusted_proxies = ["127.0.0.1", "::1", "192.168.16.1"]
trusted_proxies = ["127.0.0.1", "::1", "192.168.64.1"]
access_team = "rays-sdf1.cloudflareaccess.com"
access_aud = "8bfe73dfbc8c548d1cb5dc11c6db6887bcaf4f5144840396f83a620a140e1c4f"
auto_create_users = true
@@ -50,7 +50,7 @@ The last two turn on the token check described under [Verifying Cloudflare's tok
on since 2026-09-19. Both can be read without the dashboard: a request to the site while signed
out is sent to `https://<team domain>/cdn-cgi/access/login/ipodderx.sdf1.net?kid=<AUD tag>&...`.
Restart ipx after editing it: `docker compose -f /mnt/fast/arcane/projects/content/compose.yaml
Restart ipx after editing it: `docker compose -f /mnt/fast/arcane/projects/ipx/compose.yaml
restart ipx`.
### What was missing
@@ -65,22 +65,24 @@ Cloudflare and Authentik were already right. Three things on the ipx side were n
`rays@sdf1.net`. With `auto_create_users` on, the first visit would have made a second, empty
account. `ipx user rename rays rays@sdf1.net` fixed that without losing anything.
### The address to trust, and why it is 192.168.16.1
### The address to trust, and why it is 192.168.64.1
`cloudflared` runs in its own container and reaches ipx through the host's published port. Docker
(iptables firewall backend) masquerades traffic between its bridge networks, so the tunnel's
requests arrive from the **gateway of ipx's own network**, `content_default`:
requests arrive from the **gateway of ipx's own network**, `ipx_default`:
```sh
docker network inspect content_default -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}'
docker network inspect ipx_default -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}'
```
That was measured, not assumed. ipx does not log where a request came from, so the addresses were
read from the kernel's connection table inside the container while the site was open. (`/proc/net/tcp`
lists them in hex.)
If the `content` project's network is ever recreated, its gateway can change. Check it again, and
update `trusted_proxies` to match.
The `ipx` project's compose file pins that network's subnet to `192.168.64.0/20`, so its gateway
stays `192.168.64.1` when the network is recreated. It was `192.168.16.1`, `content_default`'s, while
ipx was part of the `content` project. If the subnet is ever changed, update `trusted_proxies` to
match.
### Names
@@ -176,7 +178,7 @@ itself, with a **Proxy Provider** and an **outpost** that adds `X-authentik-user
**The header is only believed from `trusted_proxies`.** Every other source is ignored, and the
request falls through to a session cookie or the shared token. That is the whole security boundary.
With the tunnel reaching ipx through the host's port, `192.168.16.1` means **any container on Tower
With the tunnel reaching ipx through the host's port, `192.168.64.1` means **any container on Tower
that connects to `192.168.1.130:8099`**, not only `cloudflared`. Machines on the LAN, and Tower
itself, arrive under their own addresses and cannot set the header; the checks above show both
sides. Never list a LAN address or range: anyone there could then send