手把手教你搭建OpenVPN(保姆级教程)

CentOS 7 搭建OpenVPN服务器

上述博客内容写的比较完善,具备一定参考价值。本博客内容主要参照第一个地址。

OpenVPN分配固定IP:详细指南

如何在OpenVPN中配置255.255.255.252子网


OpenVPN的安装与部署(ldap进行身份认证+记录用户访问日志并发送邮件)


TODO:待参考该博客更新当前博客内容。

OpenVpn服务端与客户端之间双向访问


基本实现我预期的目标,限制暴露在公网的应用及页面的任意IP来源访问,仅允许通过openvpn访问。

  1. 建立openvpn-server(Server)端
  2. 建立openvpn-client(A)端
  3. 建立openvpn-client(B)端

A端通过访问B端(由openVpn分配ip)地址,实现限定IP来源访问能力。

【false】通过与openvpn-server建立连接,访问Server端内网中所有服务器。这里需要开启IP的转发,及配置防火墙的转发规则等。 我未搞定!

实际应用场景

例:访问B端的Nginx端口服务,需要开启以下配置,允许openvpn网段访问

allow 10.8.0.0/24; # 允许openVpn网段来源Ip访问(前提是B端需要安装openVpn客户端)
deny all; # 禁止其他来源地址访问

服务端配置

安装配置证书软件

yum -y install easy-rsa

easy-rsa 并未包含在默认的 CentOS/RHEL 软件仓库,以下方式开启:

yum install epel-release -y
yum install easy-rsa -y

查询是否安装成功

rpm -ql easy-rsa

若依然无法安装,可以尝试更新下源 Centos7 更换阿里源

创建证书软件目录

mkdir /opt/easy-rsa
cd /opt/easy-rsa

复制配置到文件

cp -a /usr/share/easy-rsa/3.0.8/* .
cp -a /usr/share/doc/easy-rsa-3.0.8/vars.example ./vars

清空vars文件

> vars

新增vars文件内容

# 检查 EASYRSA_CALLER 环境变量
## EASYRSA_CALLER 环境变量是否为空。如果为空,则输出错误信息并返回错误状态码 1。这表示不再需要手动 source 这个 vars 文件,EasyRSA 会自动处理。
if [ -z "$EASYRSA_CALLER" ]; then
echo "You appear to be sourcing an Easy-RSA
'vars' file." >&2
echo "This is no longer necessary and is
disallowed. See the section called" >&2
echo "'How to use this file' near the top
comments for more details." >&2
return 1
fi

# 设置证书请求的通用名称(DN)格式
set_var EASYRSA_DN "cn_only"
# 设置证书请求的国家:
set_var EASYRSA_REQ_COUNTRY "CN"
# 设置证书请求的省份:
set_var EASYRSA_REQ_PROVINCE "Beijing"
# 设置证书请求的城市:
set_var EASYRSA_REQ_CITY "Shanghai"
# 设置证书请求的组织:
set_var EASYRSA_REQ_ORG "koten"
# 设置证书请求的电子邮件
set_var EASYRSA_REQ_EMAIL "888888@xxx.comm"
# 设置命名约定支持:
set_var EASYRSA_NS_SUPPORT "yes"

作用总结(gpt):

自动处理 vars 文件:不再需要手动 source 这个文件,EasyRSA 会自动处理。
配置证书请求的默认值:设置证书请求的默认值,包括国家、省份、城市、组织和电子邮件等信息。
简化证书生成过程:通过预定义这些变量,简化了生成证书请求的过程,避免每次手动输入这些信息。

创建证书

1、初始化,在当前目录创建PKI目录,用于存储整数

./easyrsa init-pki

2、创建根证书,会提示设置密码,

用于ca对之后生成的server和client证书签名时使用,其他提示内容直接回车即可

./easyrsa build-ca

Enter New CA Key Passphrase提示你输入一个新的CA密钥密码短语。这是为了保护你的CA私钥,防止未经授权的访问。

Enter PEM pass phrase 提示你输入一个密码短语,用于加密和保护生成的CA私钥文件(ca.key)。这个密码短语在每次使用CA私钥(例如签发证书)时都需要输入,以确保私钥的安全性。

3、创建server端证书和私钥文件,nopass表示不加密私钥文件,提示内容直接回车即可

./easyrsa gen-req server nopass

4、给server端证书签名,提示内容需要输入yes和创建ca根证书时候的密码

./easyrsa sign server server

5、创建Diffie-Hellman文件,密钥交换时的Diffie-Hellman算法

./easyrsa gen-dh

以下步骤为给client端创建证书

6、创建client端的证书和私钥文件,nopass表示不加密私钥文件,提示内容直接回车即可

./easyrsa gen-req client01 nopass

7、给client端证书签名,提示内容输入yes和创建ca根证书时候的密码

  • 第一个 client 证书类型:客户端证书
  • 第二个 client01 客户端证书具体名称
./easyrsa sign client client01

8.检查是否有ca根证书、客户端服务端证书、客户端服务端私钥

安装tree命令:yum install tree -y

tree
[root@server_164 easy-rsa]# tree
.
├── easyrsa #管理命令
├── openssl-easyrsa.cnf
├── pki
│   ├── ca.crt #ca根证书,服务端与客户端都需要用
│   ├── certs_by_serial
│   │   ├── 220A41E81C5C7DD7C85D47B7C11F99C0.pem
│   │   ├── B0F60154FBCD3FC6F6A4CD422AA12EC1.pem
│   │   └── F3A6D0F2F8D72C07816264D90B500AC0.pem
│   ├── dh.pem #认证算法 服务端
│   ├── index.txt
│   ├── index.txt.attr
│   ├── index.txt.attr.old
│   ├── index.txt.old
│   ├── issued
│   │   ├── xxx_user.crt #客户端证书
│   │   └── server.crt #服务端证书
│   ├── openssl-easyrsa.cnf
│   ├── private
│   │   ├── ca.key
│   │   ├── xxx_user.key #客户端私钥
│   │   └── server.key #服务端私钥
...

安装openvpn服务端并写入配置文件

yum -y install openvpn

openvpn 安装失败,可执行yum install epel-release -y

服务端配置文件:

vim /etc/openvpn/server.conf

完整配置,包含博客下文的密码登录固定IP(暂已注释)

port 1194                                    #端口
proto udp #协议
dev tun #采用路由隧道模式
ca /opt/easy-rsa/pki/ca.crt #ca证书的位置
cert /opt/easy-rsa/pki/issued/server.crt #服务端公钥的位置
key /opt/easy-rsa/pki/private/server.key #服务端私钥的位置
dh /opt/easy-rsa/pki/dh.pem #证书校验算法
server 10.8.0.0 255.255.255.0 #给客户端分配的地址池
push "route 10.8.0.0 255.255.255.0" #允许客户端访问的内网网段
ifconfig-pool-persist /etc/openvpn/ipp.txt #地址池记录文件位置,未来让openvpn客户端固定ip地址使用的
keepalive 10 120 #存活时间,10秒ping一次,120秒如果未收到响应则视为断线
max-clients 100 #最多允许100个客户端连接
status openvpn-status.log #日志位置,记录openvpn状态
#log /var/log/openvpn.log #openvpn日志记录位置
log-append /var/log/openvpn.log
verb 3 #openvpn版本
client-to-client #允许客户端与客户端之间通信
persist-key #通过keepalive检测超时后,重新启动VPN,不重新读取
persist-tun #检测超时后,重新启动VPN,一直保持tun是linkup的,否则网络会先linkdown然后再linkup
duplicate-cn #客户端密钥(证书和私钥)是否可以重复
comp-lzo #启动lzo数据压缩格式

########用户密码登录#########
#script-security 3 #允许使用自定义脚本
#auth-user-pass-verify /etc/openvpn/check.sh via-env #指定认证脚本
#username-as-common-name #用户密码登陆方式验证
###########################

########客户端IP固定########
#client-config-dir /etc/openvpn/ccd #启用客户端配置目录
###########################

启动并检查端口

启动openvpn

systemctl start openvpn@server

开机启动openven

systemctl enable openvpn@server

查看网段

ip a s tun0

检查端口

ss -lntup|grep 1194

检查pid

ps -ef|grep openvpn

客户端配置

Window客户端

下载openVpn的客户端

OpenVpn官网

配置本地window环境

ca根证书client.keyclient.crt放入config目录下

cp -rf /opt/easy-rsa/pki/ca.crt /tmp/
cp -rf /opt/easy-rsa/pki/issued/client.crt /tmp/
cp -rf /opt/easy-rsa/pki/private/client.key /tmp/

创建 client.ovpn配置文件

client
dev tun
proto udp
remote x.x.x.x 1194 #注意此处更改为openvpn服务端代码
resolv-retry infinite
nobind
ca ca.crt
cert client.crt
key client.key
verb 3
persist-key
comp-lzo

#账户密码验证
#auth-user-pass

测试连接

连接成功

连接内网其他服务器

【我没验证成功!按需查看】若需要连接内网其他服务器,则开启。

开启 openvpn 服务端开启内核转发

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

Linux客户端

安装openvpn

yum -y install openvpn

安装失败可尝试执行当前命令: yum install epel-release -y

客户端配置文件

vim /etc/openvpn/client.conf

文件内容

client
dev tun
proto udp
remote x.x.x.x 1194 #注意此处更改为openvpn服务端代码
resolv-retry infinite
nobind
ca ca.crt
cert client.crt
key client.key
verb 3
persist-key
comp-lzo
#账户密码验证
#auth-user-pass

复制证书和密钥文件到openvpn目录下

mv /tmp/ca.crt /etc/openvpn/
mv /tmp/client.crt /etc/openvpn/
mv /tmp/client.key /etc/openvpn/

启动客户端

systemctl start openvpn@client

开机启动

systemctl enable openvpn@client

OpenVpn 密码认证

服务端配置

添加配置信息到文件 /etc/openvpn/server.conf

script-security 3                                   #允许使用自定义脚本
auth-user-pass-verify /etc/openvpn/check.sh via-env #指定认证脚本
username-as-common-name #用户密码登陆方式验证

编辑脚本文件

/etc/openvpn/check.sh

#!/bin/bash
PASSFILE="/etc/openvpn/openvpnfile" #密码文件 用户名 密码明文
LOG_FILE="/var/log/openvpn-password.log" #用户登录情况的日志
TIME_STAMP=`date "+%Y-%m-%d %T"`
if [ ! -r "${PASSFILE}" ]; then
echo "${TIME_STAMP}: Could not open password file \"${PASSFILE}\" for reading." >> ${LOG_FILE}
exit 1
fi
CORRECT_PASSWORD=`awk '!/^;/&&!/^#/&&$1=="'${username}'"{print $2;exit}' ${PASSFILE}`
if [ "${CORRECT_PASSWORD}" = "" ]; then
echo "${TIME_STAMP}: User does not exist: username=\"${username}\",password=\"${password}\"." >> ${LOG_FILE}
exit 1
fi
if [ "${password}" = "${CORRECT_PASSWORD}" ]; then
echo "${TIME_STAMP}: Successful authentication: username=\"${username}\"." >> ${LOG_FILE}
exit 0
fi
echo "${TIME_STAMP}: Incorrect password: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE}
exit 1

授予脚本执行权限

chmod +x /etc/openvpn/check.sh

创建用户密码,空格为分割符

cat /etc/openvpn/openvpnfile

重启服务端

systemctl restart openvpn@server

Windows端配置

修改配置文件,底部添加配置

auth-user-pass

连接的时候输入账号密码

Linux端配置

同windows端配置一致,配置文件底部添加

auth-user-pass

重启客户端连接,然后输入账户密码登录

systemctl restart openvpn@client

固定IP地址

ifconfig-pool-persist /etc/openvpn/ipp.txt 这个配置我没验证成功,使用的当前固定IP地址方式

修改openvpn文件,添加配置:

client-config-dir /etc/openvpn/ccd

创建客户端目录

mkdir -p /etc/openvpn/ccd

配置客户端client1文件

可用IP计算公式: x.x.0.(4n+1) - x.x.0.(4n+2)

  • x.x 代表ip端
  • n 代表任意数
echo "ifconfig-push 10.8.0.9 10.8.0.10" > /etc/openvpn/ccd/client1

重启openvpn服务端

systemctl restart openvpn@server

注意:固定IP的文件,需要和配置登录密码的用户一致。

示例:创建的客户端证书文件client01,但是我配置的账号密码用户是mumu,则在固定客户端client01的IP配置时,需要指定的文件名为mumu

alt text

问题记录

固定openVpn的ip地址报错

There is a problem in your selection of --ifconfig endpoints [local=10.8.0.3, remote=10.8.0.4]. The local and remote VPN endpoints must exist within the same 255.255.255.252 subnet. This is a limitation of --dev tun when used with the TAP-WIN32 driver. Try 'openvpn --show-valid-subnets' option for more info.

如何确定可用的IP地址

alt text

上述截图所示有效IP地址

ifconfig-push 10.8.0.1 10.8.0.2
ifconfig-push 10.8.0.5 10.8.0.6

可用IP地址简单计算方式

n 必须是4的倍数,因为每个子网包含4个ip地址

x.x.0.(4*n+1) - x.x.0.(4*n+2)

例如:n = 2

x.x.0.9 - x.x.0.10