# Trusted Proxies

Configure trusted proxies to correctly handle client IPs and headers when PteroCA is behind a proxy, load balancer, or CDN.

## Overview

When PteroCA is behind a proxy (like Cloudflare, NGINX, or a load balancer), the application sees the proxy's IP address instead of the actual client IP. Configuring trusted proxies tells Symfony to trust certain headers from specific proxies.

## When You Need This

Configure trusted proxies if you're using:

* **Cloudflare** or other CDN
* **Reverse proxy** (NGINX, Apache, HAProxy)
* **Load balancer**
* **Docker with reverse proxy**
* **Any proxy that forwards requests**

## Configuration

### Step 1: Identify Proxy IPs

Determine which IP addresses should be trusted as proxies.

**Cloudflare:**

* Use official IP ranges from <https://www.cloudflare.com/ips/>

**NGINX/Apache reverse proxy:**

* Use the proxy server's IP address
* If on same server: `127.0.0.1`
* If on different server: proxy's private/public IP

**Load balancer:**

* Use all load balancer IP addresses

**Docker:**

* Use Docker network gateway IP (usually `172.17.0.1` or similar)

### Step 2: Configure in .env

Add the `TRUSTED_PROXIES` variable to your `.env` file:

```bash
nano /var/www/pteroca/.env
```

Add one of the following configurations:

**Single proxy:**

```bash
TRUSTED_PROXIES=127.0.0.1
```

**Multiple proxies:**

```bash
TRUSTED_PROXIES=127.0.0.1,192.168.1.100,10.0.1.50
```

**IP range (CIDR notation):**

```bash
TRUSTED_PROXIES=192.168.1.0/24,10.0.0.0/8
```

**Cloudflare (all IPv4 ranges):**

```bash
TRUSTED_PROXIES=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22
```

**Trust all (testing only):**

```bash
TRUSTED_PROXIES=0.0.0.0/0
```

⚠️ **Warning:** Only use `0.0.0.0/0` for testing. This trusts all IPs and is insecure.

### Step 3: Clear Cache

After updating `.env`, clear the cache:

```bash
cd /var/www/pteroca
php bin/console cache:clear
```

## Common Scenarios

### Scenario 1: Cloudflare CDN

**Setup:** Domain → Cloudflare → Your server → PteroCA

**Configuration:**

```bash
# Use all Cloudflare IP ranges
TRUSTED_PROXIES=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22

# Also configure trusted hosts
TRUSTED_HOSTS=^panel\.example\.com$
```

**Get current Cloudflare IPs:**

```bash
# IPv4
curl https://www.cloudflare.com/ips-v4

# IPv6
curl https://www.cloudflare.com/ips-v6
```

### Scenario 2: NGINX Reverse Proxy

**Setup:** Client → NGINX (proxy) → PteroCA

**NGINX Configuration:**

```nginx
location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}
```

**PteroCA Configuration:**

```bash
# If NGINX is on same server
TRUSTED_PROXIES=127.0.0.1

# If NGINX is on different server (e.g., 192.168.1.100)
TRUSTED_PROXIES=192.168.1.100
```

### Scenario 3: Docker with Reverse Proxy

**Setup:** Docker network with NGINX proxy container

**Find Docker gateway IP:**

```bash
docker network inspect bridge | grep Gateway
```

**Configuration:**

```bash
# Common Docker gateway
TRUSTED_PROXIES=172.17.0.1

# Or trust entire Docker network
TRUSTED_PROXIES=172.17.0.0/16
```

### Scenario 4: Load Balancer

**Setup:** Client → Load Balancer → Multiple PteroCA instances

**Configuration:**

```bash
# Trust all load balancer IPs
TRUSTED_PROXIES=10.0.1.10,10.0.1.11,10.0.1.12

# Or use CIDR range
TRUSTED_PROXIES=10.0.1.0/24
```

### Scenario 5: Multiple Layers

**Setup:** Cloudflare → Load Balancer → NGINX → PteroCA

**Configuration:**

```bash
# Trust both Cloudflare and load balancer
TRUSTED_PROXIES=173.245.48.0/20,103.21.244.0/22,...,10.0.1.0/24,127.0.0.1
```

## Headers Trusted

When a proxy is trusted, Symfony trusts these headers from it:

* `X-Forwarded-For` - Client IP address
* `X-Forwarded-Host` - Original host
* `X-Forwarded-Proto` - Protocol (HTTP/HTTPS)
* `X-Forwarded-Port` - Original port

## Verifying Configuration

### Check Current IP Detection

```php
// In any controller or service
$request = $this->requestStack->getCurrentRequest();
$clientIp = $request->getClientIp();
// This should be the real client IP, not proxy IP
```

### Test with curl

```bash
# Without proper proxy headers
curl http://your-domain.com

# With proxy headers (simulating Cloudflare)
curl -H "X-Forwarded-For: 1.2.3.4" http://your-domain.com
```

### Check Logs

Verify logs show correct client IPs:

```bash
# Check PteroCA logs
tail -f var/log/prod.log

# Check NGINX logs
tail -f /var/log/nginx/access.log
```

## Troubleshooting

### Wrong IP Addresses in Logs

**Symptom:** Logs show proxy IP instead of client IP

**Solutions:**

1. **Verify TRUSTED\_PROXIES is set**

   ```bash
   cat .env | grep TRUSTED_PROXIES
   ```
2. **Check proxy is sending headers**

   ```bash
   # In NGINX access log format, add:
   log_format detailed '$remote_addr - $http_x_forwarded_for ...';
   ```
3. **Verify proxy IP is in trusted list**
   * Get actual proxy IP from logs
   * Add to TRUSTED\_PROXIES
4. **Clear cache**

   ```bash
   php bin/console cache:clear
   ```

### CSRF Token Errors

**Symptom:** "Invalid CSRF token" when behind proxy

**Cause:** Proxy not trusted, so client IP changes between requests

**Solution:**

```bash
# Add proxy IPs to TRUSTED_PROXIES
TRUSTED_PROXIES=127.0.0.1,proxy_ip_here
```

See [CSRF Protection](/advanced-topics/security-hardening/csrf-protection.md) for more details.

### Rate Limiting Issues

**Symptom:** All users rate-limited together

**Cause:** Application sees all requests from proxy IP

**Solution:**

* Configure TRUSTED\_PROXIES correctly
* Application will then use X-Forwarded-For for rate limiting
* Each user has separate rate limit

## Security Considerations

### Only Trust Known Proxies

**Don't trust all IPs:**

```bash
# ❌ NEVER in production
TRUSTED_PROXIES=0.0.0.0/0

# ✅ Only trust specific proxies
TRUSTED_PROXIES=192.168.1.100
```

### Verify Proxy IPs Regularly

1. **Cloudflare IPs change** - Check quarterly
2. **Proxy infrastructure changes** - Update after infrastructure changes
3. **Remove old entries** - Clean up unused proxy IPs

### Use Specific Ranges

```bash
# ✅ Good - Specific range
TRUSTED_PROXIES=10.0.1.0/24

# ❌ Bad - Too broad
TRUSTED_PROXIES=10.0.0.0/8
```

### Validate Headers

Trusted proxies mean trusting their headers. Ensure:

* Proxy is under your control
* Proxy properly sanitizes headers
* Proxy doesn't allow header injection

## Advanced Configuration

### Symfony Configuration

For more control, edit `config/packages/framework.yaml`:

```yaml
framework:
    trusted_proxies: '%env(TRUSTED_PROXIES)%'
    trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix']
```

### Environment-Specific

Different proxies for different environments:

```bash
# .env.development
TRUSTED_PROXIES=127.0.0.1

# .env.staging
TRUSTED_PROXIES=192.168.1.0/24

# .env.production
TRUSTED_PROXIES=173.245.48.0/20,...  # Cloudflare IPs
```

### IPv6 Support

Include both IPv4 and IPv6 ranges:

```bash
TRUSTED_PROXIES=173.245.48.0/20,103.21.244.0/22,2400:cb00::/32,2606:4700::/32
```

## Cloudflare IP Detection

**New in v0.6.5**

PteroCA automatically checks the `CF-Connecting-IP` header for accurate client IP detection when running behind Cloudflare. No additional configuration is needed beyond the standard trusted proxies setup described above.

### How It Works

When Cloudflare proxies a request, it adds the `CF-Connecting-IP` header containing the original client IP address. PteroCA detects this header automatically and uses it for:

* **Rate limiting** - Correct per-user rate limits
* **Audit logging** - Accurate IP addresses in logs
* **Security features** - IP-based blocking and fraud detection
* **Session management** - Consistent IP tracking across requests

### Requirements

* Cloudflare IP ranges must be listed in `TRUSTED_PROXIES` (see [Scenario 1](#scenario-1-cloudflare-cdn) above)
* No additional `.env` or application configuration is required
* The `CF-Connecting-IP` header is only trusted when the request originates from a trusted proxy IP

{% hint style="info" %}
If you are **not** using Cloudflare, this feature has no effect. PteroCA falls back to the standard `X-Forwarded-For` header for IP detection.
{% endhint %}

## Related Guides

* [CSRF Protection](/advanced-topics/security-hardening/csrf-protection.md) - CSRF configuration
* [Web Server Configuration](/installation/installation/web-server-setup.md) - NGINX/Apache setup
* [Troubleshooting](https://github.com/PteroCA-Org/pteroca-homepage/blob/docs/help-and-maintenance/troubleshooting/README.md) - Common issues


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.pteroca.com/advanced-topics/security-hardening/trusted-proxies.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
