Skip to content

feat: add x-forwarded support#8028

Merged
dancixx merged 3 commits intodevfrom
feat/x-forwarded-access-log
Feb 3, 2026
Merged

feat: add x-forwarded support#8028
dancixx merged 3 commits intodevfrom
feat/x-forwarded-access-log

Conversation

@dancixx
Copy link
Contributor

@dancixx dancixx commented Feb 2, 2026

Testing Forwarded Headers

This document describes how to test the X-Forwarded-For and Forwarded header support in Qdrant access logs.

Configuration

Enable trusted forwarded headers in your config:

service:
  trust_forwarded_headers: true

Or via environment variable:

export QDRANT__SERVICE__TRUST_FORWARDED_HEADERS=true

Warning: Only enable this when Qdrant is behind a trusted reverse proxy or load balancer. Enabling this without a trusted proxy allows clients to spoof their IP address.

Enable gRPC Access Logs

gRPC access logs are disabled by default (trace level). Enable them with:

export QDRANT__LOG_LEVEL=info,qdrant::tonic::logging=trace

Testing Without Load Balancer

Simulate proxy headers directly with curl/grpcurl.

HTTP (REST API)

# Standard Forwarded header (RFC 7239)
curl -H "Forwarded: for=203.0.113.50" http://localhost:6333/collections

# Legacy X-Forwarded-For header
curl -H "X-Forwarded-For: 203.0.113.50" http://localhost:6333/collections

# Multiple proxies (leftmost IP is the original client)
curl -H "X-Forwarded-For: 203.0.113.50, 198.51.100.178, 192.0.2.1" http://localhost:6333/collections

gRPC

# Standard Forwarded header (RFC 7239)
grpcurl -plaintext -H "Forwarded: for=203.0.113.50" localhost:6334 qdrant.Qdrant/HealthCheck

# Legacy X-Forwarded-For header  
grpcurl -plaintext -H "X-Forwarded-For: 203.0.113.50" localhost:6334 qdrant.Qdrant/HealthCheck

# IPv6 address
grpcurl -plaintext -H "Forwarded: for=\"[2001:db8::1]\"" localhost:6334 qdrant.Qdrant/HealthCheck

Expected Log Output

With trust_forwarded_headers: true:

203.0.113.50 gRPC /qdrant.Qdrant/HealthCheck Ok 0.000123

With trust_forwarded_headers: false (default):

gRPC /qdrant.Qdrant/HealthCheck Ok 0.000123

Testing With Nginx as Load Balancer

Nginx Configuration

upstream qdrant_http {
    server 127.0.0.1:6333;
}

upstream qdrant_grpc {
    server 127.0.0.1:6334;
}

# HTTP proxy
server {
    listen 8080;
    
    location / {
        proxy_pass http://qdrant_http;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
    }
}

# gRPC proxy
server {
    listen 8081 http2;
    
    location / {
        grpc_pass grpc://qdrant_grpc;
        grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Start Nginx

# Test config
nginx -t -c /path/to/nginx.conf

# Start
nginx -c /path/to/nginx.conf

Stop Nginx

# Graceful shutdown (finish current requests)
nginx -s quit

# Immediate shutdown
nginx -s stop

# Reload config without stopping
nginx -s reload

Test Through Nginx

# HTTP - your real IP will be logged
curl http://localhost:8080/collections

# gRPC - your real IP will be logged
grpcurl -plaintext localhost:8081 qdrant.Qdrant/HealthCheck

Testing With Docker Compose

version: '3.8'

services:
  nginx:
    image: nginx:alpine
    ports:
      - "8080:8080"
      - "8081:8081"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - qdrant

  qdrant:
    image: qdrant/qdrant
    environment:
      - QDRANT__SERVICE__TRUST_FORWARDED_HEADERS=true
      - QDRANT__LOG_LEVEL=info,qdrant::tonic::logging=trace
    ports:
      - "6333:6333"
      - "6334:6334"

Security Verification

Verify that IP spoofing is blocked when trust_forwarded_headers: false:

# With trust_forwarded_headers: false (default)
curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:6333/collections
# Log should NOT show 1.2.3.4

Verify that headers are trusted when enabled:

# With trust_forwarded_headers: true
curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:6333/collections
# Log SHOULD show 1.2.3.4

Header Priority

  1. Standard Forwarded header (RFC 7239) - checked first
  2. Legacy X-Forwarded-For header - fallback

Example with both headers:

# Forwarded header takes precedence
curl -H "Forwarded: for=10.0.0.1" -H "X-Forwarded-For: 10.0.0.2" http://localhost:6333/collections
# Log shows: 10.0.0.1

All Submissions:

  • Contributions should target the dev branch. Did you create your branch from dev?
  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?

New Feature Submissions:

  1. Does your submission pass tests?
  2. Have you formatted your code locally using cargo +nightly fmt --all command prior to submission?
  3. Have you checked your code using cargo clippy --workspace --all-features command?

Changes to Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

@dancixx dancixx marked this pull request as ready for review February 2, 2026 13:26
@dancixx dancixx requested a review from generall February 2, 2026 13:26
@timvisee timvisee self-requested a review February 2, 2026 13:30
Copy link
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

🤖 Fix all issues with AI agents
In `@config/config.yaml`:
- Around line 305-310: Update the comment for the trust_forwarded_headers config
key to mention that the server honors both the legacy X-Forwarded-For header and
the standard Forwarded header (RFC 7239), preferring the Forwarded header when
present; reference the config key name trust_forwarded_headers so readers know
which setting controls this behavior and keep the existing warning about
enabling it only behind a trusted proxy.

In `@src/settings.rs`:
- Around line 78-82: Update the docstring for the struct field
trust_forwarded_headers to mention that it controls handling of both the modern
Forwarded header and the legacy X-Forwarded-For header (not just
X-Forwarded-For), and keep the existing guidance about enabling it only behind
trusted proxies and the default false note so readers understand when to enable
it.

In `@src/tonic/logging.rs`:
- Around line 32-65: The extract_forwarded_ip function currently mishandles
Forwarded IPv6 values with ports (e.g. for="[2001:db8::1]:4711") because
trimming brackets leaves the trailing port; update the parsing in
extract_forwarded_ip (the Forwarded header handling block that looks for "for=")
to detect a leading '[' and, when present, use split_once(']') on the value
after removing an optional leading quote to extract only the IPv6 address
portion before any trailing ":port" (then remove the leading '[' and any
surrounding quotes), otherwise fallback to the existing trim_matches logic; keep
FORWARDED and X_FORWARDED_FOR handling intact and ensure the returned string is
the bare IP (no brackets, no port).

Copy link
Member

@timvisee timvisee left a comment

Choose a reason for hiding this comment

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

✔️

@qdrant qdrant deleted a comment from coderabbitai bot Feb 2, 2026
Copy link
Member

@timvisee timvisee left a comment

Choose a reason for hiding this comment

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

Temporarily adjusting review because of this IPv6 handling comment: #8028 (comment)

coderabbitai[bot]

This comment was marked as resolved.

@qdrant qdrant deleted a comment from coderabbitai bot Feb 2, 2026
@dancixx dancixx merged commit 6d01e88 into dev Feb 3, 2026
15 checks passed
@dancixx dancixx deleted the feat/x-forwarded-access-log branch February 3, 2026 09:47
@generall generall mentioned this pull request Feb 7, 2026
generall pushed a commit that referenced this pull request Feb 9, 2026
* feat: add x-forwarded support

* fix: port parsing & add tests

* fix: case-insensitive mode
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.

2 participants