获取客户端真实IP
出于安全考虑,近期在处理一个记录用户真实IP的需求。本来以为很简单,后来发现没有本来以为的简单。这里主要备忘下,如果服务器处于端口回流(hairpin NAT),keepalived,nginx之后,如何取得客户端的外网IP。

来自客户端PC的流量路径如上,在这样的拓扑中,在应用服务中取得,客户端PC的外网ip,可能会遇到哪些问题呢?(ip 编的随意,为便于说明,不考虑合理)。
- 编程实现
Java 为例,这个我会。
public static String getClientIP(HttpServletRequest request) {String remoteAddr = request.getRemoteAddr();return remoteAddr;}
运行一下,输出呢是 3.3.3.3 。 这是因为这个API所取得的是IP数据包的源地址。Nginx的反向代理时工作在应用层的,当他收到一个http请求时,会对应生成一个新的请求,发送给应用服务,这个请求的IP包的源地址是Nginx服务器的IP即3.3.3.3。
- Nginx头部注入
因为是应用层,那这个请求ip包的源地址肯定就是3.3.3.3了,但是在应用层我们可以附加一点信息,以便后面的应用服务,可以通过这个附加信息,了解这个请求对应的原始源地址。这个我也会。
在Nginx 中配置。
server {...proxy_set_header X-Real-IP $remote_addr;
在应用层http协议中,加一个http header。X-Real-IP:$remote_addr. $remote_addr 是一个预设变量,代表所代理转发请求的原始源ip地址。
在Java 程序中,读取对应的附加信息
public String getRealIp(HttpServletRequest request) {String realIp = request.getHeader("X-Real-IP");if (realIp != null && !realIp.isEmpty()) {return "Client's Real IP: " + realIp;} return "";}
运行一下,此时输出2.2.2.2。 显然我们向前推进了一步。
- Keepalived负载均衡模式
印象里这里keepalived的主要作用应该是解决nginx 代理服务器的单点问题的,似乎也被配置为负载均衡了?翻了下配置文件,实际的情况如下。

运维大壮说他配置keepalived 时候多考虑了一步,如果机器活着,nginx 挂了怎么办,于是又做了一层负载均衡(这种情况虚拟IP不会漂移到右边的备机)。他说的也确实不是没有道理。keepalived 的负载均衡貌似是工作在第三层的,那肯定在负载均衡的时候,又对ip包的源地址进行了修改。这是网络层,向nginx 这样附加信息肯定是不行了。于是,翻了翻手册发现,keepalived 的负载均衡支持三种路由模式,NAT,Direct Routing 和 Tunneling。
NAT 模式,会修改源IP,出入流量都会经过负载均衡器。而DR模式,会直接修改MAC地址,那回程流量就不再经过负载均衡器了,也就意味这种模式,源地址不会被修改,回程流量会直接发送给源ip地址。
DR模式有个要求,就是负载均衡器需要能知道后端服务的MAC地址,这是依赖于ARP实现的,也就是,要求负载均衡器和后端服务器在同一广播域。恰好我门可以满足。于是。
virtual_server 192.168.11.242 80 {
……
lb_kind DR
……
将负载均衡路由模式切换为DR模式。重新看一下这次,取得客户端地址变成了 1.1.1.1, 这一步一坑。为什么到达keepalived的ip包的源地址会变成,出口路由器的外网地址呢?
- 路由器端口回流(Hairpin NAT)
离胜利是不远了,此时见多识广的大壮说,这应该是跟端口回流有关,之前有个系统也是类似问题, 你的web端口配置了端口回流,如果关掉端口回流就可以取得外网地址了。什么是端口回流?

首先,路由器做了端口映射,1.1.1.1:80->192.168.0.2:80
服务器A,由于某些原因,不方便使用内网地址192.168.0.2访问B,而要通过外网IP或者域名访问服务器B,即访问1.1.1.1:80, 按端口转发规则,路由器会将这个来自于内网接口的流量再次转发回内网服务器B,形成了一个180度的急弯——发卡弯,这也就是Haripin NAT的名字由来,十分形象。
如果不做设置,服务器A通过访问1.1.1.1:80 是无法正常访问服务器B的。原因是,hairpin会影响Tcp连接建立的握手过程。
1. A发送握手请求给入口路由器,路由器修改目的ip为192.68.0.2 ,发送到服务器B。
2.B收到握手请求后,回复握手确认应答给这个握手请求的源IP地址,此处是A的地址192.168.0.1
3.因为A,B同一网络,握手确认会直接到达A。
4.A发现这个握手确认回复的源ip(192.168.0.2)并不是我期望与之建立连接的握手请求目的地址(1.1.1.1),A并不认识B,只认识路由器,导致TCP连接无法建立。
解决以上问题的关键,就是让握手确认应当同样经过路由器,发送给A。因此,需要在之前将握手请求转发给B时,同时修改源ip地址为(1.1.1.1),如此,B服务器作出确认回复时,自然也会发送给1.1.1.1。
但是这个源地址转化(SNAT)的过程,实际上只对于来自内网的流量是有必要的。对于外网流量,其源IP本身就处于网络外部,必然会经过再次经过路由器返回。
于是联系管路由器的小明,请他不要偷懒,规则配置的细致一点,不要做无差别的源地址转换。即
1.对内网接口流量进行源地址和目标地址转换2.对外网流量只进行目标地址转化。
重新测试。 终于输出实际了客户PC实际ip地址0.0.0.0
OK,一波三折,跌宕起伏,写到这里~
相关文章:
获取客户端真实IP
出于安全考虑,近期在处理一个记录用户真实IP的需求。本来以为很简单,后来发现没有本来以为的简单。这里主要备忘下,如果服务器处于端口回流(hairpin NAT),keepalived,nginx之后,如何取得客户端的…...
韩式告白土味情话-柯桥生活韩语学习零基础入门教学
你们韩国人别太会告白了! 1、너 얼굴에 뭐가 조금 묻었어! 你的脸上有点5376东西! 뭐가 조금 묻었1585757는데? 有点什么? 이쁨이 조금 묻었네. 有点漂亮。 2、돌잡이 때 뭐 잡았어요? 你抓周的时候抓了什么? 쌀 잡았…...
Linux安全与高级应用(一)深入探讨Linux安全与高级应用
文章目录 深入探讨Linux安全与高级应用引言目录一、Linux安全与应用概述1.1 Linux的应用现状1.2 Linux的安全需求 二、构建LAMP企业网站平台2.1 LAMP平台简介2.2 安装和配置Apache服务器2.2.1 安装Apache2.2.2 配置Apache 2.3 安装和管理MySQL数据库2.3.1 安装MySQL2.3.2 配置M…...
【nginx 第二篇章】各个环境安装 nginx
一、Windows环境安装 1、下载 Nginx 访问Nginx官网(http://nginx.org/en/download.html)下载稳定版本的 Nginx 压缩包,如 nginx-1.xx.x.zip。下载后解压到指定的目录,例如 D:\nginx。 2、启动 Nginx 直接双击解压目录下的 ngi…...
在Spring Boot和MyBatis-Plus项目中,常见的错误及其解决方法2.0
1. org.springframework.beans.factory.BeanCreationException: Error creating bean with name requestMappingHandlerMapping 现象 在创建bean时发生错误,通常是因为存在重复的URL映射。 解决方法 检查所有控制器方法上的URL映射注解,确保没有重复…...
招聘信息数据清洗
文章目录 前言代码示例如下 前言 相关知识 为了完成本关任务,你需要掌握: 1.Spark 清洗数据的相关方法, 2.空值列怎么删除; 3.怎么数据切分才能达到想要的数据。 Spark清洗数据相关方法 一、将含有空值的数据删除 1.将含有空值的数据删除&a…...
机器学习——支持向量机(SVM)(1)
目录 一、认识SVM 1. 基本介绍 2. 支持向量机分类器目标 二、线性SVM分类原理(求解损失) 三、重要参数 1. kernel(核函数) 2 .C(硬间隔与软间隔) 四、sklearn中的支持向量机(自查&#…...
Elastic Observability 8.15:AI 助手、OTel 和日志质量增强功能
作者:来自 Elastic Alex Fedotyev, Tom Grabowski, Vinay Chandrasekhar, Miguel Luna Elastic Observability 8.15 宣布了几个关键功能: 新的和增强的原生 OpenTelemetry 功能: OpenTelemetry Collector 的 Elastic 分发:此版本…...
Unity3D ECS架构的优缺点详解
前言 Unity3D作为一款强大的游戏开发引擎,近年来在性能优化和架构设计上不断进化,其中ECS(Entity-Component-System)架构的引入是其重要的里程碑之一。ECS架构通过重新定义游戏对象的组织和处理方式,为开发者带来了诸…...
理解Go语言中多种并发模式
Go 的同步原语使实现高效的并发程序成为可能,并且选择合适的同步原语和并发模式可以更加容易地实现并发的可能,减少错误的发生。这里谈论的并发模式是只在 Go 语言中常见的并发的“套路” ,一种可解决某一类通用场景和问题的惯用方法。 1. 并发模式概述 我们先来回顾下同步…...
C++ primer plus 第17 章 输入、输出和文件:文件输入和输出03:文件模式:二进制文件
系列文章目录 17.4.5 文件模式 程序清单17.18 append.cpp 程序清单17.19 binary.cpp 文章目录 系列文章目录17.4.5 文件模式程序清单17.18 append.cpp程序清单17.19 binary.cpp17.4.5 文件模式1.追加文件来看一个在文件尾追加数据的程序。程序清单17.18 append.cpp2.二进制文…...
网络安全之sql靶场(11-23)
sql靶场(11-23) 目录 第十一关(post注入) 第十二关 第十三关 第十四关 第十五关 第十六关 第十七关 第十八关 第十九关 第二十关 第二十一关 第二十二关 第二十三关 第十一关(post注入) 查看…...
WordPress网站被入侵,劫持收录事件分析
7.15,网站被入侵,但是直到7月17日,我才发现被入侵。 16日,17日正常更新文章,17日查询网站收录数据时,在站长资源平台【流量与关键词】查询上,我发现了比较奇怪的关键词。 乱码关键词排名 起初…...
原生js: 实现三个水平tab按钮, 默认第一个上面有class, 点击另外的实现class=‘cur‘的切换的效果
问: <ul><li class"cur">热门问题</li><li>订阅问题</li><li>使用问题</li></ul> 这是我的代码, 这是我的代码: // 遍历 helpInfoClass 数组helpInfoClass.forEach((item, index) > {var itemId item[0];var i…...
C#语言基础速成Day07
“知止而后有定,定而后能静,静而后能安,安而后能虑,虑而后能得。” 目录 前言文章有误敬请斧正 不胜感恩!||Day07 C#常见数据结构:1. 集合(Collection)1.1 **List<T>**1.2 **H…...
jvm运行时常量池溢出的原因
Java虚拟机(JVM)的运行时常量池(Runtime Constant Pool)是方法区的一部分,用于存储类和接口的常量池表,包括字面量和对类型、字段和方法的符号引用。运行时常量池溢出通常指的是常量池的内存使用达到了JVM设…...
floyd算法详解
算法是一种用于求解所有顶点对之间的最短路径问题的算法,特别适用于稠密图。下面是一个使用C实现的算法示例: #include <iostream> #include <climits> // For INT_MAXusing namespace std;const int V 4; // 图的顶点数// 定义一个函数来…...
Web前端性能优化的方向
减少dom渲染复杂列表优化缓存优化首页背景图片加载慢,可以放在服务器上,读取绝对路径900k的图片大小有些大,可以对图片进行压缩,tinypng网站压缩、熊猫压缩、bing域名下的图片url后面带参数w、h、qlt剪裁下拉框数据较多进行懒加载…...
【面试题】设计模式-责任链模式
设计模式-责任链模式 前言责任链简历案例代码小结 前言 我们知道,设计模式是面试时经常被问到的问题之一,这是因为设计模式能够体现出代码设计的美感,且在很多框架的底层也都会使用到各种设计模式,所以对设计模式的考察ÿ…...
JavaEE 第8节 单例模式详解
目录 概念 饿汉模式 懒汉模式 懒汉模式在多线程环境下的优化 1.线程安全问题 2.效率问题 3.指令重排序导致的问题 1)为什么要进行指令重排序? 2)指令重排序在上述代码为什么会构成问题? 导读: 单例模式是一种…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...
Python网页自动化Selenium中文文档
1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API,让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API,你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...
