fix(gateway): forward the real client IP to the backend on every call (last-login IP was the docker addr) #264

Merged
developer merged 2 commits from feature/forward-client-ip into development 2026-07-14 09:38:10 +00:00
Owner

Реальный client IP теперь пробрасывается в backend на каждом вызове (last-login IP в админке был 172.19.0.9 у всех).

Корень

172.19.0.9 = докер-адрес самого gateway (он дёргает backend). Цепочка:

  • caddy → gateway — ок (в проде клиент с публичного IP, caddy ставит XFF, gateway peerIP читает).
  • gateway → backend — дроп: XFF форвардился только для chat/feedback (transcode кладёт ClientIP лишь туда). Все прочие вызовы (в т.ч. profile-fetch, который штампит last_login_ip через StampLastLogin) шли без XFF → backend clientIP(c) = peer = 172.19.0.9.
  • telemetry-лог «http request» IP вообще не писал.

Фикс (узкий)

  • backendclient: WithClientIP/clientIPFromContext (зеркало WithPlatform); do() берёт clientIP из ctx, если явный параметр пуст → ставит X-Forwarded-For.
  • Connect-edge (server.go Execute): ctx = backendclient.WithClientIP(ctx, clientIP) один раз на запрос → XFF на всех downstream-вызовах.
  • backend access-log: добавлен client_ip (c.ClientIP() — теперь резолвит проброшенный XFF).
  • Docs: ARCHITECTURE (gateway↔backend инъекция + edge).

Тесты

  • TestXForwardedForInjection: WithClientIP едет на не-chat вызове (Profile) как XFF; без IP — заголовка нет.
  • Локально: gofmt · build · vet · полный unit gateway+backend — зелёное.

Проверю живьём после раската: last-login IP в админке — реальный, не докерный.

Реальный client IP теперь пробрасывается в backend на **каждом** вызове (last-login IP в админке был `172.19.0.9` у всех). ## Корень `172.19.0.9` = докер-адрес самого gateway (он дёргает backend). Цепочка: - **caddy → gateway** — ок (в проде клиент с публичного IP, caddy ставит XFF, gateway `peerIP` читает). - **gateway → backend** — дроп: XFF форвардился только для chat/feedback (`transcode` кладёт `ClientIP` лишь туда). Все прочие вызовы (в т.ч. profile-fetch, который штампит `last_login_ip` через `StampLastLogin`) шли без XFF → backend `clientIP(c)` = peer = `172.19.0.9`. - telemetry-лог «http request» IP вообще не писал. ## Фикс (узкий) - `backendclient`: `WithClientIP`/`clientIPFromContext` (зеркало `WithPlatform`); `do()` берёт clientIP из ctx, если явный параметр пуст → ставит `X-Forwarded-For`. - Connect-edge (`server.go` Execute): `ctx = backendclient.WithClientIP(ctx, clientIP)` один раз на запрос → XFF на всех downstream-вызовах. - backend access-log: добавлен `client_ip` (`c.ClientIP()` — теперь резолвит проброшенный XFF). - Docs: ARCHITECTURE (gateway↔backend инъекция + edge). ## Тесты - `TestXForwardedForInjection`: `WithClientIP` едет на не-chat вызове (`Profile`) как XFF; без IP — заголовка нет. - Локально: gofmt · build · vet · полный unit gateway+backend — зелёное. Проверю живьём после раската: last-login IP в админке — реальный, не докерный.
developer added 1 commit 2026-07-14 09:23:56 +00:00
fix(gateway): forward the real client IP to the backend on every call
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 12s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m58s
ff55d5de83
The backend recorded 172.19.0.9 — the gateway's own docker connection address — as
the client IP for all users: the account's last-login IP shown in the admin console,
and it never reached the backend access log. The gateway forwarded the client IP as
X-Forwarded-For only on chat/feedback calls; every other backend call (including the
profile fetch that stamps last_login_ip) sent none, so the backend fell back to the
peer address.

Carry the client IP on the request context (WithClientIP, mirroring WithPlatform) and
set it once per request in the Connect edge, so the backend client injects
X-Forwarded-For on every downstream REST call. Also add the resolved client IP to the
backend access log.

Test: WithClientIP rides a non-chat call (Profile) as X-Forwarded-For, and is absent
when no IP is set. Docs updated (ARCHITECTURE gateway↔backend + edge).
owner approved these changes 2026-07-14 09:30:17 +00:00
Dismissed
developer added 1 commit 2026-07-14 09:33:41 +00:00
chore(ansible): pin every host's system timezone to UTC
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Successful in 1m14s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 2m0s
c16008e67a
The tg (bot) VPS came up on Europe/Moscow while the main host is UTC, so host-level
timestamps (journald, file mtimes, cron) sat 3h apart across the fleet. Add a
community.general.timezone task to the common role so every provisioned host is UTC
(idempotent — a no-op on the already-UTC main host). Applied live to the tg host in
the same change; the containerised services run in UTC regardless, so no restart.
developer dismissed owner's review 2026-07-14 09:33:41 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

owner approved these changes 2026-07-14 09:34:55 +00:00
developer merged commit d8d1b06eee into development 2026-07-14 09:38:10 +00:00
developer deleted branch feature/forward-client-ip 2026-07-14 09:38:10 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#264