Skip to content

chore(deploy): version nginx http tuning#451

Merged
thewrz merged 3 commits into
mainfrom
feat/issue-447
Jun 18, 2026
Merged

chore(deploy): version nginx http tuning#451
thewrz merged 3 commits into
mainfrom
feat/issue-447

Conversation

@thewrz

@thewrz thewrz commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add deploy/nginx/tuning.conf as a versioned http-context include installed to /etc/nginx/conf.d/wrzdj-tuning.conf by setup-nginx.sh.
  • Enable gzip for proxied JSON/JS/CSS/SVG/text responses, set global TLS protocol default to TLS 1.2/1.3, and add generous edge limit_req_zone defaults.
  • Apply limit_req to non-SSE API/app proxy locations while keeping the public event stream location explicitly exempt.
  • Align the HTTPS catch-all listener with the app/API ssl http2 listen options to avoid protocol options redefined reload warnings.
  • Update deployment docs to treat the new include as the versioned source for nginx tuning.

Closes #447

Design decisions

  • worker_connections and worker_rlimit_nofile are not in tuning.conf because they are events/main-context directives and nginx rejects them inside /etc/nginx/conf.d http-context includes. The versioned include keeps only directives valid in http{}; full main/events ownership should be a separate deployment change if needed.
  • Edge rate limiting uses $binary_remote_addr at 60r/s with burst=180 nodelay in vhosts. This is intentionally generous for shared venue NATs while still shedding clear floods before they reach FastAPI/slowapi.
  • The SSE stream location has no active limit_req; long-lived EventSource connections stay exempt from edge throttling and keep proxy_buffering off plus the 24h read timeout.
  • Production templates keep the existing listen ... http2 syntax for Ubuntu nginx compatibility. Docker nginx 1.27 reports that syntax as deprecated, but the config test no longer reports the protocol options redefined warning.

Verification

  • bash -n deploy/setup-nginx.sh deploy/setup-user.sh
  • shellcheck deploy/setup-nginx.sh deploy/setup-user.sh
  • Static checks: tuning.conf is tracked/not ignored, has no template variables, has four active non-SSE limit_req directives, and the SSE location has no active limit_req.
  • Dry generation: APP_DOMAIN=app.example.test API_DOMAIN=api.example.test PORT_API=8000 PORT_FRONTEND=3000 ./deploy/setup-nginx.sh in an environment without /etc/nginx/sites-available; confirmed the manual-copy output includes wrzdj-tuning.conf.
  • Containerized nginx syntax test: generated app/API/default vhosts plus logging.conf and tuning.conf, then ran nginx:1.27-alpine nginx -t; syntax passed and no protocol options redefined warning appeared.

Not run live against production: gzip header check, real SSE stream, TLS scan, edge 429 behavior, and full app/API/overlay/upload smoke tests require an installed nginx deployment with real certs and running upstream services.

Summary by CodeRabbit

  • New Features

    • Added edge request rate limiting for API and app routes, while explicitly excluding the long-lived SSE stream from limiting.
    • Enabled HTTP/2 support on the default HTTPS catch-all.
  • Improvements

    • Improved proxied response compression and gzip settings.
    • Strengthened proxy and long-lived connection behavior with tuned timeouts/keepalive and proxy socket keepalive.
  • Documentation

    • Updated the Nginx deployment guide to clarify installed logging/tuning includes, prevent manual edits of the main config, and added maintenance steps for updating configs on a running deployment.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@thewrz, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 40 minutes and 30 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: faf7e52e-75a5-4e6e-9efe-7695d111c858

📥 Commits

Reviewing files that changed from the base of the PR and between 4e6aa4c and 5b38f3a.

📒 Files selected for processing (1)
  • deploy/DEPLOYMENT.md
📝 Walkthrough

Walkthrough

Introduces deploy/nginx/tuning.conf, a new versioned nginx http-context include covering gzip compression, SSE-oriented connection timeouts, proxy upstream timeouts, TLS 1.2/1.3 baseline, and an edge limit_req_zone. The setup-nginx.sh installer is refactored to install tuning.conf alongside logging.conf. The vhost templates (api.conf.template, app.conf.template) apply limit_req at all non-SSE locations, the default catch-all gains HTTP/2, and deployment docs and .gitignore are updated accordingly.

Changes

Nginx http-context tuning rollout

Layer / File(s) Summary
New tuning.conf and gitignore tracking
deploy/nginx/tuning.conf, deploy/nginx/.gitignore
Introduces the full wrzdj-tuning.conf nginx http-context include with gzip compression, SSE-oriented timeouts, proxy upstream defaults, TLS 1.2/1.3 baseline, and the limit_req_zone wrzdj_edge definition. Adds !tuning.conf to .gitignore so it is tracked despite the *.conf ignore pattern.
Edge rate limiting in vhost templates and HTTP/2 on catch-all
deploy/nginx/api.conf.template, deploy/nginx/app.conf.template, deploy/nginx/default.conf.template
Applies limit_req zone=wrzdj_edge burst=180 nodelay to the /uploads/ and / locations in api.conf.template and to the overlay and frontend / locations in app.conf.template; adds an explicit SSE-exemption comment in api.conf.template. Enables ssl http2 on the default catch-all listen 443 directive.
setup-nginx.sh: install_confd_config helper and tuning.conf wiring
deploy/setup-nginx.sh
Extracts a reusable install_confd_config helper, installs tuning.conf as wrzdj-tuning.conf alongside logging.conf, adds a shellcheck suppression for envsubst template variables, and extends the manual-copy fallback path to include tuning.conf.
Initial setup documentation for tuning.conf
deploy/DEPLOYMENT.md
Expands the setup-nginx.sh description to cover logging/tuning include installation to /etc/nginx/conf.d/ and vhost config placement to /etc/nginx/sites-available/, adds a note that /etc/nginx/nginx.conf should not be hand-edited, and removes the prior sed/server_tokens instruction.
Maintenance section for running deployment updates
deploy/DEPLOYMENT.md
Adds a new "Update nginx config on a running deployment" subsection explaining container rebuilds do not affect host nginx, documenting idempotent setup-nginx.sh rerun with nginx -t validation and reload-only-on-success, clarifying tuning.conf scope as an http-context include, and providing post-reload verification commands.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: versioning nginx http-context tuning configuration via the new tuning.conf file.
Linked Issues check ✅ Passed The PR successfully addresses the two primary coding objectives from #447: gzip compression for proxied API responses and edge rate limiting with SSE exemption. Two items are intentionally deferred as documented follow-ups.
Out of Scope Changes check ✅ Passed All changes are directly related to nginx http-context tuning implementation: tuning.conf addition, rate limiting in vhost templates, setup script modifications, and documentation updates. No unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-447

Comment @coderabbitai help to get the list of available commands and usage tips.

@thewrz

thewrz commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

CodeRabbit body-note assessment:

  • INVALID: Docstring Coverage warning / generate docstrings. This PR changes nginx config/templates, deployment docs, and setup shell, not Python/TypeScript APIs where docstrings apply. The repo CI gates for this PR are green, and adding synthetic docstrings would not improve the changed deployment behavior.
  • NITPICK declined: Generate unit tests finishing-touch suggestion. The change is nginx/deployment configuration; existing CI and syntax-sensitive install paths are green, and there was no concrete failing behavior or actionable review thread to pin with a regression test.

@thewrz thewrz marked this pull request as ready for review June 18, 2026 00:16
The new conf.d/wrzdj-tuning.conf is included into the http{} block, but the
base /etc/nginx/nginx.conf (stock Ubuntu, and the live VPS) already declares
gzip, server_tokens, and ssl_protocols there. Repeating them in the include is
a fatal "directive is duplicate" error, so `nginx -t` fails and setup-nginx.sh
skips its reload -- re-running it on a running deployment (or a fresh Ubuntu
install) silently never applies the update.

Drop the three redundant directives from tuning.conf; they are already covered
by lower layers:
- gzip on: kept enabled by the base http block; the include only adds the
  proxied-compression settings (gzip_proxied/gzip_types/...) it leaves
  commented out.
- server_tokens off: already set by the base nginx.conf and the per-vhost
  templates.
- ssl_protocols: pinned to TLS 1.2/1.3 per-vhost by the certbot
  options-ssl-nginx.conf include (server level overrides http level).

Document the live-update procedure (re-run setup-nginx.sh; idempotent,
fail-closed via nginx -t) in DEPLOYMENT.md.

Verified with `nginx -t` against a replica of the live nginx.conf http block
plus a vhost exercising the wrzdj_edge rate-limit zone: before, EXIT 1
("gzip directive is duplicate"); after, test successful.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@thewrz

thewrz commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up: made the http-tuning include installable on an already-live box

While validating the rollout path against the live host (read-only), I hit a blocker: tuning.conf is included into the http{} block, and the live /etc/nginx/nginx.conf (and stock Ubuntu) already declare gzip on, server_tokens off, and ssl_protocols there. nginx rejects the repeats with a fatal "directive is duplicate", so setup-nginx.sh's nginx -t gate fails and the reload is skipped — re-running it on a running deployment (or a fresh install) would silently never apply the update.

Fix: drop the three redundant directives from tuning.conf (each documented inline). They're already covered by lower layers:

  • gzip on — stays enabled by the base http block; the include adds only the proxied-compression settings (gzip_proxied/gzip_types/…) it leaves commented out.
  • server_tokens off — already set by the base + the per-vhost templates.
  • ssl_protocols — pinned to TLS 1.2/1.3 per-vhost by the certbot options-ssl-nginx.conf include (server level overrides http level).

All the actual value of the PR (API/JSON gzip, edge rate-limiting, connection timeouts) is preserved, and the deploy script never has to touch the co-tenant–shared distro nginx.conf.

Verified with nginx -t against a replica of the live nginx.conf http block + a vhost exercising the wrzdj_edge zone: before → EXIT 1 "gzip directive is duplicate"; after → test is successful.

Also added an "Update nginx config on a running deployment" section to DEPLOYMENT.md (re-run setup-nginx.sh; idempotent, fail-closed) with the gzip/429/TLS verification curls.

Two issue items intentionally left as follow-ups: global TLS pin (item #3 — already 1.2/1.3 per-vhost) and worker_connections capacity (item #2 — can't live in an http-include).

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@deploy/DEPLOYMENT.md`:
- Around line 332-335: The `/health` endpoint in the gzip verification curl
command likely returns a response too small to exceed the gzip_min_length
threshold of 1024 bytes set in deploy/nginx/tuning.conf, causing the check to
fail even when gzip is properly configured. Replace the `/health` endpoint with
a larger JSON endpoint that will reliably exceed 1024 bytes (such as a list or
details endpoint), or temporarily reduce the gzip_min_length value in
deploy/nginx/tuning.conf during validation to properly verify that gzip
compression is active.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2a63b36b-e243-4cd7-b5dc-884c42eff646

📥 Commits

Reviewing files that changed from the base of the PR and between 868f88a and 4e6aa4c.

📒 Files selected for processing (2)
  • deploy/DEPLOYMENT.md
  • deploy/nginx/tuning.conf

Comment thread deploy/DEPLOYMENT.md
The post-reload gzip check curled /health with -I (HEAD). /health returns
{"status":"ok"} (16 bytes), far below gzip_min_length (1024), and a HEAD
response has no body for nginx to compress — so the check would never show
Content-Encoding: gzip even when gzip is correctly configured. Use a GET
against /openapi.json (application/json, well over 1024 bytes) and dump
response headers so the verification actually demonstrates compression.

Addresses CodeRabbit review on PR #451.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@thewrz thewrz merged commit 29146b9 into main Jun 18, 2026
11 checks passed
@thewrz thewrz deleted the feat/issue-447 branch June 18, 2026 01:33
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.

chore(deploy): version-control http-context nginx tuning (gzip, capacity, TLS default, edge rate limiting)

1 participant