使用 CloudFlare 和 Nginx 在 Ubuntu 中托管的 Nodejs 应用程序中有时未定义客户端 IP

Client IP is sometimes undefined in a Nodejs app hosted in Ubuntu with CloudFlare and Nginx

我的应用程序有一个不寻常的问题。该应用严重依赖客户端的 IP,有时是 undefined。我的意思是,如果一天有 10 次访问我的应用程序,我可以看到 7 个客户的 IP,但其中有 3 个 returns undefined.

该应用程序没有问题,我可以肯定地说,因为当它托管在具有 CloudFlare 且没有 Nginx 的共享主机中时,它运行得非常好。但是自从我迁移到 Ubuntu 20.04 VPS 并使用 Nginx 和 CloudFlare 后,这个问题就开始了。

我遵循了 CloudFlare 中的教程,希望它能解决问题,但事实并非如此。 现在我不知道我应该怎么做才能解决这个问题。所以在这里我希望有人能弄明白。

以下是我在应用端点中获取客户端 IP 的方式:

const clientIp = req.header( 'cf-connecting-ip' ) || req.header( 'true-client-ip' );

nginx.conf 文件如下所示:

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; 
    ssl_prefer_server_ciphers on;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    
    proxy_hide_header X-Powered-By;
    add_header X-Frame-Options SAMEORIGIN;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

这是应用配置文件:

server {
    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    server_name example.com www.example.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $http_cf_connecting_ip;
        proxy_set_header X-Forwarded-For $http_x_forwarded_for;
        proxy_cache_bypass $http_upgrade;
    }

    location /blog/ {
        access_log /var/log/nginx/blog-example.org_access.log;
        error_log /var/log/nginx/blog-example.org_error.log;

        root /var/www/html/example.com;
        index index.php;

        if (!-f $request_filename) {
                rewrite [^/]$ $uri/ permanent;
        }

        try_files $uri $uri/ /blog/index.php?$args;

        location ~ \.php {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_index index.php;
            fastcgi_pass  unix:/var/run/php/php7.4-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
            include fastcgi_params;
        }
    }

    #CLOUDFLARE
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 104.16.0.0/13;
    set_real_ip_from 104.24.0.0/14;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 131.0.72.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 188.114.96.0/20;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 2400:cb00::/32;
    set_real_ip_from 2606:4700::/32;
    set_real_ip_from 2803:f800::/32;
    set_real_ip_from 2405:b500::/32;
    set_real_ip_from 2405:8100::/32;
    set_real_ip_from 2a06:98c0::/29;
    set_real_ip_from 2c0f:f248::/32;

    real_ip_header CF-Connecting-IP;

    listen [::]:443 ssl http2 ipv6only=on; # managed by Certbot
    listen 443 ssl http2; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    # include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
}

server {
    if ($host = www.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80 default_server;
    listen [::]:80 default_server;

    server_name example.com www.example.com;
    return 404; # managed by Certbot
}

更新


我不知道这是否是原因,但我收到 GET 到我主页的请求:/xdebug_session_start=phpstorm。我真的不知道那是什么,我怀疑每当它发出请求时,IP 都会返回 undefined


更新


我分析了请求headers,客户端ip是undefined。这里有 3 个请求'headers:

headers: {
    connection: 'upgrade',
    host: '63.250.33.76',
    'user-agent': 'Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)',
    accept: '*/*',
    'accept-encoding': 'gzip'
}
headers: { 
    connection: 'upgrade', 
    host: '63.250.33.76' 
}
headers: {
    connection: 'upgrade',
    host: 'www.example.com',
    'user-agent': 'Expanse indexes the network perimeters of our customers. If you have any questions or concerns, please reach out to: scaninfo@expanseinc.com'
}

有人知道这些是什么意思吗?

我对 cloudflare 不太熟悉,但是你可以在你的代码中添加“x-real-ip”header 并检查一下吗?

const clientIp = req.header( 'cf-connecting-ip' ) || req.header( 'true-client-ip' ) || req.header( 'x-real-ip' );

这些客户端是否可能直接访问您的应用程序而不是通过 Cloudflare?例如,如果您的服务器未配置为接受来自 Cloudflare IP ranges 的流量 ,那么有人可能会直接访问您的应用程序,这可以解释为什么 CF-Connecting-IP部分场景不设置

更多信息在此 documentation page