OpenVPN搭建管道为内网地址映射公网端口

近日工作上有这样一个需求,某学校没有公网地址,但公司的业务对接需要公网地址的一个端口,而这边另一个学校有公网地址,可做映射。要求是在不影响业务正常运行的情况下实现本次映射。对端对接地址是:10.0.0.2 提供了一台可操作服务器 10.0.0.3 ,本地我提供了可操作服务器:10.100.101.115,公网 nat 映射一应俱全。仔细思考过后,决定使用OpenVPN。实现如下:

服务器端

添加epel源

1
2
3
4
yum install epel-release
yum cleanall # 可选
yum update # 可选
yum makecache # 可选

安装openvpn easy-rsa firewalld

任选其一,以防火墙为基础的端口转发

  • CentOS 6.5 iptables #这里对端提供的服务器是 CentOS 6.5,不支持firewalld
  • CentOS 7 firewalld #本地服务器防火墙
1
yum -y install openvpn easy-rsa firewalld

配置easy-rsa

在这一步生成一些证书

  • CA证书
  • 服务器证书和密钥
  • Diffie-Hellman密钥
  • 客户端证书和密钥
1
2
3
cp -r /usr/share/easy-rsa/ /etc/openvpn/
cd /etc/openvpn/easy-rsa/2.*/
vim vars

确保vars中以下参数正确

1
2
3
4
export KEY_SIZE=2048
export CA_EXPIRE=3650
export KEY_EXPIRE=3650
export KEY_NAME="EasyRSA"

生成服务器证书密钥和客户端证书密钥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
source ./vars #初始化证书授权中心
./clean-all
# 生成证书
# Name [EasyRSA] 那一项写ca
./build-ca
# 生成服务器密钥和证书
# 在challenge password和optional company name处留空
# Name [EasyRSA] 那一项写server
# 两个y选项选择y
./build-key-server server
./build-dh
# 生成客户端密钥和证书
# 在challenge password和optional company name处留空
# Name [EasyRSA] 那一项写client
# 两个y选项选择y
./build-key client
cd /etc/openvpn/easy-rsa/2.0/
cp -r keys/ /etc/openvpn/

配置OpenVPN服务端

你可以从/usr/share/doc/openvpn-*.*.*/sample/sample-config-files中拷贝出配置文件(..*是openvpn版本),也可以自己新建配置文件,

1
2
3
cd /etc/openvpn/
cp /usr/share/doc/openvpn-*.*.*/sample/sample-config-files/server.conf /etc/openvpn
vim server.conf
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
local 0.0.0.0    #监听地址
port 1194 #监听端口
proto tcp #监听协议
dev tun #采用路由隧道模式
ca /etc/openvpn/keys/ca.crt #证书路径
cert /etc/openvpn/keys/server.crt #服务器证书
key /etc/openvpn/keys/server.key #服务器密钥
dh /etc/openvpn/keys/dh2048.pem #密钥交换协议文件
server 192.168.200.0 255.255.255.0 #给客户端分配地址池,注意:不能和VPN服务器内网网段有相同
push "route 10.100.101.115 255.255.255.255" #向客户端推送10.100.101.115并允许客户端访问10.100.101.115的地址
;push"dhcp-option DNS 8.8.8.8" #dhcp分配dns,可选
client-to-client #客户端之间互相通信
keepalive 10 120 #存活时间,10秒ping一次,120 如未收到响应则视为断线
cipher AES-256-CBC #加密方式 参考Shadowsocks
comp-lzo #传输数据压缩
max-clients 100 #最多允许 100 客户端连接
user nobody #用户
group nobody #用户组
persist-key
persist-tun
reneg-sec 900 #可选,这里设置15分钟
status /var/log/openvpn/openvpn-status.log
log /var/log/openvpn/openvpn.log
verb 3
#OpenVPN在服务器和客户端都有一个参数 reneg-sec n,该参数是指n秒钟之后重新验证key。默认值为3600s,该参数值以服务器和客户端的最小reneg-sec为最终决定重新验证的时间。例如:如果服务器上设定了3000s,即使你客户端设置30000s,最终重新验证key值仍是3000s

设置允许IP转发,在/etc/sysctl.conf文件中添加一行net.ipv4.ip_forward = 1
sysctl -p

配置firewalld端口转发

1
2
3
4
5
6
7
8
9
10
#启动防火墙
systemctl start firewalld
#添加OpenVPN连接用端口1194和映射用端口8080 下由注释
firewall-cmd --permanent --zone=public --add-service=openvpn
#由于我这边直接添加OpenVPN服务TCP端口起不来,所以再添加一条规则,上一条起作用了就不用配
firewall-cmd --permanent --zone=public --add-port=1194/tcp
firewall-cmd --permanent --zone=public --add-service=webcache
#在防火墙上添加端口 8080,把本机 8080 端口收到的数据转发到 192.168.200.6 的 18080 端口
#这里转发到客户端的端口一定要和映射到公网的端口一致,不然会出现无法登录的情况
firewall-cmd --permanent --zone=public --add-forward-port=port=18080:proto=tcp:toport=18080:toaddr=192.168.200.6
  • 为什么这里添加1194和8080端口是写成openvpn和webcache,因为这两个服务的端口已经被写入linux系统了,映射服务名即可映射对应端口,便于识别,但也可以直接使用端口8080 2012 9090
1
2
3
4
5
6
cat /etc/services | grep 8080
webcache 8080/tcp http-alt # WWW caching service
webcache 8080/udp http-alt # WWW caching service
cat /etc/services | grep openvpn
openvpn 1194/tcp # OpenVPN
openvpn 1194/udp # OpenVPN
  • 直接使用端口,这样的好处是可以自定义端口,还可以指定通过的协议。
1
2
firewall-cmd --permanent --zone=public --add-port=1194/tcp
firewall-cmd --permanent --zone=public --add-port=8080/tcp
  • 在不停止服务的情况下重新加载防火墙
1
firewall-cmd --reload

查看防火墙配置

1
2
3
4
5
6
7
8
9
10
11
12
13
public
target: default
icmp-block-inversion: no
interfaces:
sources:
services: ssh dhcpv6-client dns openvpn webcache
ports: 1194/tcp
protocols:
masquerade: yes
forward-ports: port=18080:proto=tcp:toport=18080:toaddr=192.168.200.6
source-ports:
icmp-blocks:
rich rules:

firewalld和OpenVPN开机启动

1
2
3
4
5
##防火墙设置开机启动
systemctl enable firewalld
##服务端启动和开机启动
systemctl start openvpn@server
systemctl enable openvpn@server

客户端设置

安装openvpn iptables

1
yum install openvpn iptables nginx

配置OpenVPN客户端

你可以从/usr/share/doc/openvpn-*.*.*/sample/sample-config-files中拷贝出配置文件(..*是openvpn版本),也可以自己新建配置文件,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cd /etc/openvpn/
cp /usr/share/doc/openvpn-*.*.*/sample/sample-config-files/client.conf /etc/openvpn
vim client.conf
client
dev tun
proto tcp #监听协议,和服务端一致
remote my-server-2 1194 #这里是服务器映射出来的公网地址和端口
nobind
user nobody
group nobody
persist-key
persist-tun
ca /etc/openvpn/keys/ca.crt #这里是从服务器拷过来的ca证书
cert /etc/openvpn/keys/client.crt #这里是从服务器拷过来的客户端证书
key /etc/openvpn/keys/client.key #这里是从服务器拷过来的客户端密钥
cipher AES-256-CBC #加密方式,和服务端一致
reneg-sec 900 #可选,这里和服务器端一致
comp-lzo #传输数据压缩,和服务器端一致
verb 3
  • 拷贝服务器端的/etc/openvpn/easy-rsa/{ca.crt,client.crt,client.key}到客户端的主机 /etc/openvpn/keys/目录下,没有就新建一个

客户端做反向代理

1
2
3
4
5
6
7
8
9
10
11
yum install 
vim /etc/nginx/conf.d/default.conf
server {
// 当通过 10.0.0.3:18080 端口访问这个服务器时
// 该请求会被转发到 10.0.0.2:8080
listen 18080 ;
location / {
//物理机能访问到的web服务都可以做代理
proxy_pass http://10.0.0.2:8080;
}
}

配置iptables端口转发

1
2
3
4
5
service iptables start
#将外网访问 192.168.200.6 的 18080 端口转发到 10.0.0.3:18080 端口。
iptables -t nat -A PREROUTING -d 192.168.200.6 -p tcp --dport 18080 -j DNAT --to-destination 10.0.0.3:18080
#将 10.0.0.3 18080 端口将数据返回给客户端时,将源 ip 改为 192.168.200.6
iptables -t nat -A POSTROUTING -d 10.0.0.3 -p tcp --dport 18080 -j SNAT --to 192.168.200.6

iptables和nginx开机启动

1
2
3
4
service nginx start    #启动反向代理
chkconfig nginx on #开机启动反向代理
service iptables start #启动端口转发
chkconfig iptables on #开机启动端口转发

常用命令

1
2
3
4
5
6
7
8
9
/etc/init.d/iptables start     # 开启防火墙,或者service iptables start,以下同理
/etc/init.d/iptables stop # 停止防火墙
/etc/init.d/iptables restart # 重启防火墙
/etc/init.d/iptables status # 查看端口状态
/etc/init.d/iptables save # 保存配置
/etc/init.d/iptables -t nat --list #查看nat状态
/etc/init.d/iptables -t nat -F #清空nat
chkconfig iptables off # 永久关闭防火墙
chkconfig iptables on # 永久关闭后启用

至此访问服务器端映射的公网地址+端口 http://ip:port/ 即可访问没有公网的那台主机的服务

要求达成。