端口转发

iptables

关于CentOS 7系统:需要删除firewalld装回iptables.

# 安装命令:

1
2
3
4
systemctl stop firewalld.service
systemctl disable firewalld.service
yum install iptables-services -y
systemctl enable iptables.service

ubuntu

1
apt install iptables -y

第一步:开启系统的转发功能

首先,先确认服务器是否已开启转发,运行:

1
2
3
4
5
sysctl net.ipv4.ip_forward
# 如果已经启动则显示
> net.ipv4.ip_forward = 1
# 如果没有启动则显示
> net.ipv4.ip_forward = 0

# CentOS 6/Debian/Ubuntu 开启方式:

1
2
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

# CentOS 7 开启方式:

1
2
echo "net.ipv4.ip_forward = 1" >> /usr/lib/sysctl.d/cloudiplc.conf
sysctl -p /usr/lib/sysctl.d/cloudiplc.conf

首先我们设置一下iptables 防火墙的开机启动自动载入规则功能。

CentOS 系统:

1
2
service iptables save 
service iptables restart

Debian/Ubuntu使用:

1
2
iptables-save > /etc/iptables.up.rules
iptables-restore < /etc/iptables.up.rules

第二步: 加入iptables规则

总体是这样的:

1
2
3
4
iptables -t nat -A PREROUTING -p tcp --dport [端口号] -j DNAT --to-destination [目标IP]
iptables -t nat -A PREROUTING -p udp --dport [端口号] -j DNAT --to-destination [目标IP]
iptables -t nat -A POSTROUTING -p tcp -d [目标IP] --dport [端口号] -j SNAT --to-source [本地服务器IP]
iptables -t nat -A POSTROUTING -p udp -d [目标IP] --dport [端口号] -j SNAT --to-source [本地服务器IP]

如服务器是内网IP(例如NAT-VPS),请用ifconfig或ip addr确认走公网流量网卡的内网IP(本地服务器IP),比如阿里云这些,内网IP一般为10.xx.xx.xx

例如单端口同端口转发: 将本地服务器(中转服务器2.2.2.2)的10000端口转发至目标IP(节点服务器)为1.1.1.130000端口

1
2
3
4
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 10000 -j DNAT --to-destination 1.1.1.1:30000
iptables -t nat -A PREROUTING -p udp -m udp --dport 10000 -j DNAT --to-destination 1.1.1.1:30000
iptables -t nat -A POSTROUTING -d 1.1.1.1 -p tcp -m tcp --dport 30000 -j SNAT --to-source 2.2.2.2
iptables -t nat -A POSTROUTING -d 1.1.1.1 -p udp -m udp --dport 30000 -j SNAT --to-source 2.2.2.2

例如端口范围不同端口转发:

将本地服务器(中转服务器2.2.2.2)的10000~20000端口转发至目标IP(节点服务器)为1.1.1.130000~40000端口

1
2
3
4
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 10000:20000 -j DNAT --to-destination 1.1.1.1:30000-40000
iptables -t nat -A PREROUTING -p udp -m udp --dport 10000:20000 -j DNAT --to-destination 1.1.1.1:30000-40000
iptables -t nat -A POSTROUTING -d 1.1.1.1 -p tcp -m tcp --dport 30000:40000 -j SNAT --to-source 2.2.2.2
iptables -t nat -A POSTROUTING -d 1.1.1.1 -p udp -m udp --dport 30000:40000 -j SNAT --to-source 2.2.2.2

第三步:保存 iptables配置

CentOS 系统:

1
service iptables save

Debian/Ubuntu 系统:

1
iptables-save > /etc/iptables.up.rules

1.查看NAT规则

1
2
iptables -t nat -vnL POSTROUTING
iptables -t nat -vnL PREROUTING

2.删除NAT规则

通过上面的查看规则命令,查看规则后,确定你要删除的规则的顺序,下面的命令是删除第四个规则。

1
2
iptables -t nat -D POSTROUTING 4
iptables -t nat -D PREROUTING 4

nginx

一般配置

nginx.conf添加如下配置,并使用nginx -s reload重载nginx使其生效,同时注意防火墙/安全组放行对应的端口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
stream {
#将12345端口转发到192.168.1.23的3306端口
server {
listen 12345;
proxy_connect_timeout 5s;
proxy_timeout 20s;
proxy_pass 192.168.1.23:3306;
}
#将udp 53端口转发到192.168.1.23 53端口
server {
listen 53 udp reuseport;
proxy_timeout 20s;
proxy_pass 192.168.1.23:53;
}
#ipv4转发到ipv6
server {
listen 9135;
proxy_connect_timeout 10s;
proxy_timeout 30s;
proxy_pass [2607:fcd0:107:3cc::1]:9135;
}
}
  • listen:后面填写源端口(也就是当前服务器端口),默认协议为TCP,可以指定为UDP协议
  • proxy_connect_timeout:连接超时时间
  • proxy_timeout:超时时间
  • proxy_pass:填写转发目标的IP及端口号

获取到客户端的IP

Proxy protocol 是haproxy 作者开发和设计的一个inernet 协议, 用于获取客户端的IP地址。 在使用7层代理是可以向http协议添加X-Forword-For来实现,而4层协议就无法简单的获取到客户端IP。haproxy、nginx、apache、squid、mysql等等都支持proxy protocol.

转发服务器配置

1
2
3
4
5
6
7
stream {
server {
listen 12345;
proxy_pass example.com:12345;
proxy_protocol on;
}
}

目标服务器

通过$proxy_protocol_addr获取客户端ip

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
http {
log_format combined '$proxy_protocol_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
#...

server {
server_name localhost;
# 设置proxy_protocol
listen 80 proxy_protocol;
listen 443 ssl proxy_protocol;

ssl_certificate /etc/nginx/ssl/public.example.com.pem;
ssl_certificate_key /etc/nginx/ssl/public.example.com.key;

location /app/ {
proxy_pass http://backend1;
proxy_set_header Host $host;
#设置$proxy_protocol_addr
proxy_set_header X-Real-IP $proxy_protocol_addr;
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
}
}
}

stream {
log_format basic '$proxy_protocol_addr - $remote_user [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time';
#...
server {
listen 12345 ssl proxy_protocol;

ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/cert.key;

proxy_pass backend.example.com:12345;
proxy_protocol on;
}
}

reference