当前位置: 首页 > news >正文

后端nginx使用set_real_ip_from获取用户真实IP

         随着nginx的迅速崛起,越来越多公司将apache更换成nginx. 同时也越来越多人使用nginx作为负载均衡, 并且代理前面可能还加上了CDN加速,但是随之也遇到一个问题:nginx如何获取用户的真实IP地址.

前言:Nginx ngx_http_realip_module

官方说明:

Module ngx_http_realip_module

例子1

        realip模块的作用是:当本机的nginx处于一个反向代理的后端时获取到真实的用户IP

        如果没有realip模块,nginx的access_log里记录的IP会是反向代理服务器的IP,PHP中$_SERVER[‘REMOTE_ADDR’]的值也是反向代理的IP。

        而安装了realip模块,并且配置正确,就可以让nginx日志和php的REMOTE_ADDR都变成真实的用户IP。

举一个最简单的例子,网络架构如图:

        如果不做任何配置,后端web服务器nginx日志里记录的IP将会是10.10.10.10,这个时候我们增加如下nginx配置:

set_real_ip_from 10.10.10.10;

real_ip_header X-Forwarded-For;

  • set_real_ip_from指令是告诉nginx,10.10.10.10是我们的反代服务器(信任服务器,记住这个名词,下面会提到),不是真实的用户IP,
  • real_ip_header则是告诉nginx真正的用户IP是存在X-Forwarded-For请求头中(对X-Forwarded-For不了解的同学请自行百度)。

        重新加载nginx配置之后,就可以看到nginx日志里记录的IP就是123.123.123.123了,php里的REMOTE_ADDR也是123.123.123.123。

        realip模块还提供了另外一个指令real_ip_recursive,可以用来处理更加复杂的情况,架构如图:

        这个时候如果还用上面的配置,后端nginx的日志里显示的IP就变成了192.168.1.10了,这个时候就需要real_ip_recursive这个指令了。

set_real_ip_from 10.10.10.10;

set_real_ip_from 192.168.1.10;

real_ip_header X-Forwarded-For;

real_ip_recursive on;

官网文档对于real_ip_recursive指令的解释十分拗口,看了老半天才明白。

首先要明确一点,realip模块生效的前提是:直接连接nginx的ip是在set_real_ip_from中指定的。

  • 当real_ip_recursive为off时,nginx会把real_ip_header指定的HTTP头中的最后一个IP当成真实IP
  • 当real_ip_recursive为on时,nginx会把real_ip_header指定的HTTP头中的最后一个不是信任服务器的IP当成真实IP

        在这个例子中,当请求到达后端web服务器时,X-Forwarded-For应该是123.123.123.123, 192.168.1.10。

        如果real_ip_recursive为off,nginx取X-Forwarded-For的最后一个IP也就是192.168.1.10作为真实IP。

        如果real_ip_recursive为on,由于192.168.1.10是信任服务器IP,所以nginx会继续往前查找,发现123.123.123.123不是信任服务器IP,就认为是真实IP了。

例子2:

实例环境:

  • 用户IP 120.22.11.11
  • CDN前端 61.22.22.22
  • CDN中转 121.207.33.33
  • 公司NGINX前端代理 192.168.50.121(外网121.207.231.22)

1、使用CDN自定义IP头来获取

假如说你的CDN厂商使用nginx,那么在nginx上将$remote_addr赋值给你指定的头,方法如下:

proxy_set_header remote-user-ip $remote_addr;

后端PHP代码getRemoteUserIP.php

<?php
$ip = getenv("HTTP_REMOTE_USER_IP"); 
echo $ip;
?>

访问getRemoteUserIP.php,结果如下:

120.22.11.11 //取到了真实的用户IP,如果CDN能给定义这个头的话,那这个方法最佳

2、通过HTTP_X_FORWARDED_FOR获取IP地址

        一般情况下CDN服务器都会传送HTTP_X_FORWARDED_FOR头,这是一个ip串,后端的真实服务器获取HTTP_X_FORWARDED_FOR头,截取字符串第一个不为unkown的IP作为用户真实IP地址, 例如:
        120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121(用户IP,CDN前端IP,CDN中转,公司NGINX代理)
getFor.php

<?php
$ip = getenv("HTTP_X_FORWARDED_FOR");
echo $ip;
?>

访问getFor.php结果如下:

120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121

如果你是php程序员,你获取第一个不为unknow的ip地址,这边就是120.22.11.11.

3.使用nginx自带模块realip获取用户IP地址

安装nginx之时加上realip模块,我的参数如下:

./configure --prefix=/usr/local/nginx-1.4.1 --with-http_realip_module

真实服务器nginx配置

server {listen 80;server_name www.zcy.com;access_log /data/logs/nginx/www.ttlsa.com.access.log main;index index.php index.html index.html;root /data/site/www.ttlsa.com;location /{root /data/site/www.ttlsa.com;}location = /getRealip.php{set_real_ip_from 192.168.50.0/24;set_real_ip_from 61.22.22.22;set_real_ip_from 121.207.33.33;set_real_ip_from 127.0.0.1;real_ip_header X-Forwarded-For;real_ip_recursive on;fastcgi_pass unix:/var/run/phpfpm.sock;fastcgi_index index.php;include fastcgi.conf;}
}

getRealip.php内容

<?php
$ip = $_SERVER['REMOTE_ADDR'];
echo $ip;
?>

访问www.ttlsa.com/getRealip.php,返回:

120.22.11.11

注释 real_ip_recursive on或者 real_ip_recursive off:

访问www.ttlsa.com/getRealip.php,返回:

121.207.33.33

很不幸,获取到了中继的IP, real_ip_recursive的效果看明白了吧.

  • set_real_ip_from:真实服务器上一级代理的IP地址或者IP段,可以写多行
  • real_ip_header:从哪个header头检索出要的IP地址
  • real_ip_recursive:递归排除IP地址,ip串从右到左开始排除set_real_ip_from里面出现的IP,如果出现了未出现这些ip段的IP,那么这个IP将被认为是用户的IP。例如我这边的例子,真实服务器获取到的IP地址串如下:
 120.22.11.11,61.22.22.22,121.207.33.33,192.168.50.121

在real_ip_recursive on的情况下

        61.22.22.22,121.207.33.33,192.168.50.121都出现在set_real_ip_from中,仅仅120.22.11.11没出现,那么他就被认为是用户的ip地址,并且赋值到remote_addr变量。
        在real_ip_recursive off或者不设置的情况下192.168.50.121出现在set_real_ip_from中,  排除掉,接下来的ip地址便认为是用户的ip地址

如果仅仅如下配置:

set_real_ip_from 192.168.50.0/24;
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

访问结果如下:

121.207.33.33

4、三种在CDN环境下获取用户IP方法总结

4.1 CDN自定义header头

  • 优点:获取到最真实的用户IP地址,用户绝对不可能伪装IP
  • 缺点:需要CDN厂商提供

4.2 获取forwarded-for头

  • 优点:可以获取到用户的IP地址
  • 缺点:程序需要改动,以及用户IP有可能是伪装的

4.3 使用realip获取

  • 优点:程序不需要改动,直接使用remote_addr即可获取IP地址
  • 缺点:ip地址有可能被伪装,而且需要知道所有CDN节点的ip地址或者ip段

参考

后端nginx使用set_real_ip_from获取用户真实IP-CSDN博客

nginx之ngx_http_realip_module使用详解-腾讯云开发者社区-腾讯云

相关文章:

后端nginx使用set_real_ip_from获取用户真实IP

随着nginx的迅速崛起&#xff0c;越来越多公司将apache更换成nginx. 同时也越来越多人使用nginx作为负载均衡, 并且代理前面可能还加上了CDN加速&#xff0c;但是随之也遇到一个问题&#xff1a;nginx如何获取用户的真实IP地址. 前言&#xff1a;Nginx ngx_http_realip_module…...

python使用leveldb

LevelDB 是由 Google 开发的一个快速的键值存储库&#xff0c;提供了一个持久化的有序映射&#xff0c;非常适合用作简单的高性能数据库。 安装 Plyvel 首先&#xff0c;使用 pip3 来安装 plyvel pip3 install plyvel基本用法 接下来&#xff0c;介绍使用 plyvel 来操作 Le…...

hcs部署场景

HCS售前规划&#xff1a; eDesigner&#xff1f; SCT报价器&#xff1f; 将eDesigner项目导出到SCT后&#xff0c;报价器会自动对硬件进行配置及报价。 HCS规划设计工具 - HUAWEI CLOUD Stack Designer 用于支撑HUAWEI CLOUD Stack解决方案项目LLD设计&#xff0c;提升设计效率…...

从零开始学习的ai教程视频,如何入手?

个人认为小白想零基础学习ai应该从理论和实操两个方面入手。理论是支撑实践的前提&#xff0c;只有以一种全局观角度了解ai才能实现从熟练使用ai到有自我意识的用ai创作。 接下来将会简单介绍一些理论免费学习网站和软件&#xff08;一笔带过&#xff0c;不重点&#xff09;&a…...

【精选】发布应用到应用商店的基本介绍

摘要 本文旨在介绍如何在各大应用商店发布应用&#xff0c;包括市场选择、准备材料、上架步骤以及常见被拒原因及解决方法。通过详细的步骤和经验分享&#xff0c;帮助开发者顺利将应用推向市场。 引言 随着移动应用市场的不断发展&#xff0c;越来越多的开发者希望将他们的…...

LC 572.另一棵树的子树

572. 另一棵树的子树 给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tr…...

PPT 操作

WPS 版式 PPT中&#xff0c;巧妙使用母版&#xff0c;可以提高效率。 双击母版&#xff0c;选择其中一个版式&#xff0c;插入装饰符号。 然后选择关闭。 这个时候&#xff0c;在该版式下的所有页面&#xff0c;就会出现新加入的符号。不在该版式下的页面&#xff0c;不会出现…...

python项目练习——19、单词计数器

这个项目允许用户输入一段文本,然后统计其中每个单词出现的次数,并按照出现次数从高到低进行排序显示。它涉及到字符串处理、数据结构和用户界面设计等方面的技术。 示例: import tkinter as tk # 导入 Tkinter 库 from collections import Counter # 导入计数器工具类 c…...

单链表专题

文章目录 目录1. 链表的概念及结构2. 实现单链表2.1 链表的打印2.2 链表的尾插2.3 链表的头插2.4 链表的尾删2.5 链表的头删2.6 查找2.7 在指定位置之前插入数据2.8 在指定位置之后插入数据2.9 删除pos节点2.10 删除pos之后的节点2.11 销毁链表 3. 链表的分类 目录 链表的概念…...

js把数组中的某一项移动到第一位

在JavaScript中&#xff0c;如果你要将数组中的某一项移动到第一位&#xff0c;你可以使用以下几种方法。 假设我们有一个数组arr&#xff0c;并且想要将位于索引index的项移动到数组的第一个位置&#xff1a; let arr [1, 2, 3, 4, 5]; let index 2; // 假设我们想将3&…...

MyBatis如何实现分页

文章目录 MyBatis分页方式对比使用数据库厂商提供的分页查询语句通过自定义 SQL 实现分页逻辑1. 使用 RowBounds 实现分页2. 使用 PageHelper 实现分页 数组分页使用 MyBatis-Plus 进行分页MyBatis物理分页和逻辑分页MyBatis 手写一个 拦截器分页 在 MyBatis 中实现分页通常有两…...

在 Python 编程中,面向对象编程的核心概念包括哪些部分?

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 在 Python 编程中&#xff0c;面向对象编程&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;的核心概念主要包括类&#xff08;Class&#xff09;、对象&#xff08;Object&#x…...

elementui树形组件自定义高亮颜色

1、需求描述&#xff1a;点击按钮切换树形的章节&#xff0c;同时高亮 2、代码实现 1&#xff09;style样式添加 <style> .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {background-color: #81d3f8 !important; //高亮颜色colo…...

富格林:技巧抵抗曝光虚假套路

富格林悉知&#xff0c;黄金具备独特的优势吸引着众多投资者的目光&#xff0c;在现货黄金市场也被认为是一条潜力无限的盈利之道。但我们要明白风险与盈利是相辅相成的&#xff0c;因此在这复杂的市场中我们必须利用技巧来抵抗曝光的虚假套路。下面富格林将给大家分享一些正确…...

24年权威数学建模报名通知汇总(含妈妈杯、国赛、美赛、电工杯、数维杯、五一数模、深圳杯......)

1、MathorCup比赛 报名时间&#xff1a;2024年4月11日中午12点&#xff08;周四&#xff09; 比赛开始时间&#xff1a;2024年4月12日上午8时&#xff08;周五&#xff09; 比赛结束时间&#xff1a;2024年4月16日上午9时&#xff08;周二&#xff09; 报名费用&#xff1a…...

【C语言自定义类型之----结构体,联合体和枚举】

一.结构体 1.结构体类型的声明 srruct tag {nemer-list;//成员列表 }varible-list;//变量列表结构体在声明的时候&#xff0c;可以不完全声明。 例如&#xff1a;描述一个学生 struct stu {char name[20];//名字int age;//年龄char sex[20];//性别 };//分号不能省略2.结构体…...

[Java基础揉碎]StringBuffer类 StringBuild类

目录 StringBuffer类 介绍 继承图 String VS StringBuffer StringBuffer的构造器 String和StringBuffer的转换 StringBuffer类常见方法 测试题 StringBuild类 基本介绍 继承图 String、StringBuffer 和StringBuilder的比较 通过字符串拼接循环测试可以看到各自的性…...

Android Studio修改项目包名

1.第一步&#xff0c;项目结构是这样的&#xff0c;3个包名合在了一起&#xff0c;我们需要把每个包名单独展示出来 2.我们点击这个 取消选中后的包名结构是这样的&#xff0c;可以看到&#xff0c;包名的每个文件夹已经展示分开了&#xff0c;现在我们可以单独对每个包名文件夹…...

c++语言增强的地方

目录 1.对全局变量的检测能力 2.struct类型增强 3.c中所有变量和函数都必须有类型 4.c中新增的bool类型 5.三目运算符的加强 6.const的增强 7.对枚举的增强 1.对全局变量的检测能力 C语言中同时定义两个相同的全局变量编译器并不会报错&#xff0c;而c中就会报重定义错…...

评论发布完整篇(react版)

此篇文章阐述评论的最新、最热之间的tab标签切换&#xff08;包括当前所在tab标签的高亮显示问题&#xff09;&#xff1b;当前评论的删除&#xff1b;除此之外还延伸了用户的评论实时发布功能。其中最新tab标签所展示的内容是根据当前评论点赞数来进行排序&#xff0c;点赞数量…...

前端window.open的简单使用

JavaScript 中的 Window.open() 用法详解-CSDN博客 window.open("https://www.baidu.com/?tn49055317_12_hao_pg", _blank);...

基于开源软件构建存储解决方案的思考

近来看了一些IBM的存储产品的资料&#xff0c;有一些收获。 依据存储软件和搭配硬件&#xff0c;IBM存储产品的组合&#xff0c;大致分类如下&#xff1a; 自研存储软件&#xff0c;搭配自研专有硬件自研存储软件&#xff0c;搭配通用服务器硬件&#xff0c;比如IBM Storage S…...

【leetcode】动态规划::前缀和(二)

标题&#xff1a;【leetcode】前缀和&#xff08;二&#xff09; 水墨不写bug 正文开始&#xff1a; &#xff08;一&#xff09; 和为K的子数组 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续…...

SpringBoot自动装配原理之@Import注解解析

文章目录 1. 概述2. 使用2.1 导入普通Bean2.2 导入配置类2.3 导入 ImportSelector 实现类2.4 导入 ImportBeanDefinitionRegistrar 实现类 3. 区别 1. 概述 当谈及现代Java开发领域中的框架选择时&#xff0c;SpringBoot无疑是无与伦比的热门之选。其简化了开发流程&#xff0…...

49 样式迁移【李沐动手学深度学习v2课程笔记】

1. 样式迁移&#xff08;Style Transfer) 计算机视觉的应用之一&#xff0c;将样式图片中的样式&#xff08;比如油画风格等&#xff09;迁移到内容图片&#xff08;比如实拍的图片&#xff09;上&#xff0c;得到合成图片 可以理解成为一个滤镜&#xff0c;但相对于滤镜来讲…...

Linux的学习之路:4、权限

一、Linux权限的概念 权限我们都熟悉&#xff0c;最常见的就是在看电视时需要vip这个就是权限&#xff0c;然后在Linux就是有两个权限&#xff0c;就是管理员也就是超级用户和普通的用户 命令&#xff1a;su [用户名] 功能&#xff1a;切换用户。 例如&#xff0c;要从root用户…...

自定义类型—结构体

目录 1 . 结构体类型的声明 1.1 结构的声明 1.2 结构体变量的创建与初始化 1.3 结构体的特殊声明 1.4 结构体的自引用 2. 结构体内存对齐 2.1 对齐规则 2.2 为什么存在内存对齐 2.3 修改默认对齐数 3. 结构体传参 4.结构体实现位段 4.1 位段的内存分配 4.3 位段的…...

【JavaWeb】Jsp基本教程

目录 JSP概述作用一个简单的案例&#xff1a;使用JSP页面输出当前日期 JSP处理过程JSP 生命周期编译阶段初始化阶段执行阶段销毁阶段案例 JSP页面的元素JSP指令JSP中的page指令Include指令示例 taglib指令 JSP中的小脚本与表达式JSP中的声明JSP中的注释HTML的注释JSP注释 JSP行…...

外包干了25天,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入杭州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…...

C++(14): STL条件变量std::condition_variable

1. 简述 在C的标准模板库&#xff08;STL&#xff09;中&#xff0c;std::condition_variable是一个非常重要的同步原语&#xff0c;用于在多线程编程中实现线程间的条件同步。它允许一个或多个线程等待某个条件成立&#xff0c;当条件成立时&#xff0c;等待的线程会被唤醒并继…...