<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>真实IP &#8211; 清和&#039;s blog</title>
	<atom:link href="https://www.qingh.xyz/tag/%E7%9C%9F%E5%AE%9Eip/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.qingh.xyz</link>
	<description></description>
	<lastBuildDate>Mon, 26 Jan 2026 08:39:57 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.qingh.xyz/wp-content/uploads/2025/08/cropped-favicon-32x32.jpg</url>
	<title>真实IP &#8211; 清和&#039;s blog</title>
	<link>https://www.qingh.xyz</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>NPS内网穿透获取真实IP</title>
		<link>https://www.qingh.xyz/nps-get-real-ip/</link>
					<comments>https://www.qingh.xyz/nps-get-real-ip/#respond</comments>
		
		<dc:creator><![CDATA[清和]]></dc:creator>
		<pubDate>Thu, 03 Jul 2025 07:35:23 +0000</pubDate>
				<category><![CDATA[内网穿透]]></category>
		<category><![CDATA[JumpServer]]></category>
		<category><![CDATA[nps]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[兰空图床]]></category>
		<category><![CDATA[真实IP]]></category>
		<category><![CDATA[雷池WAF]]></category>
		<guid isPermaLink="false">https://www.qingh.xyz/?p=57</guid>

					<description><![CDATA[&#8195;&#8195;内网穿透情况下，无论雷池、群晖、web应用还有jumpserver的ssh都有拿到真实 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>&emsp;&emsp;内网穿透情况下，无论雷池、群晖、web应用还有jumpserver的ssh都有拿到真实IP的需求，不然在日志中看到全是内网ip没办法进行针对性封锁。要获取真实ip，公网VPS和内网都需要进行不同的配置。</p>
<h2>VPS配置</h2>
<p>&emsp;&emsp;VPS上我用的是NPS：相比FRP，不用在客户端写配置文件，最方便的是可以直接在公网web页面上管理哪些端口穿透。<br />
NPS前面使用NginxProxyManager来代理群晖、博客、图床等web页面，方便资源缓存和证书管理。<br />
SSH和RDP直接NPS的TCP隧道+Proxy Protocol代理协议连接。</p>
<h3>NPS服务端</h3>
<p>&emsp;&emsp;原版NPS有不少bug，也不支持Proxy Protocol代理协议，使用的是这个<a href="https://github.com/djylb/nps" title="NPS 内网穿透 (全修)">NPS 内网穿透 (全修)</a></p>
<p>配置<code>docker-compose.yml</code>，然后<code>docker compose up -d</code>运行：</p>
<pre><code>name: nps
services:
  nps:
    container_name: nps
    hostname: nps
    image: duan2001/nps:latest
    network_mode: host
    restart: always
    volumes:
      - ./conf:/conf
      - /etc/localtime:/etc/localtime:ro</code></pre>
<p>启动后修改配置文件<code>conf/npd.conf</code>:</p>
<ul>
<li>关闭http和https代理</li>
<li>修改公共密钥</li>
<li>修改登录名和密码</li>
</ul>
<p>然后<code>docker compose restart</code>重启:</p>
<pre><code>#############################################
# 域名转发设置
#############################################
# HTTP/HTTPS 代理设置：端口为 0 时不启动代理服务
http_proxy_ip=0.0.0.0
http_proxy_port=0
https_proxy_port=0
#http3_proxy_port=443
...
# 公共密钥
public_vkey=xxxx
...
# 管理后台登录用户名和密码
web_username=admin
web_password=xxxx</code></pre>
<h3>NPC客户端</h3>
<p>&emsp;&emsp;浏览器访问<code>http://vpsip:8080</code>登录NPS，新建一个客户端(cpu内存弱的可以不选加密和压缩)，记下验证密钥。<br />
在路由器或nas、旁路等这些不常关机的设备上下载npc客户端，运行:<br />
<code>./npc -server=vpsip:8024 -vkey=key -type=tcp -log=off</code><br />
或者：</p>
<pre><code>docker run -d --restart=always --name npc --net=host duan2001/npc -server=vpsip:8024,yyy:456 -vkey=key1,key2 -type=tls,tcp -log=off</code></pre>
<p>&emsp;&emsp;在NPS网页上添加TCP隧道，把雷池的80和443端口映射出来：<br />
<img decoding="async" src="https://img.qingh.xyz/FcETiO.png" alt="端口" title="端口" /></p>
<h2>内网配置</h2>
<h3>雷池配置</h3>
<p>&emsp;&emsp;防护应用-&gt;高级配置-&gt;源IP获取方式改为从HTTP Heder获取，填入<code>X-Real-IP</code>。<br />
<img decoding="async" src="https://img.qingh.xyz/GNVBfb.png" alt="X-Real-IP" title="X-Real-IP" /><br />
&emsp;&emsp;每个应用都需要打开应用详情-&gt;高级配置-&gt;自定义NGINX配置，添加</p>
<pre><code>set_real_ip_from 192.168.0.0/16;
# 高级版和专业版可以直接在 防护应用-&gt;高级配置-&gt;HTTP Heder操作统一添加</code></pre>
<p>然后就能在日志中看到真实IP了<br />
<img decoding="async" src="https://img.qingh.xyz/Uk5wi1.png" alt="雷池日志" title="雷池日志" /></p>
<h3>JumpServer配置</h3>
<p>&emsp;&emsp;JumpServer分为网页端和ssh(2222)终端两个不同的配置，分别对应操作日志和登录日志内的内容。</p>
<h4>网页端</h4>
<p>&emsp;&emsp;在雷池添加防护并填上JumpServer上游，修改JumpServer的配置文件<code>/opt/jumpserver/config/config.txt</code>：</p>
<pre><code>DOMAINS=&quot;&quot;  #添加上子域名
USE_LB=0  #改为0</code></pre>
<p>执行<code>jmsctl restart</code>重启JumpServer。</p>
<h4>ssh端</h4>
<p>&emsp;&emsp;在NPS新增一个客户端，并在运行JumpServer的机器上运行一个新的NPC客户端，在添加2222的TCP隧道时，代理协议 (Proxy Protocol)选择V2，这样在登录日志就能看到真实IP了。<br />
<img decoding="async" src="https://img.qingh.xyz/sHkUn2.png" alt="2222映射" title="2222映射" /><br />
<strong>最终效果：</strong><br />
<img decoding="async" src="https://img.qingh.xyz/HJ6EGt.png" alt="最终效果" title="最终效果" /><br />
<strong>真实IP：</strong><br />
<img decoding="async" src="https://img.qingh.xyz/PkA181.png" alt="" /></p>
<h3>Web应用</h3>
<h4>WordPress</h4>
<p>&emsp;&emsp;WordPress是从<code>$_SERVER[&#039;REMOTE_ADDR&#039;]</code>获取评论和用户IP的，可以用<code>$_SERVER[&#039;HTTP_X_REAL_IP&#039;]</code>覆盖<code>$_SERVER[&#039;REMOTE_ADDR&#039;]</code>，实现获取真实IP。<br />
在<code>wp-config.php</code>最上方添加:</p>
<pre><code>// 获取真实IP并覆盖 REMOTE_ADDR
if ( isset($_SERVER[&#039;HTTP_X_REAL_IP&#039;]) &amp;&amp; filter_var($_SERVER[&#039;HTTP_X_REAL_IP&#039;], FILTER_VALIDATE_IP) ) {
    $_SERVER[&#039;REMOTE_ADDR&#039;] = $_SERVER[&#039;HTTP_X_REAL_IP&#039;];
} elseif ( isset($_SERVER[&#039;HTTP_X_FORWARDED_FOR&#039;]) ) {
    $xff_ips = explode(&#039;,&#039;, $_SERVER[&#039;HTTP_X_FORWARDED_FOR&#039;]);
    foreach ( $xff_ips as $ip ) {
        $ip = trim($ip);
        if (filter_var($ip, FILTER_VALIDATE_IP)) {
            $_SERVER[&#039;REMOTE_ADDR&#039;] = $ip;
            break;
        }
    }
}</code></pre>
<p>&emsp;&emsp;如果是在雷池后面的K8s里安装的WordPress，可以使用<code>$_SERVER[&#039;HTTP_X_ORIGINAL_FORWARDED_FOR&#039;]</code>去覆盖<code>$_SERVER[&#039;REMOTE_ADDR&#039;]</code>:</p>
<pre><code>if (isset($_SERVER[&#039;HTTP_X_ORIGINAL_FORWARDED_FOR&#039;])) {
    // 多个 IP 情况下取第一个
    $list = explode(&#039;,&#039;, $_SERVER[&#039;HTTP_X_ORIGINAL_FORWARDED_FOR&#039;]);
    $_SERVER[&#039;REMOTE_ADDR&#039;] = trim($list[0]);
}</code></pre>
<h4>兰空图床</h4>
<p>&emsp;&emsp;修改<code>app/Services/ImageService.php</code>的206行，修改为一下代码：</p>
<pre><code>        if ($request-&gt;hasHeader(&#039;X-Original-Forwarded-For&#039;)) {
            // 优先使用 X-Original-Forwarded-For（取第一个）
            $xff = $request-&gt;header(&#039;X-Original-Forwarded-For&#039;);
            $xoffIp = trim(explode(&#039;,&#039;, $xff)[0]);
            $ip = filter_var($xoffIp, FILTER_VALIDATE_IP) ? $xoffIp : $request-&gt;ip();
        } elseif ($request-&gt;hasHeader(&#039;X-Real-IP&#039;)) {
            $realIp = $request-&gt;header(&#039;X-Real-IP&#039;);
            $ip = filter_var($realIp, FILTER_VALIDATE_IP) ? $realIp : $request-&gt;ip();
        } elseif ($request-&gt;hasHeader(&#039;X-Forwarded-For&#039;)) {
            $xff = $request-&gt;header(&#039;X-Forwarded-For&#039;);
            $firstIp = trim(explode(&#039;,&#039;, $xff)[0]);
            $ip = filter_var($firstIp, FILTER_VALIDATE_IP) ? $firstIp : $request-&gt;ip();
        } else {
            // 默认回退
            $ip = $request-&gt;ip();
        }

        $image-&gt;fill([
            &#039;md5&#039; =&gt; md5_file($file-&gt;getRealPath()),
            &#039;sha1&#039; =&gt; sha1_file($file-&gt;getRealPath()),
            &#039;path&#039; =&gt; $configs-&gt;get(GroupConfigKey::PathNamingRule) ? dirname($pathname) : &#039;&#039;,
            &#039;name&#039; =&gt; basename($pathname),
            &#039;origin_name&#039; =&gt; $file-&gt;getClientOriginalName(),
            &#039;size&#039; =&gt; $file-&gt;getSize() / 1024,
            &#039;mimetype&#039; =&gt; $file-&gt;getMimeType(),
            &#039;extension&#039; =&gt; strtolower($extension),
            &#039;width&#039; =&gt; $width,
            &#039;height&#039; =&gt; $height,
            &#039;is_unhealthy&#039; =&gt; false,
            &#039;uploaded_ip&#039; =&gt; $ip,
            // &#039;uploaded_ip&#039; =&gt; $request-&gt;ip(),
        ]);</code></pre>
<h4>群晖</h4>
<p>&emsp;&emsp;控制面板-&gt;安全性-&gt;信任的代理服务器-&gt;新增-&gt;<code>192.167.0.0/16</code>-&gt;保存。<br />
<img decoding="async" src="https://img.qingh.xyz/RggYdC.png" alt="群晖" title="群晖" /></p>
<h4>go程序</h4>
<p>&emsp;&emsp;内网有少量go写的微服务，如随机背景、ip地址定位等，使用的是<code>github.com/gin-gonic/gin</code>库，修改起来比较方便，在路由前添加下面代码就行：</p>
<pre><code>r.SetTrustedProxies([]string{
    &quot;10.0.0.0/8&quot;,
    &quot;192.168.0.0/16&quot;,
})
r.RemoteIPHeaders = []string{&quot;X-Original-Forwarded-For&quot;, &quot;X-Real-IP&quot;}</code></pre>
<h3>普通TCP端口</h3>
<p align="center"><strong><span style="font-size:24px">能且只能让运行npc客户端的设备获取真实ip</span></strong></p>
<blockquote>
<p>目前只在Linux系统上实验成功。Win的local路由还没摸清</p>
</blockquote>
<p>&emsp;&emsp;实现逻辑如下：<br />
<img decoding="async" src="https://img.qingh.xyz/SZ2b3Z.png" alt="mmproxy" title="mmproxy" /></p>
<h4>nps/npc配置</h4>
<blockquote>
<p>参考链接：<a href="https://github.com/fatedier/frp/issues/4692#issuecomment-2728547880" title="https://github.com/fatedier/frp/issues/4692#issuecomment-2728547880">https://github.com/fatedier/frp/issues/4692#issuecomment-2728547880</a></p>
</blockquote>
<p>&emsp;&emsp;nps和JumpServer一样，在需要获取真实IP的机器上运行npc。<br />
在运行npc的设备上<code>mkdir mmproxy &amp;&amp; cd mmproxy</code>，创建一个名为Dockerfile的文件，粘贴如下内容：</p>
<pre><code>FROM golang:1.21-alpine AS builder
RUN apk add --no-cache git
WORKDIR /app
RUN git clone https://github.com/path-network/go-mmproxy .
RUN go build -o mmproxy .

FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/mmproxy .
RUN echo &#039;#!/bin/sh&#039; &gt; /app/start.sh &amp;&amp; \
    echo &#039;&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;# 设置路由规则&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;ip rule add from 127.0.0.1/8 iif lo table 123 2&gt;/dev/null || true&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;ip route add local 0.0.0.0/0 dev lo table 123 2&gt;/dev/null || true&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;# 如果没有提供端口映射，使用默认的&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;if [ -z &quot;$PORT_MAPPINGS&quot; ]; then&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;  PORT_MAPPINGS=&quot;222:22&quot;&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;fi&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;# 解析并启动所有端口映射&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;for mapping in $(echo $PORT_MAPPINGS | tr &quot;,&quot; &quot; &quot;); do&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;  listen_port=$(echo $mapping | cut -d: -f1)&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;  target_port=$(echo $mapping | cut -d: -f2)&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;  echo &quot;启动端口映射: $listen_port -&gt; 127.0.0.1:$target_port&quot;&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;  /app/mmproxy -l &quot;0.0.0.0:$listen_port&quot; -4 &quot;127.0.0.1:$target_port&quot; -6 &quot;[::1]:$target_port&quot; &amp;&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;done&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;# 保持容器运行&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    echo &#039;wait&#039; &gt;&gt; /app/start.sh &amp;&amp; \
    chmod +x /app/start.sh

ENTRYPOINT [&quot;/app/start.sh&quot;]</code></pre>
<p>然后使用这个命令编译：<br />
<code>docker build -t mmproxy:latest .</code><br />
然后新增一个<code>docker-compose.yml</code>:</p>
<pre><code>version: &#039;3&#039;
services:
  mmproxy:
    image: mmproxy:latest
    container_name: mmproxy
    restart: always
    network_mode: host
    cap_add:
      - NET_ADMIN
    environment:
      - PORT_MAPPINGS=222:22,333:33</code></pre>
<p>在nps上添加一个TCP隧道，内网端口填222(不填写ip)，代理协议 (Proxy Protocol)选择V2。</p>
<blockquote>
<p>其他端口的隧道一样操作，也适用于80和443。</p>
</blockquote>
]]></content:encoded>
					
					<wfw:commentRss>https://www.qingh.xyz/nps-get-real-ip/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
