Skip to content

fix: Fix worker class and proxy headers in the web entrypoint - #338

Open
Uxío (Uxio0) wants to merge 1 commit into
mainfrom
uxio/pla-1938-deployment-fix-web-entrypoint-worker-class-worker-count-and
Open

fix: Fix worker class and proxy headers in the web entrypoint#338
Uxío (Uxio0) wants to merge 1 commit into
mainfrom
uxio/pla-1938-deployment-fix-web-entrypoint-worker-class-worker-count-and

Conversation

@Uxio0

@Uxio0 Uxío (Uxio0) commented Sep 3, 2026

Copy link
Copy Markdown
Member

Linear: PLA-1938

What was wrong? 👾

Same three things as safe-global/safe-queue-service#260, which ships an identical entrypoint. Full analysis there.

  1. uvicorn.workers.UvicornWorker has been deprecated since uvicorn 0.30 and the module is going away. uvicorn-worker was already a dependency in pyproject.toml, just unused. (The DeprecationWarning is filtered out by default, so this is about the removal, not log noise.)

  2. request.client and the request scheme depended on how the request reached the app. Over a unix socket uvicorn leaves scope["client"] as None, so ProxyHeadersMiddleware never trusted the connection under the default forwarded_allow_ips=127.0.0.1 and dropped both X-Forwarded-For and X-Forwarded-Proto. The same request over the TCP bind got them applied. Since nginx talks to the socket, everything coming through nginx lost the real client and scheme.

  3. The worker count was invisible: it was WEB_CONCURRENCY or 1 through the gunicorn default.

* is the only value that works on a unix socket — the connection reports no peer address to match a trusted host against. Both binds are pod-local and the headers on either come from the nginx sidecar.

How was it fixed? 🎯

exec gunicorn app.main:app \
  -k uvicorn_worker.UvicornWorker \
  -b unix:$DOCKER_SHARED_DIR/uvicorn.socket \
  -b 0.0.0.0:8888 \
  --workers "${WEB_CONCURRENCY:-1}" \
  --forwarded-allow-ips "*"

${WEB_CONCURRENCY:-1} keeps the current behaviour, just spelled out.

Verification

Built the image and ran web + nginx from docker-compose.yml:

[INFO] Listening at: unix:/nginx/uvicorn.socket,http://0.0.0.0:8888 (1)
[INFO] Using worker: uvicorn_worker.UvicornWorker

:8888 serves /health 200 and /api/v1/about1.16.1. Through nginx on :8000: /health, /, /static/favicon.ico and /api/v1/about all 200.

Sending X-Forwarded-Proto: https straight to the unix socket from inside the container, the app now logs the request as https://localhost/health. It logged http:// before.

Out of scope

  • Worker recycling (max-requests): no measured leak to justify it.
  • The taskiq worker entrypoint.
  • The web service in docker-compose.yml uses env_file: .env, whose hosts are localhost, so the container cannot reach db/redis/rabbitmq. .env.docker exists with the right hostnames and is what safe-queue-service uses. Worth a follow-up; I worked around it with a compose override to verify this PR.

uvicorn.workers.UvicornWorker is deprecated since uvicorn 0.30 and the module
is going away. uvicorn-worker was already a dependency but unused, so use its
worker class instead.

Over a unix socket uvicorn leaves scope["client"] as None, so its
ProxyHeadersMiddleware never trusted the connection with the default
forwarded_allow_ips=127.0.0.1 and dropped both X-Forwarded-For and
X-Forwarded-Proto. The same request over the TCP bind got them applied, so
request.client and the scheme depended on whether the request came through
nginx or hit the port directly. "*" is the only value that works on a socket:
the connection reports no peer address to match a trusted host against. Both
binds are pod-local and the headers on either come from the nginx sidecar.

The worker count was already WEB_CONCURRENCY or 1 through the gunicorn default.
Spell it out in the command so it is visible.

Same change as safe-queue-service#260.
@Uxio0
Uxío (Uxio0) requested a review from a team as a code owner September 3, 2026 11:34
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T11:38:03.681441Z 8d5e717 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8d5e7170eb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".

Comment thread docker/web/run_web.sh
-b unix:$DOCKER_SHARED_DIR/uvicorn.socket \
-b 0.0.0.0:8888 \
--workers "${WEB_CONCURRENCY:-1}" \
--forwarded-allow-ips "*"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict proxy trust on the exposed TCP listener

When the TCP listener is reachable directly—as it is via the checked docker-compose.yml mapping 8888:8888—requests bypass nginx and can supply arbitrary forwarding headers. Gunicorn documents * as disabling frontend-IP checking, so the Uvicorn worker will accept a direct caller's X-Forwarded-For and X-Forwarded-Proto, making request.client, the request scheme, and logged URLs attacker-controlled. Remove or isolate the TCP bind, or avoid wildcard trust on any listener reachable by untrusted clients.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant