问题: 通过nps或者frp访问内网服务时获取不到客户端的真实ip
解决思路: frp支持Proxy Protocol, 但是nps不支持, nginx支持Proxy Protocol
1.使用frp, 内网服务通过nginx或者雷池代理
2.使用nps, 由于nps不支持Proxy Protocol, 需要在前面加一层haproxy, 内网服务通过nginx或者雷池代理
以上
使用frp
在公网服务器部署frps, 在内网服务器部署frpc, 假设公网的ip为1.1.1.1,内网ip为10.10.0.2
目标: 通过公网服务器的443端口访问内网的10.10.0.2:7070应用
frp配置文件示例
公网frps配置
bindPort = 7000
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "xxx"
webServer.password = "xxx"
内网frpc配置
serverAddr = "1.1.1.1"
serverPort = 7000
webServer.addr = "0.0.0.0"
webServer.port = 7400
webServer.user = "xxx"
webServer.password = "xxx"
webServer.pprofEnable = false
[[proxies]]
name = "https"
type = "tcp"
localIP ="10.10.0.2"
localPort = 8443 # 该端口为雷池或nginx的应用端口
remotePort = 443 # 该端口为公网frps监听端口
transport.proxyProtocolVersion = "v2" # 开启Proxy Protocol,这是获取客户端真实ip的关键
雷池或nginx配置示例
由于雷池界面没有开启Proxy Protocol的功能, 需要手动修改配置文件
前往雷池的nginx目录: ~/safeline/resources/nginx/sites-enabled/
其中每个IF_backend_*
文件都要修改
以下是一个文件的示例, 其他文件类似
只需在server中加上注释的4点即可, 其他nginx应用同理
upstream backend_9 {
server 10.10.0.2:7070;
keepalive 128;
keepalive_timeout 75;
}
map $scheme $hsts_header {
https "max-age=5184000";
}
server {
# 1.这里加上proxy_protocol
listen 0.0.0.0:8443 ssl http2 proxy_protocol;
server_name xx.xx.com;
ssl_certificate /etc/nginx/certs/cert_3.crt;
ssl_certificate_key /etc/nginx/certs/cert_3.key;
# 2.排除本地ip
set_real_ip_from 192.168.0.0/24;
set_real_ip_from 10.0.0.0/24;
# 3.开启排除IP功能
real_ip_recursive on;
# 4.真实IP使用proxy_protocol协议
real_ip_header proxy_protocol;
...省略
}
问题: 雷池目前是不支持自定义server内容的, 每次重启配置文件都会重置, 而且添加的网站很多的话, 修改起来也比较麻烦
解决办法: 使用脚本一键修改所有IF_backend_*
文件
在目录~/safeline/resources/nginx/sites-enabled/
下新建脚本modify.sh
#!/bin/bash
# 修改文件内容在`ssl http2`后面加上` proxy_protocol`, 在`gateway_timeout_page;`下一行加上4行内容:
# \n```
# set_real_ip_from 192.168.0.0/16;
# set_real_ip_from 10.0.0.0/8;
# real_ip_recursive on;
# real_ip_header proxy_protocol;
# ```
find ./ -name "IF_backend_*" | while read filename; do
if grep -q "proxy_protocol" "$filename"; then
echo "文件 $filename 已包含 proxy_protocol,无需修改。"
else
# 解锁
chattr -i "$filename"
sed -i 's/ssl http2/ssl http2 proxy_protocol/g' "$filename" # 有换行
sed -i '/gateway_timeout_page;/a \
set_real_ip_from 192.168.0.0/16;\
set_real_ip_from 10.0.0.0/8;\
real_ip_recursive on;\
real_ip_header proxy_protocol;' "$filename" # 有换行
fi
# 为了避免雷池重启后配置文件被重置需要锁定文件
chattr +i "$filename"
done
docker exec -it safeline-tengine nginx -t
docker exec -it safeline-tengine nginx -s reload
上面说的4点配置通过脚本一键修改, 修改后使用chattr +i
锁住文件,防止文件被修改, 在雷池上修改或者添加站点时记得解锁哦
在目录~/safeline/resources/nginx/sites-enabled/
下新建解锁脚本unlock.sh
#!/bin/bash
find ./ -name "IF_backend_*" | while read filename; do
# 解锁
chattr -i "$filename"
done
在雷池修改或添加站点之前运行unlock.sh
脚本, 修改完后运行modify.sh
脚本
总结
通过在frp上开启Proxy Protocol, 和在nginx开启Proxy Protocol即可在应用中通过header里的X-Real-IP
获取客户端的真实IP
使用nps
在公网服务器部署haproxy和nps, 在内网服务器部署npc, 假设公网的ip为1.1.1.1,内网ip为10.10.0.2
目标: 通过公网的443端口访问内网的10.10.0.2:7070应用
haproxy配置示例
安装haproxy
- ubuntu/debian
sudo apt update && apt upgrade && apt install haproxy
- centos
yum install epel-release -ysudo yum update -y && yum install haproxy -y
编辑haproyx的配置文件vim /etc/haproxy/haproxy.cfg
在配置文件的最下方加上:
其中443是haproxy监听端口, 4545是nps TCP隧道的服务端端口
listen web
bind 0.0.0.0:443
mode tcp
option forwardfor
server web1 localhost:4545 send-proxy check inter 3000 fall 3 rise 5
完整配置:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
listen web
bind 0.0.0.0:1443
mode tcp
option forwardfor
server web1 localhost:444 send-proxy check inter 3000 fall 3 rise 5
nps配置
雷池或nginx配置示例
同上