✨ Улучшена функция получения IP-адреса клиента и добавлен тестовый эндпоинт
- Расширена логика получения IP-адреса с учетом новых заголовков, таких как CF-Connecting-IP и Forwarded. - Добавлено детальное логирование заголовков для упрощения отладки. - Внедрен тестовый эндпоинт для проверки извлечения IP-адресов и отображения заголовков запроса.
This commit is contained in:
parent
ceed63249e
commit
0cb0b27f20
149
NGINX_PROXY_SETUP.md
Normal file
149
NGINX_PROXY_SETUP.md
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
# Настройка nginx Proxy Manager для корректной передачи IP-адресов
|
||||||
|
|
||||||
|
## Проблема
|
||||||
|
|
||||||
|
При использовании nginx Proxy Manager в режиме bridge, реальный IP-адрес клиента может не передаваться корректно, и вместо него всегда показывается IP-адрес прокси-сервера (например, 90.189.198.107).
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
### 1. Настройка nginx Proxy Manager
|
||||||
|
|
||||||
|
В настройках прокси-хоста в nginx Proxy Manager добавьте следующие заголовки:
|
||||||
|
|
||||||
|
#### В разделе "Advanced" → "Custom Nginx Configuration":
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
# Передача реального IP-адреса клиента
|
||||||
|
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;
|
||||||
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
|
|
||||||
|
# Дополнительные заголовки для лучшей совместимости
|
||||||
|
proxy_set_header X-Client-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded $scheme://$host;
|
||||||
|
|
||||||
|
# Установка доверенного прокси
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Server $host;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Или в разделе "Custom Nginx Configuration" (если доступен):
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
location / {
|
||||||
|
proxy_pass http://your-app-container:3000;
|
||||||
|
|
||||||
|
# Передача реального IP-адреса
|
||||||
|
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;
|
||||||
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
|
proxy_set_header X-Client-IP $remote_addr;
|
||||||
|
|
||||||
|
# Дополнительные настройки
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Server $host;
|
||||||
|
|
||||||
|
# Таймауты
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_send_timeout 60s;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
|
||||||
|
# Буферизация
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_request_buffering off;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Настройка Docker Compose (если используется)
|
||||||
|
|
||||||
|
Если ваш nginx Proxy Manager работает в Docker, убедитесь, что в docker-compose.yml правильно настроена сеть:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
nginx-proxy-manager:
|
||||||
|
image: jc21/nginx-proxy-manager:latest
|
||||||
|
container_name: nginx-proxy-manager
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
- "81:81"
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./letsencrypt:/etc/letsencrypt
|
||||||
|
networks:
|
||||||
|
- npm-network
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
your-app:
|
||||||
|
image: your-app-image
|
||||||
|
container_name: your-app
|
||||||
|
networks:
|
||||||
|
- npm-network
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
networks:
|
||||||
|
npm-network:
|
||||||
|
driver: bridge
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Проверка работы
|
||||||
|
|
||||||
|
После настройки используйте тестовый эндпоинт для проверки:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -H "X-Forwarded-For: 192.168.1.100" https://your-domain.com/api/debug/ip
|
||||||
|
```
|
||||||
|
|
||||||
|
Или откройте в браузере: `https://your-domain.com/api/debug/ip`
|
||||||
|
|
||||||
|
### 4. Ожидаемый результат
|
||||||
|
|
||||||
|
В ответе должно быть:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"detected_ip": "192.168.1.100", // Реальный IP клиента
|
||||||
|
"headers": {
|
||||||
|
"x-forwarded-for": "192.168.1.100",
|
||||||
|
"x-real-ip": "192.168.1.100",
|
||||||
|
"x-client-ip": "192.168.1.100"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Отладка
|
||||||
|
|
||||||
|
Если IP-адрес все еще неправильный:
|
||||||
|
|
||||||
|
1. Проверьте логи nginx Proxy Manager
|
||||||
|
2. Убедитесь, что заголовки передаются (используйте `/api/debug/ip`)
|
||||||
|
3. Проверьте настройки сети Docker
|
||||||
|
4. Убедитесь, что nginx Proxy Manager не находится за дополнительными прокси
|
||||||
|
|
||||||
|
### 6. Дополнительные настройки
|
||||||
|
|
||||||
|
#### Для Cloudflare
|
||||||
|
|
||||||
|
Если вы используете Cloudflare, добавьте:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
proxy_set_header CF-Connecting-IP $http_cf_connecting_ip;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Для AWS Load Balancer
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Примечания
|
||||||
|
|
||||||
|
- После изменения настроек nginx Proxy Manager перезапустите контейнер
|
||||||
|
- Убедитесь, что ваш Node.js сервер настроен с `app.set("trust proxy", true)`
|
||||||
|
- Тестовый эндпоинт `/api/debug/ip` можно удалить после настройки
|
||||||
85
server.js
85
server.js
@ -304,29 +304,67 @@ function getClientIP(req) {
|
|||||||
console.log("x-forwarded-for:", req.headers["x-forwarded-for"]);
|
console.log("x-forwarded-for:", req.headers["x-forwarded-for"]);
|
||||||
console.log("x-real-ip:", req.headers["x-real-ip"]);
|
console.log("x-real-ip:", req.headers["x-real-ip"]);
|
||||||
console.log("x-client-ip:", req.headers["x-client-ip"]);
|
console.log("x-client-ip:", req.headers["x-client-ip"]);
|
||||||
|
console.log("cf-connecting-ip:", req.headers["cf-connecting-ip"]); // Cloudflare
|
||||||
|
console.log("x-forwarded:", req.headers["x-forwarded"]);
|
||||||
|
console.log("forwarded:", req.headers["forwarded"]);
|
||||||
console.log("req.connection.remoteAddress:", req.connection?.remoteAddress);
|
console.log("req.connection.remoteAddress:", req.connection?.remoteAddress);
|
||||||
console.log("req.socket.remoteAddress:", req.socket?.remoteAddress);
|
console.log("req.socket.remoteAddress:", req.socket?.remoteAddress);
|
||||||
console.log("ALL HEADERS:", JSON.stringify(req.headers, null, 2));
|
console.log("ALL HEADERS:", JSON.stringify(req.headers, null, 2));
|
||||||
console.log("========================");
|
console.log("========================");
|
||||||
|
|
||||||
// Используем req.socket.remoteAddress напрямую, так как nginx передает внутренний IP контейнера
|
// Приоритет заголовков для nginx proxy manager:
|
||||||
let ip = req.socket?.remoteAddress;
|
// 1. X-Real-IP (часто используется nginx)
|
||||||
|
// 2. X-Forwarded-For (стандартный заголовок)
|
||||||
|
// 3. CF-Connecting-IP (если используется Cloudflare)
|
||||||
|
// 4. X-Client-IP
|
||||||
|
// 5. req.ip (Express с trust proxy)
|
||||||
|
// 6. req.socket.remoteAddress (прямое соединение)
|
||||||
|
|
||||||
// Если remoteAddress недоступен, пробуем заголовки
|
let ip = null;
|
||||||
if (!ip || ip === "::1") {
|
|
||||||
ip =
|
// Проверяем X-Real-IP (nginx часто использует этот заголовок)
|
||||||
req.headers["x-forwarded-for"]?.split(",")[0]?.trim() ||
|
if (req.headers["x-real-ip"]) {
|
||||||
req.headers["x-real-ip"] ||
|
ip = req.headers["x-real-ip"];
|
||||||
req.headers["x-client-ip"] ||
|
}
|
||||||
req.ip ||
|
// Проверяем X-Forwarded-For (берем первый IP из списка)
|
||||||
req.connection?.remoteAddress ||
|
else if (req.headers["x-forwarded-for"]) {
|
||||||
"unknown";
|
ip = req.headers["x-forwarded-for"].split(",")[0].trim();
|
||||||
|
}
|
||||||
|
// Проверяем CF-Connecting-IP (Cloudflare)
|
||||||
|
else if (req.headers["cf-connecting-ip"]) {
|
||||||
|
ip = req.headers["cf-connecting-ip"];
|
||||||
|
}
|
||||||
|
// Проверяем X-Client-IP
|
||||||
|
else if (req.headers["x-client-ip"]) {
|
||||||
|
ip = req.headers["x-client-ip"];
|
||||||
|
}
|
||||||
|
// Проверяем Forwarded заголовок (RFC 7239)
|
||||||
|
else if (req.headers["forwarded"]) {
|
||||||
|
const forwarded = req.headers["forwarded"];
|
||||||
|
const forMatch = forwarded.match(/for=([^;,\s]+)/);
|
||||||
|
if (forMatch) {
|
||||||
|
ip = forMatch[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Используем req.ip (Express с trust proxy)
|
||||||
|
else if (req.ip && req.ip !== "::1" && req.ip !== "127.0.0.1") {
|
||||||
|
ip = req.ip;
|
||||||
|
}
|
||||||
|
// В крайнем случае используем socket remoteAddress
|
||||||
|
else if (
|
||||||
|
req.socket?.remoteAddress &&
|
||||||
|
req.socket.remoteAddress !== "::1" &&
|
||||||
|
req.socket.remoteAddress !== "127.0.0.1"
|
||||||
|
) {
|
||||||
|
ip = req.socket.remoteAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Очищаем IP от скобок IPv6 и портов
|
// Очищаем IP от скобок IPv6, портов и кавычек
|
||||||
if (ip && ip !== "unknown") {
|
if (ip && ip !== "unknown") {
|
||||||
// Убираем скобки IPv6
|
// Убираем скобки IPv6
|
||||||
ip = ip.replace(/[[\]]/g, "");
|
ip = ip.replace(/[[\]]/g, "");
|
||||||
|
// Убираем кавычки если есть
|
||||||
|
ip = ip.replace(/['"]/g, "");
|
||||||
|
|
||||||
// Обрабатываем IPv6 адреса
|
// Обрабатываем IPv6 адреса
|
||||||
if (ip.startsWith("::ffff:")) {
|
if (ip.startsWith("::ffff:")) {
|
||||||
@ -710,6 +748,29 @@ app.get("/api/user", requireApiAuth, (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Тестовый эндпоинт для проверки IP-адресов (только для отладки)
|
||||||
|
app.get("/api/debug/ip", (req, res) => {
|
||||||
|
const clientIP = getClientIP(req);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
detected_ip: clientIP,
|
||||||
|
headers: {
|
||||||
|
"x-forwarded-for": req.headers["x-forwarded-for"],
|
||||||
|
"x-real-ip": req.headers["x-real-ip"],
|
||||||
|
"x-client-ip": req.headers["x-client-ip"],
|
||||||
|
"cf-connecting-ip": req.headers["cf-connecting-ip"],
|
||||||
|
"x-forwarded": req.headers["x-forwarded"],
|
||||||
|
forwarded: req.headers["forwarded"],
|
||||||
|
},
|
||||||
|
express: {
|
||||||
|
req_ip: req.ip,
|
||||||
|
socket_remoteAddress: req.socket?.remoteAddress,
|
||||||
|
connection_remoteAddress: req.connection?.remoteAddress,
|
||||||
|
},
|
||||||
|
all_headers: req.headers,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Страница с заметками (требует аутентификации)
|
// Страница с заметками (требует аутентификации)
|
||||||
app.get("/notes", requireAuth, (req, res) => {
|
app.get("/notes", requireAuth, (req, res) => {
|
||||||
// Получаем цвет пользователя для предотвращения FOUC
|
// Получаем цвет пользователя для предотвращения FOUC
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user