Skip to content

fix: correct real IP header in nginx configs#8981

Closed
717986230 wants to merge 3 commits intomakeplane:previewfrom
717986230:fix-nginx-forwarded-for-header
Closed

fix: correct real IP header in nginx configs#8981
717986230 wants to merge 3 commits intomakeplane:previewfrom
717986230:fix-nginx-forwarded-for-header

Conversation

@717986230
Copy link
Copy Markdown

@717986230 717986230 commented Apr 30, 2026

Summary

Fixes a typo in the nginx real_ip_header directive across the web, admin, and space nginx configs.

Changes

  • Replaces X-Forward-For with the standard X-Forwarded-For header.
  • Updates nginx configs for:
    • apps/web
    • apps/admin
    • apps/space

Why

X-Forward-For is not a standard HTTP header. Using X-Forwarded-For allows nginx to resolve the real client IP correctly when Plane is deployed behind a proxy or load balancer.

Related Issue

Closes #8934

Summary by CodeRabbit

  • Chores
    • Corrected Nginx real client IP header detection configuration across admin, space, and web services to properly identify client addresses when recursive IP resolution is enabled. This change improves the accuracy of rate limiting enforcement, access logging, and IP-based security policies that depend on correct client identification across all applications.

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

📝 Walkthrough

Walkthrough

This PR fixes a typo in three Nginx configuration files, correcting the real_ip_header directive from the non-standard X-Forward-For to the correct HTTP header X-Forwarded-For, enabling proper real client IP detection when deployed behind proxies or load balancers.

Changes

Cohort / File(s) Summary
Nginx Real IP Header Typo Fix
apps/admin/nginx/nginx.conf, apps/space/nginx/nginx.conf, apps/web/nginx/nginx.conf
Corrected real_ip_header directive from X-Forward-For to X-Forwarded-For to enable accurate client IP detection behind proxies, affecting rate limiting and IP logging accuracy.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

Poem

🐰 A typo once hidden in headers so sly,
But this rabbit hopped in to fix on the fly!
From X-Forward-For's myth to the true Forwarded-For,
Real client IPs shine now, forevermore! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: correcting the real IP header in nginx configs.
Description check ✅ Passed The description is mostly complete with a clear summary, detailed changes, rationale, and linked issue, though Type of Change and Test Scenarios sections from the template are missing.
Linked Issues check ✅ Passed All coding requirements from issue #8934 are met: the typo X-Forward-For is corrected to X-Forwarded-For across all three nginx config files (apps/web, apps/admin, apps/space).
Out of Scope Changes check ✅ Passed All changes are directly related to correcting the real IP header typo in nginx configs as specified in issue #8934; no out-of-scope modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/admin/nginx/nginx.conf`:
- Around line 12-15: The nginx configs currently set_real_ip_from 0.0.0.0/0
which trusts all proxies and allows X-Forwarded-For spoofing; replace the
set_real_ip_from entry in the nginx blocks (the set_real_ip_from directive
paired with real_ip_header X-Forwarded-For and real_ip_recursive on) in
apps/admin/nginx/nginx.conf, apps/web/nginx/nginx.conf and
apps/space/nginx/nginx.conf with your trusted proxy CIDR (for docker-compose use
the docker bridge like 172.17.0.0/16 or your ingress subnet) and ensure the same
CIDR is applied consistently across all three files; if your deployment uses
multiple proxy subnets, add multiple set_real_ip_from lines for each trusted
CIDR.

In `@apps/space/nginx/nginx.conf`:
- Around line 12-15: The configuration currently sets set_real_ip_from to
0.0.0.0/0 which allows any client to claim an X-Forwarded-For address and can
bypass IP-based controls; change the set_real_ip_from directive(s) to only
include your trusted ingress/load-balancer CIDR(s) or specific IP(s) (e.g., your
cluster LB CIDR like 10.0.0.0/8 or the specific load balancer IP) so
real_ip_header (X-Forwarded-For) is only trusted from those sources and rate
limiting in limit_req_zone against $binary_remote_addr and zone=mylimit cannot
be spoofed.

In `@apps/web/nginx/nginx.conf`:
- Around line 12-15: The real IP configuration is too permissive: replace the
broad set_real_ip_from 0.0.0.0/0 with only your trusted proxy CIDR(s) (e.g., the
load balancer or CDN networks) so real_ip_header X-Forwarded-For is only trusted
from those sources; update set_real_ip_from entries accordingly (or remove the
directive if no trusted proxies exist) to prevent forged client IPs affecting
limit_req_zone $binary_remote_addr and related rate-limiting logic.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 327116d2-f5c6-4040-b680-6714ad285527

📥 Commits

Reviewing files that changed from the base of the PR and between a62fe8a and eaebe9e.

📒 Files selected for processing (3)
  • apps/admin/nginx/nginx.conf
  • apps/space/nginx/nginx.conf
  • apps/web/nginx/nginx.conf

Comment on lines 12 to 15
set_real_ip_from 0.0.0.0/0;
real_ip_recursive on;
real_ip_header X-Forward-For;
real_ip_header X-Forwarded-For;
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify where permissive real_ip trust is still configured
rg -nP '^\s*set_real_ip_from\s+0\.0\.0\.0/0;' apps
rg -n -C2 'set_real_ip_from|real_ip_header|real_ip_recursive|limit_req_zone' apps/**/nginx/nginx.conf

Repository: makeplane/plane

Length of output: 1760


🏁 Script executed:

# Search for deployment/infrastructure configuration
find . -type f \( -name "docker-compose*.yml" -o -name "Dockerfile*" -o -name "*.yaml" -o -name "*.yml" \) ! -path "*/node_modules/*" ! -path "*/.git/*" | head -20

# Check for any comments or documentation about nginx proxy setup
rg -n "set_real_ip_from|proxy_pass|trusted.*proxy|ingress" --type yaml --type yml -A 2 -B 2

# Look for kubernetes or helm configs
find . -type d \( -name "k8s" -o -name "kubernetes" -o -name "helm" -o -name "charts" \) 2>/dev/null

Repository: makeplane/plane

Length of output: 889


🏁 Script executed:

# Explore kubernetes deployment structure
find ./deployments/kubernetes -type f -name "*.yaml" -o -name "*.yml" | head -20

# Check for docker-compose
find . -maxdepth 3 -name "docker-compose*.y*ml" -o -name "compose*.y*ml"

# Look for ingress controller config
rg -n "kind:\s*Ingress|apiVersion" ./deployments/kubernetes/ -A 3

# Check if there's documentation about deployment
find . -maxdepth 2 -type f \( -name "README*" -o -name "DEPLOYMENT*" -o -name "ARCHITECTURE*" \)

Repository: makeplane/plane

Length of output: 119


🏁 Script executed:

# Check docker-compose to see how services are networked
head -100 ./docker-compose.yml

# Check if README mentions nginx or deployment architecture
rg -n "nginx|proxy|ingress|deploy" ./README.md -i -A 2 -B 1

# Look at kubernetes service definitions to understand traffic flow
find ./deployments/kubernetes -type f \( -name "*.yaml" -o -name "*.yml" \) | xargs grep -l "kind.*Service\|kind.*Ingress" 2>/dev/null | head -5

Repository: makeplane/plane

Length of output: 2426


🏁 Script executed:

# Get port mappings from docker-compose
rg -n "ports:" ./docker-compose.yml -A 5

# Check one Dockerfile to see how nginx is configured
head -50 ./apps/web/Dockerfile.web

# Look at kubernetes services to understand traffic ingress
find ./deployments/kubernetes -type f -name "*.yaml" -o -name "*.yml" | xargs grep -l "Service\|Ingress" | head -3

Repository: makeplane/plane

Length of output: 2062


🏁 Script executed:

# Check the full Dockerfile.web, especially final stage
tail -100 ./apps/web/Dockerfile.web

# Search for nginx references in Dockerfiles
rg -n "nginx" ./apps/web/Dockerfile.web ./apps/admin/Dockerfile.admin ./apps/space/Dockerfile.space

# Check if there's a proxy service in docker-compose
rg -n "proxy:" ./docker-compose.yml -A 20

# Check the entrypoint or cmd for web service
rg -n "CMD\|ENTRYPOINT\|entrypoint\|command:" ./apps/web/Dockerfile.web

Repository: makeplane/plane

Length of output: 4150


🏁 Script executed:

# Check proxy Dockerfile to understand traffic forwarding
head -150 ./apps/proxy/Dockerfile.ce

# Check if there's nginx config in proxy
find ./apps/proxy -name "nginx.conf" -o -name "*.conf"

# Look at kubernetes deployment to see if architecture differs
ls -la ./deployments/kubernetes/

Repository: makeplane/plane

Length of output: 692


🏁 Script executed:

# Check Caddyfile configuration
cat ./apps/proxy/Caddyfile.ce

# Check kubernetes structure
find ./deployments/kubernetes/community -type f | head -20

Repository: makeplane/plane

Length of output: 871


🏁 Script executed:

# Check kubernetes README and deployment structure
cat ./deployments/kubernetes/community/README.md

# List kubernetes manifest files
find ./deployments/kubernetes/community -type f -name "*.yaml" -o -name "*.yml" | sort

Repository: makeplane/plane

Length of output: 316


🏁 Script executed:

# List all kubernetes files in community directory
find ./deployments/kubernetes/community -type f -not -path "*/\.*"

# Check if there are any actual k8s manifests beyond README
ls -la ./deployments/kubernetes/community/

Repository: makeplane/plane

Length of output: 271


Restrict trusted proxy CIDRs in all nginx configs (web, admin, space).

This configuration appears in three files (apps/web/nginx/nginx.conf, apps/admin/nginx/nginx.conf, and apps/space/nginx/nginx.conf). All currently trust X-Forwarded-For from 0.0.0.0/0, enabling clients to spoof source IPs and weakening per-client rate limiting.

In the docker-compose deployment, these nginx services are behind Caddy and not directly exposed, but should still restrict to the internal docker network range. In production deployments, this becomes critical.

Replace set_real_ip_from 0.0.0.0/0; with the actual trusted proxy CIDR (e.g., 172.17.0.0/16 for docker bridge network, or your specific ingress/proxy subnet):

-  set_real_ip_from        0.0.0.0/0;
+  set_real_ip_from        <trusted_proxy_cidr>;
   real_ip_recursive       on;
   real_ip_header          X-Forwarded-For;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/admin/nginx/nginx.conf` around lines 12 - 15, The nginx configs
currently set_real_ip_from 0.0.0.0/0 which trusts all proxies and allows
X-Forwarded-For spoofing; replace the set_real_ip_from entry in the nginx blocks
(the set_real_ip_from directive paired with real_ip_header X-Forwarded-For and
real_ip_recursive on) in apps/admin/nginx/nginx.conf, apps/web/nginx/nginx.conf
and apps/space/nginx/nginx.conf with your trusted proxy CIDR (for docker-compose
use the docker bridge like 172.17.0.0/16 or your ingress subnet) and ensure the
same CIDR is applied consistently across all three files; if your deployment
uses multiple proxy subnets, add multiple set_real_ip_from lines for each
trusted CIDR.

Comment on lines 12 to 15
set_real_ip_from 0.0.0.0/0;
real_ip_recursive on;
real_ip_header X-Forward-For;
real_ip_header X-Forwarded-For;
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n apps/space/nginx/nginx.conf | head -30

Repository: makeplane/plane

Length of output: 817


Restrict set_real_ip_from to only trusted sources to prevent IP spoofing.

Line 12's 0.0.0.0/0 allows any source to spoof the X-Forwarded-For header (line 14), bypassing rate limiting on line 15 and any IP-based security controls. Narrow this to only your ingress controller or load balancer CIDR (e.g., 10.0.0.0/8, 172.16.0.0/12, or a specific IP).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/space/nginx/nginx.conf` around lines 12 - 15, The configuration
currently sets set_real_ip_from to 0.0.0.0/0 which allows any client to claim an
X-Forwarded-For address and can bypass IP-based controls; change the
set_real_ip_from directive(s) to only include your trusted ingress/load-balancer
CIDR(s) or specific IP(s) (e.g., your cluster LB CIDR like 10.0.0.0/8 or the
specific load balancer IP) so real_ip_header (X-Forwarded-For) is only trusted
from those sources and rate limiting in limit_req_zone against
$binary_remote_addr and zone=mylimit cannot be spoofed.

Comment thread apps/web/nginx/nginx.conf
Comment on lines 12 to 15
set_real_ip_from 0.0.0.0/0;
real_ip_recursive on;
real_ip_header X-Forward-For;
real_ip_header X-Forwarded-For;
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Same trust-boundary issue exists here with real IP handling.

Line 12 (set_real_ip_from 0.0.0.0/0) is overly permissive. Combined with Line 14 (X-Forwarded-For), this can allow forged client IPs unless only trusted proxy networks can reach this service.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/nginx/nginx.conf` around lines 12 - 15, The real IP configuration is
too permissive: replace the broad set_real_ip_from 0.0.0.0/0 with only your
trusted proxy CIDR(s) (e.g., the load balancer or CDN networks) so
real_ip_header X-Forwarded-For is only trusted from those sources; update
set_real_ip_from entries accordingly (or remove the directive if no trusted
proxies exist) to prevent forged client IPs affecting limit_req_zone
$binary_remote_addr and related rate-limiting logic.

@sriramveeraghanta
Copy link
Copy Markdown
Member

This PR #8935 already resolves this.

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.

[bug]: real_ip_header directive has typo X-Forward-For instead of X-Forwarded-For in nginx configs

3 participants