# Pathrule Pattern: Nginx and Reverse Proxy Operations (1.0.0)
# ::pathrule:package:nginx-reverse-proxy

### [RULE] Rebuild forwarding headers from trusted connection data  (path: /deploy/nginx)
<!-- scope: folder | priority: high | strict -->

Headers such as Forwarded and X-Forwarded-For arrive from untrusted clients unless the edge proxy replaces them. Passing them through unchanged lets callers spoof scheme, host, or client address.

- Set the upstream Host and public scheme from approved server configuration or trusted connection variables instead of accepting arbitrary client forwarding values.
- Replace or construct the first forwarding hop at the public edge, then append only inside a documented trusted proxy chain.
- Configure real-client address processing with explicit trusted proxy networks; never trust every source merely because Nginx is behind another network layer.
- Test direct, edge, and internal ingress paths and confirm the application derives the same canonical origin and an attributable client chain.

See /tests/proxy for the adjacent decision or procedure that completes this constraint.

---

### [RULE] Set body, header, timeout, and connection limits by route  (path: /deploy/nginx)
<!-- scope: folder | priority: high | strict -->

Proxy defaults and copied global values rarely match uploads, ordinary APIs, health checks, or long-lived streams. Overly small limits break valid traffic, while overly large ones tie up memory and connections under abuse or dependency failure.

- Set request-body limits for the endpoint and reject oversized uploads before proxying where possible; align the application and storage limits with the same contract.
- Separate connect, header, read, and send timeouts so a failed dial is not treated like a legitimate long-lived response.
- Apply request and response header limits that support required cookies and tracing without allowing unbounded metadata.
- Size upstream keep-alive connections and worker limits against application capacity and file descriptors; the proxy must not create more concurrency than the service can drain.

See /ops/runbooks for the adjacent decision or procedure that completes this constraint.

---

### [RULE] Retry only operations proven safe to repeat  (path: /deploy/nginx)
<!-- scope: folder | priority: high | strict -->

A proxy can fail over after an upstream timeout or connection error, but it may not know whether the first service already committed a state change. Blind retry turns one client action into two effects.

- Allow automatic retry for idempotent reads only under explicitly chosen failure conditions and attempt limits.
- Do not retry a state-changing request unless the application contract uses an idempotency key and the body can be replayed safely.
- Distinguish failure before a connection or request write from failure after the upstream may have processed it; ambiguous outcomes need reconciliation, not optimistic success.
- Expose upstream address, status, response time, and retry count in structured access logs without recording secrets or full sensitive payloads.

See /ops/runbooks for the adjacent decision or procedure that completes this constraint.

---

### [MEMORY] Buffering is an endpoint-level latency decision  (path: /deploy/nginx)

Nginx buffering protects upstreams from slow clients and improves throughput for ordinary responses, but it can delay server-sent events, incremental rendering, and other streaming protocols until enough data accumulates.

- Classify endpoints as buffered request-response, large upload, download, server-sent stream, or upgraded connection and configure each location deliberately.
- For streaming responses, disable response buffering where required and ensure the upstream emits flushable chunks and anti-buffering headers understood by the deployment.
- For large request bodies, decide whether Nginx should spool before contacting the application or stream directly, accounting for retry and temporary-disk behavior.
- Load-test with slow clients because disabling buffering can transfer connection and backpressure cost from the proxy to the application.

See /tests/proxy for the rule or workflow that puts this decision into practice.

---

### [MEMORY] A WebSocket upgrade is a hop-by-hop contract  (path: /deploy/nginx)

Connection and Upgrade headers are hop-by-hop and are not forwarded like ordinary end-to-end headers. A successful HTTP route can therefore fail only when the client attempts a protocol upgrade.

- Set the upstream HTTP version and forward Upgrade and Connection values through a controlled mapping rather than copying arbitrary client connection tokens.
- Choose idle timeout and liveness behavior from the application's heartbeat contract so healthy quiet sessions are not closed unexpectedly.
- Preserve authentication and origin validation at the application handshake; the proxy upgrade does not make the browser connection trusted.
- Expose active upgraded connections, close codes where observable, upstream resets, and reconnect rates so connection churn is not hidden inside generic 5xx metrics.

See /ops/runbooks for the rule or workflow that puts this decision into practice.

---

### [SKILL] validate-nginx-change  (path: /)

---
name: validate-nginx-change
description: Validate an Nginx routing, header, timeout, TLS, buffering, or upstream change.
---

# Validate Nginx Change

Run this procedure when the affected surface changes, before the result is promoted to production. Record evidence for every step instead of accepting a plausible-looking result.

- [ ] Render the exact production configuration with secrets redacted, inspect included files, and run the Nginx configuration test in the target image or host environment.
- [ ] Probe ordinary, malformed, oversized, streaming, upgraded, and upstream-failure requests through the same ingress path clients use.
- [ ] Record active connections and baseline error and latency signals, then perform a graceful reload rather than terminating workers with live traffic.
- [ ] Verify new workers accepted the configuration and old workers drain; watch upstream status, retry count, connection errors, and response latency.
- [ ] If any acceptance signal regresses, restore the prior rendered configuration, test it, reload again, and preserve the failed config and evidence for diagnosis.

## Exit criteria

The change is complete only when the expected behavior, failure behavior, and rollback path have all been exercised with representative data. Preserve the evidence with the change so the next operator can repeat the same checks.
