内网穿透情况下,无论雷池、群晖、web应用还有jumpserver的ssh都有拿到真实IP的需求,不然在日志中看到全是内网ip没办法进行针对性封锁。要获取真实ip,公网VPS和内网都需要进行不同的配置。
VPS配置
VPS上我用的是NPS:相比FRP,不用在客户端写配置文件,最方便的是可以直接在公网web页面上管理哪些端口穿透。
NPS前面使用NginxProxyManager来代理群晖、博客、图床等web页面,方便资源缓存和证书管理。
SSH和RDP直接NPS的TCP隧道+Proxy Protocol代理协议连接。
NPS服务端
原版NPS有不少bug,也不支持Proxy Protocol代理协议,使用的是这个NPS 内网穿透 (全修)
配置docker-compose.yml
,然后docker compose up -d
运行:
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
启动后修改配置文件conf/npd.conf
:
- 关闭http和https代理
- 修改公共密钥
- 修改登录名和密码
然后docker compose restart
重启:
#############################################
# 域名转发设置
#############################################
# 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
NPC客户端
浏览器访问http://vpsip:8080
登录NPS,新建一个客户端(cpu内存弱的可以不选加密和压缩),记下验证密钥。
在路由器或nas、旁路等这些不常关机的设备上下载npc客户端,运行:
./npc -server=vpsip:8024 -vkey=key -type=tcp -log=off
或者:
docker run -d --restart=always --name npc --net=host duan2001/npc -server=vpsip:8024,yyy:456 -vkey=key1,key2 -type=tls,tcp -log=off
在NPS网页上添加TCP隧道,把雷池的80和443端口映射出来:
内网配置
雷池配置
防护应用->高级配置->源IP获取方式改为从HTTP Heder获取,填入X-Real-IP
。
每个应用都需要打开应用详情->高级配置->自定义NGINX配置,添加
set_real_ip_from 192.168.0.0/16;
# 高级版和专业版可以直接在 防护应用->高级配置->HTTP Heder操作统一添加
然后就能在日志中看到真实IP了
JumpServer配置
JumpServer分为网页端和ssh(2222)终端两个不同的配置,分别对应操作日志和登录日志内的内容。
网页端
在雷池添加防护并填上JumpServer上游,修改JumpServer的配置文件/opt/jumpserver/config/config.txt
:
DOMAINS="" #添加上子域名
USE_LB=0 #改为0
执行jmsctl restart
重启JumpServer。
ssh端
在NPS新增一个客户端,并在运行JumpServer的机器上运行一个新的NPC客户端,在添加2222的TCP隧道时,代理协议 (Proxy Protocol)选择V2,这样在登录日志就能看到真实IP了。
最终效果:
真实IP:
Web应用
WordPress
WordPress是从$_SERVER['REMOTE_ADDR']
获取评论和用户IP的,可以用$_SERVER['HTTP_X_REAL_IP']
覆盖$_SERVER['REMOTE_ADDR']
,实现获取真实IP。
在wp-config.php
最上方添加:
// 获取真实IP并覆盖 REMOTE_ADDR
if ( isset($_SERVER['HTTP_X_REAL_IP']) && filter_var($_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP) ) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_REAL_IP'];
} elseif ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) ) {
$xff_ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ( $xff_ips as $ip ) {
$ip = trim($ip);
if (filter_var($ip, FILTER_VALIDATE_IP)) {
$_SERVER['REMOTE_ADDR'] = $ip;
break;
}
}
}
如果是在雷池后面的K8s里安装的WordPress,可以使用$_SERVER['HTTP_X_ORIGINAL_FORWARDED_FOR']
去覆盖$_SERVER['REMOTE_ADDR']
:
if (isset($_SERVER['HTTP_X_ORIGINAL_FORWARDED_FOR'])) {
// 多个 IP 情况下取第一个
$list = explode(',', $_SERVER['HTTP_X_ORIGINAL_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = trim($list[0]);
}
兰空图床
修改app/Services/ImageService.php
的206行,修改为一下代码:
if ($request->hasHeader('X-Original-Forwarded-For')) {
// 优先使用 X-Original-Forwarded-For(取第一个)
$xff = $request->header('X-Original-Forwarded-For');
$xoffIp = trim(explode(',', $xff)[0]);
$ip = filter_var($xoffIp, FILTER_VALIDATE_IP) ? $xoffIp : $request->ip();
} elseif ($request->hasHeader('X-Real-IP')) {
$realIp = $request->header('X-Real-IP');
$ip = filter_var($realIp, FILTER_VALIDATE_IP) ? $realIp : $request->ip();
} elseif ($request->hasHeader('X-Forwarded-For')) {
$xff = $request->header('X-Forwarded-For');
$firstIp = trim(explode(',', $xff)[0]);
$ip = filter_var($firstIp, FILTER_VALIDATE_IP) ? $firstIp : $request->ip();
} else {
// 默认回退
$ip = $request->ip();
}
$image->fill([
'md5' => md5_file($file->getRealPath()),
'sha1' => sha1_file($file->getRealPath()),
'path' => $configs->get(GroupConfigKey::PathNamingRule) ? dirname($pathname) : '',
'name' => basename($pathname),
'origin_name' => $file->getClientOriginalName(),
'size' => $file->getSize() / 1024,
'mimetype' => $file->getMimeType(),
'extension' => strtolower($extension),
'width' => $width,
'height' => $height,
'is_unhealthy' => false,
'uploaded_ip' => $ip,
// 'uploaded_ip' => $request->ip(),
]);
群晖
控制面板->安全性->信任的代理服务器->新增->192.167.0.0/16
->保存。
go程序
内网有少量go写的微服务,如随机背景、ip地址定位等,使用的是github.com/gin-gonic/gin
库,修改起来比较方便,在路由前添加下面代码就行:
r.SetTrustedProxies([]string{
"10.0.0.0/8",
"192.168.0.0/16",
})
r.RemoteIPHeaders = []string{"X-Original-Forwarded-For", "X-Real-IP"}
普通TCP端口
能且只能让运行npc客户端的设备获取真实ip
目前只在Linux系统上实验成功。Win的local路由还没摸清
实现逻辑如下:
nps/npc配置
参考链接:https://github.com/fatedier/frp/issues/4692#issuecomment-2728547880
nps和JumpServer一样,在需要获取真实IP的机器上运行npc。
在运行npc的设备上mkdir mmproxy && cd mmproxy
,创建一个名为Dockerfile的文件,粘贴如下内容:
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 '#!/bin/sh' > /app/start.sh && \
echo '' >> /app/start.sh && \
echo '# 设置路由规则' >> /app/start.sh && \
echo 'ip rule add from 127.0.0.1/8 iif lo table 123 2>/dev/null || true' >> /app/start.sh && \
echo 'ip route add local 0.0.0.0/0 dev lo table 123 2>/dev/null || true' >> /app/start.sh && \
echo '' >> /app/start.sh && \
echo '# 如果没有提供端口映射,使用默认的' >> /app/start.sh && \
echo 'if [ -z "$PORT_MAPPINGS" ]; then' >> /app/start.sh && \
echo ' PORT_MAPPINGS="222:22"' >> /app/start.sh && \
echo 'fi' >> /app/start.sh && \
echo '' >> /app/start.sh && \
echo '# 解析并启动所有端口映射' >> /app/start.sh && \
echo 'for mapping in $(echo $PORT_MAPPINGS | tr "," " "); do' >> /app/start.sh && \
echo ' listen_port=$(echo $mapping | cut -d: -f1)' >> /app/start.sh && \
echo ' target_port=$(echo $mapping | cut -d: -f2)' >> /app/start.sh && \
echo ' echo "启动端口映射: $listen_port -> 127.0.0.1:$target_port"' >> /app/start.sh && \
echo ' /app/mmproxy -l "0.0.0.0:$listen_port" -4 "127.0.0.1:$target_port" -6 "[::1]:$target_port" &' >> /app/start.sh && \
echo 'done' >> /app/start.sh && \
echo '' >> /app/start.sh && \
echo '# 保持容器运行' >> /app/start.sh && \
echo 'wait' >> /app/start.sh && \
chmod +x /app/start.sh
ENTRYPOINT ["/app/start.sh"]
然后使用这个命令编译:
docker build -t mmproxy:latest .
然后新增一个docker-compose.yml
:
version: '3'
services:
mmproxy:
image: mmproxy:latest
container_name: mmproxy
restart: always
network_mode: host
cap_add:
- NET_ADMIN
environment:
- PORT_MAPPINGS=222:22,333:33
在nps上添加一个TCP隧道,内网端口填222(不填写ip),代理协议 (Proxy Protocol)选择V2。
其他端口的隧道一样操作,也适用于80和443。
暂无评论 IP地址位置数据由 纯真CZ88 提供支持