Ubuntu架设OpenVPN实现内网穿透

前言

家里的网络因为没有公网 IP,有时候想要连接到家里的树莓派或者电脑就无法实现。这个时候可以采用内网穿透的方法远程连接家中的机器,内网穿透的方案有很多,下面介绍一种采用 OpenVPN 实现内网穿透的方案。


配置

主机:腾讯云/阿里云
操作系统:Ubuntu 16.04/18.04/20.04

教程

安装 OpenVPN

首先,我们需要在服务器安装 OpenVPN。在 Ubuntu 系统中我们可以通过 apt 简单的进行安装。同时我们也需要安装 easy-rsa,它可以帮助我们生成 VPN 使用过程中所需的 CA 证书。

$ sudo apt-get update 

$ sudo apt-get install openvpn easy-rsa
设置 CA 目录

OpenVPN 是使用 TLS/SSL 的 VPN。这意味着它利用证书来加密服务器和客户端之间的通信。为了发布受信任的证书,我们需要建立一个自己的简单的证书颁发机构(CA)。 使用 `make-cadir` 命令复制 easy-rsa 模板到 home 目录。

$ make-cadir ~/openvpn/openvpn-ca

接着进入刚刚新建的目录准备配置 CA:

$ cd ~/openvpn/openvpn-ca

$ ln -s openssl-1.0.0.cnf openssl.cnf
配置 CA 变量

进入 ~/openvpn/openvpn-ca 目录后,我们需要修改 vars 文件,以便于生成需要的 CA 值。

$ vim vars

在文件底部找到以下配置:

...
export KEY_COUNTRY="US"
export KEY_PROVINCE="CA"
export KEY_CITY="SanFrancisco"
export KEY_ORG="Fort-Funston"
export KEY_EMAIL="me@myhost.mydomain"
export KEY_OU="MyOrganizationalUnit"
...

将这些变量修改为任意你喜欢的值,但是不要为空:

...
export KEY_COUNTRY="CN"
export KEY_PROVINCE="ZJ"
export KEY_CITY="HZ"
export KEY_ORG="www.mobibrw.com"
export KEY_EMAIL="xx.com"
export KEY_OU="com.mobibrw"
...

然后,我们还要修改紧接着出现的 `KEY_NAME` 的值,为了简单起见,我们改为 `server`  (这个不要修改成其他名字,后续的配置文件中默认是这个名字), 默认是 `EasyRSA`:

export KEY_NAME="server"
构建 CA 证书

针对 ubuntu 16.04 LTS/ubuntu 18.04 LTS 执行如下操作

首先进入你的 CA 目录,然后执行 `source vars` :

$ cd ~/openvpn/openvpn-ca

$ source vars

接着会有以下输出:

NOTE: If you run ./clean-all, I will be doing a rm -rf on /home/xxxx/openvpn/openvpn-ca/keys

执行下列操作确保操作环境干净:

$ ./clean-all

现在我们可以构建根 CA:

# 如果执行时候报错
# grep: /etc/openvpn/easy-rsa/2.0/openssl.cnf: No such file or directory
# pkitool: KEY_CONFIG (set by the ./vars script) is pointing to the wrong
# version of openssl.cnf: /etc/openvpn/easy-rsa/2.0/openssl.cnf
# The correct version should have a comment that says: easy-rsa version 2.x
# 则可以执行如下命令修复
# ln -s openssl-1.0.0.cnf openssl.cnf

$ ./build-ca

这将会启动创建根证书颁发密钥、证书的过程。由于我们刚才修改了 vars 文件,所有值应该都会自动填充。所以,一路回车就好了:

Generating a 2048 bit RSA private key
..........................................................................................+++
...............................+++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [CN]:
State or Province Name (full name) [ZJ]:
Locality Name (eg, city) [HZ]:
Organization Name (eg, company) [www.mobibrw.com]:
Organizational Unit Name (eg, section) [com.mobibrw]:
Common Name (eg, your name or your server's hostname) [www.mobibrw.com CA]:
Name [mobibrw]:
Email Address [xxx.com]:

现在,我们就有了创建以下步骤需要的 CA 证书。

针对 ubuntu 20.04.6 LTS, 由于OpenVPN版本升级,已经没有上面的命令了,需要调整脚本为如下:

$ cd ~/openvpn/openvpn-ca

$ ./easyrsa init-pki

$ ./easyrsa build-server-full <SERVER_NAME> nopass
创建服务器端证书、密钥和加密文件

通过下列命令生成服务器端证书和秘钥:

$ ./build-key-server server

注:`server` 就是刚才在 `vars` 文件中修改的 `KEY_NAME` 变量的值。请不要使用别的名字! 然后一直回车选择默认值即可,不要设置 `challenge password` ,直接回车即可。到最后,你需要输入两次 y 注册证书和提交。

...
Certificate is to be certified until May  1 17:51:16 2026 GMT (3650 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

然后还需要生成一些其他东西。我们可以在密钥交换过程中生成一个强大的 Diffie-Hellman 密钥:

$ ./build-dh

这个操作大约会花费几分钟不等。 然后,我们可以生成 HMAC 签名加强服务器的 TLS 完整性验证功能:

$ openvpn --genkey --secret keys/ta.key
配置 OpenVPN 服务

首先将刚刚生成的各类文件复制到 OpenVPN 目录下:

$ cd ~/openvpn/openvpn-ca/keys

$ sudo cp ca.crt ca.key server.crt server.key ta.key dh2048.pem /etc/openvpn

然后,解压并复制一个 OpenVPN 配置文件到 OpenVPN 目录:

$ gunzip -c /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz | sudo tee /etc/openvpn/server.conf

$ sudo mkdir -p /etc/openvpn/ccd

接着更改配置,注释掉 `udp` 更改协议为 `tcp` :

proto tcp
;proto udp

找到 tls-auth 位置,去掉注释,并在下面新增一行:

tls-auth ta.key 0 # This file is secret
key-direction 0

去掉 usergroup 行前的注释:

user nobody
group nogroup

去掉 client-to-client 行前的注释允许客户端之间互相访问:

client-to-client

开启客户端固定 IP 配置文件夹:

client-config-dir ccd

去掉注释后的完整配置如下:

#################################################
# Sample OpenVPN 2.0 config file for            #
# multi-client server.                          #
#                                               #
# This file is for the server side              #
# of a many-clients <-> one-server              #
# OpenVPN configuration.                        #
#                                               #
# OpenVPN also supports                         #
# single-machine <-> single-machine             #
# configurations (See the Examples page         #
# on the web site for more info).               #
#                                               #
# This config should work on Windows            #
# or Linux/BSD systems.  Remember on            #
# Windows to quote pathnames and use            #
# double backslashes, e.g.:                     #
# "C:\\Program Files\\OpenVPN\\config\\foo.key" #
#                                               #
# Comments are preceded with '#' or ';'         #
#################################################

# Which local IP address should OpenVPN
# listen on? (optional)
;local a.b.c.d

# Which TCP/UDP port should OpenVPN listen on?
# If you want to run multiple OpenVPN instances
# on the same machine, use a different port
# number for each one.  You will need to
# open up this port on your firewall.
port 1194

# TCP or UDP server?
proto tcp
;proto udp

# "dev tun" will create a routed IP tunnel,
# "dev tap" will create an ethernet tunnel.
# Use "dev tap0" if you are ethernet bridging
# and have precreated a tap0 virtual interface
# and bridged it with your ethernet interface.
# If you want to control access policies
# over the VPN, you must create firewall
# rules for the the TUN/TAP interface.
# On non-Windows systems, you can give
# an explicit unit number, such as tun0.
# On Windows, use "dev-node" for this.
# On most systems, the VPN will not function
# unless you partially or fully disable
# the firewall for the TUN/TAP interface.
;dev tap
dev tun

# Windows needs the TAP-Win32 adapter name
# from the Network Connections panel if you
# have more than one.  On XP SP2 or higher,
# you may need to selectively disable the
# Windows firewall for the TAP adapter.
# Non-Windows systems usually don't need this.
;dev-node MyTap

# SSL/TLS root certificate (ca), certificate
# (cert), and private key (key).  Each client
# and the server must have their own cert and
# key file.  The server and all clients will
# use the same ca file.
#
# See the "easy-rsa" directory for a series
# of scripts for generating RSA certificates
# and private keys.  Remember to use
# a unique Common Name for the server
# and each of the client certificates.
#
# Any X509 key management system can be used.
# OpenVPN can also use a PKCS #12 formatted key file
# (see "pkcs12" directive in man page).
ca ca.crt
cert server.crt
key server.key  # This file should be kept secret

# Diffie hellman parameters.
# Generate your own with:
#   openssl dhparam -out dh2048.pem 2048
dh dh2048.pem

# Network topology
# Should be subnet (addressing via IP)
# unless Windows clients v2.0.9 and lower have to
# be supported (then net30, i.e. a /30 per client)
# Defaults to net30 (not recommended)
;topology subnet

# Configure server mode and supply a VPN subnet
# for OpenVPN to draw client addresses from.
# The server will take 10.8.0.1 for itself,
# the rest will be made available to clients.
# Each client will be able to reach the server
# on 10.8.0.1. Comment this line out if you are
# ethernet bridging. See the man page for more info.
server 10.8.0.0 255.255.255.0

# Maintain a record of client <-> virtual IP address
# associations in this file.  If OpenVPN goes down or
# is restarted, reconnecting clients can be assigned
# the same virtual IP address from the pool that was
# previously assigned.
ifconfig-pool-persist ipp.txt

# Configure server mode for ethernet bridging.
# You must first use your OS's bridging capability
# to bridge the TAP interface with the ethernet
# NIC interface.  Then you must manually set the
# IP/netmask on the bridge interface, here we
# assume 10.8.0.4/255.255.255.0.  Finally we
# must set aside an IP range in this subnet
# (start=10.8.0.50 end=10.8.0.100) to allocate
# to connecting clients.  Leave this line commented
# out unless you are ethernet bridging.
;server-bridge 10.8.0.4 255.255.255.0 10.8.0.50 10.8.0.100

# Configure server mode for ethernet bridging
# using a DHCP-proxy, where clients talk
# to the OpenVPN server-side DHCP server
# to receive their IP address allocation
# and DNS server addresses.  You must first use
# your OS's bridging capability to bridge the TAP
# interface with the ethernet NIC interface.
# Note: this mode only works on clients (such as
# Windows), where the client-side TAP adapter is
# bound to a DHCP client.
;server-bridge

# Push routes to the client to allow it
# to reach other private subnets behind
# the server.  Remember that these
# private subnets will also need
# to know to route the OpenVPN client
# address pool (10.8.0.0/255.255.255.0)
# back to the OpenVPN server.
;push "route 192.168.10.0 255.255.255.0"
;push "route 192.168.20.0 255.255.255.0"

# To assign specific IP addresses to specific
# clients or if a connecting client has a private
# subnet behind it that should also have VPN access,
# use the subdirectory "ccd" for client-specific
# configuration files (see man page for more info).

# EXAMPLE: Suppose the client
# having the certificate common name "Thelonious"
# also has a small subnet behind his connecting
# machine, such as 192.168.40.128/255.255.255.248.
# First, uncomment out these lines:
client-config-dir ccd
;route 192.168.40.128 255.255.255.248
# Then create a file ccd/Thelonious with this line:
#   iroute 192.168.40.128 255.255.255.248
# This will allow Thelonious' private subnet to
# access the VPN.  This example will only work
# if you are routing, not bridging, i.e. you are
# using "dev tun" and "server" directives.

# EXAMPLE: Suppose you want to give
# Thelonious a fixed VPN IP address of 10.9.0.1.
# First uncomment out these lines:
;client-config-dir ccd
;route 10.9.0.0 255.255.255.252
# Then add this line to ccd/Thelonious:
#   ifconfig-push 10.9.0.1 10.9.0.2

# Suppose that you want to enable different
# firewall access policies for different groups
# of clients.  There are two methods:
# (1) Run multiple OpenVPN daemons, one for each
#     group, and firewall the TUN/TAP interface
#     for each group/daemon appropriately.
# (2) (Advanced) Create a script to dynamically
#     modify the firewall in response to access
#     from different clients.  See man
#     page for more info on learn-address script.
;learn-address ./script

# If enabled, this directive will configure
# all clients to redirect their default
# network gateway through the VPN, causing
# all IP traffic such as web browsing and
# and DNS lookups to go through the VPN
# (The OpenVPN server machine may need to NAT
# or bridge the TUN/TAP interface to the internet
# in order for this to work properly).
;push "redirect-gateway def1 bypass-dhcp"

# Certain Windows-specific network settings
# can be pushed to clients, such as DNS
# or WINS server addresses.  CAVEAT:
# http://openvpn.net/faq.html#dhcpcaveats
# The addresses below refer to the public
# DNS servers provided by opendns.com.
;push "dhcp-option DNS 208.67.222.222"
;push "dhcp-option DNS 208.67.220.220"

# Uncomment this directive to allow different
# clients to be able to "see" each other.
# By default, clients will only see the server.
# To force clients to only see the server, you
# will also need to appropriately firewall the
# server's TUN/TAP interface.
client-to-client

# Uncomment this directive if multiple clients
# might connect with the same certificate/key
# files or common names.  This is recommended
# only for testing purposes.  For production use,
# each client should have its own certificate/key
# pair.
#
# IF YOU HAVE NOT GENERATED INDIVIDUAL
# CERTIFICATE/KEY PAIRS FOR EACH CLIENT,
# EACH HAVING ITS OWN UNIQUE "COMMON NAME",
# UNCOMMENT THIS LINE OUT.
;duplicate-cn

# The keepalive directive causes ping-like
# messages to be sent back and forth over
# the link so that each side knows when
# the other side has gone down.
# Ping every 10 seconds, assume that remote
# peer is down if no ping received during
# a 120 second time period.
keepalive 10 120

# For extra security beyond that provided
# by SSL/TLS, create an "HMAC firewall"
# to help block DoS attacks and UDP port flooding.
#
# Generate with:
#   openvpn --genkey --secret ta.key
#
# The server and each client must have
# a copy of this key.
# The second parameter should be '0'
# on the server and '1' on the clients.
tls-auth ta.key 0 # This file is secret
key-direction 0

# Select a cryptographic cipher.
# This config item must be copied to
# the client config file as well.
;cipher BF-CBC        # Blowfish (default)
;cipher AES-128-CBC   # AES
;cipher DES-EDE3-CBC  # Triple-DES
;cipher AES-256-CBC
cipher AES-256-GCM # 尽量使用GCM模式,CBC模式容易遭受Padding Oracle攻击

# Enable compression on the VPN link.
# If you enable it here, you must also
# enable it in the client config file.
# comp-lzo 
# 从2.5版本开始 comp-lzo 被废弃,要求使用 compress lzo 配置
# https://github.com/Nyr/openvpn-install/issues/430
compress lzo

# The maximum number of concurrently connected
# clients we want to allow.
;max-clients 100

# It's a good idea to reduce the OpenVPN
# daemon's privileges after initialization.
#
# You can uncomment this out on
# non-Windows systems.
user nobody
group nogroup

# The persist options will try to avoid
# accessing certain resources on restart
# that may no longer be accessible because
# of the privilege downgrade.
persist-key
persist-tun

# Output a short status file showing
# current connections, truncated
# and rewritten every minute.
status openvpn-status.log

# By default, log messages will go to the syslog (or
# on Windows, if running as a service, they will go to
# the "\Program Files\OpenVPN\log" directory).
# Use log or log-append to override this default.
# "log" will truncate the log file on OpenVPN startup,
# while "log-append" will append to it.  Use one
# or the other (but not both).
;log         openvpn.log
;log-append  openvpn.log
log         /var/log/openvpn/openvpn.log
log-append  /var/log/openvpn/openvpn.log

# Set the appropriate level of log
# file verbosity.
#
# 0 is silent, except for fatal errors
# 4 is reasonable for general usage
# 5 and 6 can help to debug connection problems
# 9 is extremely verbose
verb 3

# Silence repeating messages.  At most 20
# sequential messages of the same message
# category will be output to the log.
;mute 20

去掉注释之后,精简的关键信息如下:

port 1194
proto tcp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
client-config-dir ccd
client-to-client
keepalive 10 120
tls-auth ta.key 0
key-direction 0

# 尽量使用GCM模式,CBC模式容易遭受Padding Oracle攻击
cipher AES-256-GCM

# 从2.5版本开始 comp-lzo 被废弃,要求使用 compress lzo 配置
# https://github.com/Nyr/openvpn-install/issues/430
compress lzo

user nobody
group nogroup
persist-key
persist-tun
status openvpn-status.log
verb 3
调整服务器网络配置
调整 `UFW` 规则

首先,确认`UFW`防火墙状态,如果状态为开启,则调整。如果防火墙是关闭的,则不需要调整。

$ sudo ufw status

如果输出是`Status: inactive`, 那么不需要进行下面的调整。

注意,下面的调整如果中间出现问题,可能导致防火墙拦截`SSH`进而无法进行恢复操作。如果出现问题,可以使用阿里云或者腾讯云提供的远程控制台在网页端进行恢复操作。

注意,如果服务器是从早期版本的`ubuntu 14.04`升级到`ubunt 16.04`的,那么可能会出现如下警告信息:

WARN: Duplicate profile 'Apache', using last found
WARN: Duplicate profile 'Apache Secure', using last found
WARN: Duplicate profile 'Apache Full', using last found

原因为存在两个版本的防火墙配置文件 `apache2-utils.ufw.profile`(`ubunt 16.04`) , `apache2.2-common`(`ubuntu 14.04`) ,这两个配置文件。

我们需要删除早期的防火墙配置文件,如下:

$ sudo rm -rf /etc/ufw/applications.d/apache2.2-common

如果服务器上`UFW`首次启用, 需要手工许可若干常用服务,否则无法远程访问:

# 默认情况下存在 "Apache"(80) "Apache Secure"(443) "Apache Full"(80,443) 三个配置项,我们一般使用"Apache Full"
$ sudo ufw allow "Apache Full"

# 同理 Nginx 对应的是 "Nginx Full"

# 许可SSH服务,注意: 如果 SSH 服务端口修改过,需要确认两者端口是否一致(默认是22),配置文件位于 "/etc/ufw/applications.d/" 目录
$ sudo ufw allow "OpenSSH"

当然,也可以直接配置需要开放的端口,但是不推荐,如下:

$ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp

如果需要删除特定的规则,那么参考如下命令:

$ sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----               
[ 1] Apache Full                ALLOW IN    Anywhere                              
[ 2] Apache Full (v6)           ALLOW IN    Anywhere (v6) 

$ sudo ufw delete <编号>

打开 OpenVPN 端口并使变化生效

$ sudo ufw allow 1194/tcp

$ sudo ufw disable

$ sudo ufw enable
启动OpenVPN

执行:

$ sudo mkdir -p /etc/openvpn/ccd

$ sudo systemctl start openvpn@server

#如果启动失败,则执行如下命令观察日志
# sudo tail -f /var/log/syslog

设置开机自启:

$ sudo systemctl enable openvpn@server

创建客户端配置

生成客户端证书、密钥对
$ cd ~/openvpn/openvpn-ca

$ source vars

$ cp /etc/openvpn/ca.crt ./keys/

$ sudo cp /etc/openvpn/ca.key ./keys/

$ sudo cp /etc/openvpn/ta.key ./keys/

$ sudo chmod 755 ./keys/ca.crt

$ sudo chmod 755 ./keys/ta.key

$ ./build-key client-mobibrw

`client-mobibrw` 为密钥对名称,生成过程中回车选择默认选项即可。

注意,下面这一步一定要输入 `y` 否则会跳过最后一步,导致生成证书的时候会缺少部分信息。

Certificate is to be certified until May 29 11:40:12 2029 GMT (3650 days)

Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

注意,如果有多个客户端的话,建议为每个客户端生成一份配置文件。

创建客户端配置

执行下列命令,生成客户端配置的基础文件:

$ mkdir -p ~/client-configs/files

$ chmod 700 ~/client-configs/files

$ cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf

然后打开 `~/client-configs/base.conf` 文件,修改 `remote my-server-1 1194` 为服务器公网IP或者域名。 然后更改客户端协议为 `tcp`:

# Are we connecting to a TCP or
# UDP server?  Use the same setting as
# on the server.
proto tcp
;proto udp

去掉 `user` 和 `group` 前的注释:

# Downgrade privileges after initialization (non-Windows only)
user nobody
group nogroup

找到 ca/cert/key,注释掉:

# SSL/TLS parms.
# See the server config file for more
# description.  It's best to use
# a separate .crt/.key file pair
# for each client.  A single ca
# file can be used for all clients.
#ca ca.crt
#cert client.crt
#key client.key

在文件中新增一行:

key-direction 1

保存退出文件。

##############################################
# Sample client-side OpenVPN 2.0 config file #
# for connecting to multi-client server.     #
#                                            #
# This configuration can be used by multiple #
# clients, however each client should have   #
# its own cert and key files.                #
#                                            #
# On Windows, you might want to rename this  #
# file so it has a .ovpn extension           #
##############################################

# Specify that we are a client and that we
# will be pulling certain config file directives
# from the server.
client

# Use the same setting as you are using on
# the server.
# On most systems, the VPN will not function
# unless you partially or fully disable
# the firewall for the TUN/TAP interface.
;dev tap
dev tun

# Windows needs the TAP-Win32 adapter name
# from the Network Connections panel
# if you have more than one.  On XP SP2,
# you may need to disable the firewall
# for the TAP adapter.
;dev-node MyTap

# Are we connecting to a TCP or
# UDP server?  Use the same setting as
# on the server.
proto tcp
;proto udp

# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
remote www.mobibrw.com 1194
;remote my-server-2 1194

# Choose a random host from the remote
# list for load-balancing.  Otherwise
# try hosts in the order specified.
;remote-random

# Keep trying indefinitely to resolve the
# host name of the OpenVPN server.  Very useful
# on machines which are not permanently connected
# to the internet such as laptops.
resolv-retry infinite

# Most clients don't need to bind to
# a specific local port number.
nobind

# Downgrade privileges after initialization (non-Windows only)
user nobody
group nogroup

# Try to preserve some state across restarts.
persist-key
persist-tun

# If you are connecting through an
# HTTP proxy to reach the actual OpenVPN
# server, put the proxy server/IP and
# port number here.  See the man page
# if your proxy server requires
# authentication.
;http-proxy-retry # retry on connection failures
;http-proxy [proxy server] [proxy port #]

# Wireless networks often produce a lot
# of duplicate packets.  Set this flag
# to silence duplicate packet warnings.
;mute-replay-warnings

# SSL/TLS parms.
# See the server config file for more
# description.  It's best to use
# a separate .crt/.key file pair
# for each client.  A single ca
# file can be used for all clients.
#ca ca.crt
#cert client.crt
#key client.key
key-direction 1

# Verify server certificate by checking that the
# certicate has the correct key usage set.
# This is an important precaution to protect against
# a potential attack discussed here:
#  http://openvpn.net/howto.html#mitm
#
# To use this feature, you will need to generate
# your server certificates with the keyUsage set to
#   digitalSignature, keyEncipherment
# and the extendedKeyUsage to
#   serverAuth
# EasyRSA can do this for you.
remote-cert-tls server

# If a tls-auth key is used on the server
# then every client must also have the key.
;tls-auth ta.key 1

# Select a cryptographic cipher.
# If the cipher option is used on the server
# then you must also specify it here.
;cipher x
;cipher AES-256-CBC
# 尽量使用GCM模式,CBC模式容易遭受Padding Oracle攻击
cipher AES-256-GCM

# Enable compression on the VPN link.
# Don't enable this unless it is also
# enabled in the server config file.
# comp-lzo
# 从2.5版本开始 comp-lzo 被废弃,要求使用 compress lzo 配置
# https://github.com/Nyr/openvpn-install/issues/430
compress lzo

# Set log file verbosity.
verb 3

# Silence repeating messages
;mute 20

去掉注释后的完整配置为:

client
dev tun
proto tcp
remote www.mobibrw.com 1194
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
remote-cert-tls server

# 尽量使用GCM模式,CBC模式容易遭受Padding Oracle攻击
cipher AES-256-GCM 

key-direction 1

# 从2.5版本开始 comp-lzo 被废弃,要求使用 compress lzo 配置
# https://github.com/Nyr/openvpn-install/issues/430
compress lzo

verb 3

创建配置生成脚本

新建 ~/client-configs/make_config.sh 文件,复制如下内容:

#!/bin/bash
# First argument: Client identifier

cd ~/openvpn/openvpn-ca
source vars
./build-key ${1}

KEY_DIR=~/openvpn/openvpn-ca/keys
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf
cat ${BASE_CONFIG} \
    <(echo -e '<ca>') \
    ${KEY_DIR}/ca.crt \
    <(echo -e '</ca>\n<cert>') \
    ${KEY_DIR}/${1}.crt \
    <(echo -e '</cert>\n<key>') \
    ${KEY_DIR}/${1}.key \
    <(echo -e '</key>\n<tls-auth>') \
    ${KEY_DIR}/ta.key \
    <(echo -e '</tls-auth>') \
    > ${OUTPUT_DIR}/${1}.ovpn

针对 ubuntu 20.04.6 LTS, 由于OpenVPN版本升级,已经没有上面的命令了,需要调整脚本为如下:

#!/bin/bash
# First argument: Client identifier

cd ~/openvpn/openvpn-ca
#source vars
./easyrsa build-client-full ${1} nopass

PKI_DIR=~/openvpn/openvpn-ca/pki
KEY_DIR=${PKI_DIR}/issued
PRIV_DIR=${PKI_DIR}/private
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf
cat ${BASE_CONFIG} \
    <(echo -e '<ca>') \
    ${PKI_DIR}/ca.crt \
    <(echo -e '</ca>\n<cert>') \
    ${KEY_DIR}/${1}.crt \
    <(echo -e '</cert>\n<key>') \
    ${PRIV_DIR}/${1}.key \
    <(echo -e '</key>\n<tls-auth>') \
    ${PKI_DIR}/ta.key \
    <(echo -e '</tls-auth>') \
    > ${OUTPUT_DIR}/${1}.ovpn

保存并赋予执行权限:

$ chmod 700 ~/client-configs/make_config.sh

生成客户端配置

执行:

$ cd ~/client-configs

$ ./make_config.sh client-mobibrw

使用此脚本生成一个配置文件方便客户端使用。 注:需要生成客户端密钥后才可使用脚本生成配置文件,`client-mobibrw.ovpn` 为刚刚生成的客户端密钥名称 生成后的脚本储存在 `~/client-configs/files` 目录下,名称为 `client-mobibrw.ovpn`。将文件下载到本地即可使用了。

为客户端设置固定IP

首先在OpenVPN所在的文件夹内创建`ccd`文件夹:

$ sudo mkdir -p /etc/openvpn/ccd

然后进入该文件夹并创建与客户端密钥同名的文件:

$ cd /etc/openvpn/ccd

$ vim client-mobibrw

文件内容如下:

ifconfig-push 10.8.0.8 10.8.0.9

此内容意为固定`client-mobibrw`客户端的`OpenVPN`内网`IP`为`10.8.0.8`。

注意,上面的配置在客户端是Windows系统的时候,会报告如下错误:

There is a problem in your selection of --ifconfig endpoints [local=10.8.0.8, remote=10.8.0.9].  The local and remote VPN endpoints cannot use the first or last address within a given 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.

导致这个错误的原因是 TAP-WIN32 使用默认子网掩码 255.255.255.252 因此一个网段之内只能有两个相邻IP,一个是网关,一个是子网设备。

这个问题在 Linux/macOS 系统上是不存在的,这个是 TAP-WIN32 驱动的限制。

因此,如果系统是 Windows 并且使用 TAP-WIN32 驱动,那么配置的地址只能是如下情况:

ifconfig-push 10.8.0.10 10.8.0.9

或者

ifconfig-push 10.8.0.11 10.8.0.10

或者

ifconfig-push 10.8.0.20 10.8.0.19

前面为设备地址,后面为网关IP. 规律就是 设备地址是 网关地址 +1

客户端命令行使用

首先安装`OpenVPN`, 运行时选择配置为客户端配置文件:

$ sudo apt install openvpn

$ sudo openvpn --config client-mobibrw.ovpn

使用此方法可以让家里的电脑或者树莓派等设备实现内网穿透,从而远程连接进行操作。

对于客户端是`macOS`的设备来说,推荐使用`Tunnelblick`。

服务器上查看连接上的客户端列表,则执行如下命令:"`cat /etc/openvpn/openvpn-status.log`" 也可能是"`cat /var/log/openvpn/openvpn-status.log`"

对于`Debian`/`Ubuntu`/`WDMyCloud`等设备,我们把配置文件放到`/etc/openvpn/`并且重命名为`client-mobibrw.conf`,(也就是扩展名为 `.conf`)可以实现开机自动启动连接。

`WDMyCloud` 查看日志

$ tail -f /var/log/daemon.log

如果日志中出现

Authenticate/Decrypt packet error: cipher final failed

则需要注释掉 

;cipher AES-256-CBC

常用的几条客户端命令如下:

# ubuntu 16.04 启用客户端配置文件,注意 .service 中的.代表任意匹配,等价于我们上面的 client-mobibrw.service
# 这样才能实现服务的开机自启动
$ sudo systemctl enable openvpn@.service

# ubuntu 16.04 观察服务运行状态
$ sudo systemctl status openvpn@client-mobibrw.service

对于`群晖`来说,`group nogroup`这个用户组是不存在,我们需要注释掉这一行,但是`user nobody`是存在的。

`群晖 DSM 6.2/7.0`测试的命令如下:

# 群晖系统升级之后,需要重新执行这一句命令,重新启用内核模块,一般需要重启系统
$ sudo insmod /lib/modules/tun.ko

# 启用后执行如下命令可以观察是否启用成功
$ lsmod | grep tun

# 系统需要重启
$ sudo reboot

# 成功后应该能观察到已经获取到的IP地址信息,一般网卡名 tun0
$ ip address 

# DSM 7.1-42661 Update 1 版本没有自动创建节点,需要手工创建
$ sudo mkdir /dev/net

$ sudo mknod /dev/net/tun c 10 200

$ sudo reboot

$ sudo openvpn --config client-mobibrw.ovpn

对于`群晖 DSM 6.2/7.0`来说,我们把配置文件放到`/usr/syno/etc/synovpnclient/openvpn/`并且重命名为`client-mobibrw.conf`,(也就是扩展名为`.conf`), 然后执行如下命令:

$ sudo touch /usr/syno/etc.defaults/rc.sysv/S199OpenVPNClient.sh

$ sudo chmod +x /usr/syno/etc.defaults/rc.sysv/S199OpenVPNClient.sh

文件内容如下:

#!/bin/sh

case $1 in
    start)	
	
	CONF_DIR="/usr/syno/etc/synovpnclient/openvpn"
	for file in `ls $CONF_DIR`
	do
		if [ -f "$CONF_DIR/$file" ]; then
			/usr/syno/etc.defaults/synovpnclient/scripts/ovpnc.sh start $file
		fi
	done
	;;
	stop)
	;;
esac

`DSM 6.2/7.0` 中增加计划任务,设定为开机自动运行脚本,如下图:

可以实现开机自动启动连接。

注:该方法只有连接内网机器时会使用OpenVPN代理,平时访问网页等不会走代理,并不是全局代理,节省服务带宽的使用

常见问题

如果运行时候报错(一般发生在ubuntu 20.04系统)

error: --explicit-exit-notify can only be used with --proto udp

则注释掉 `#explicit-exit-notify 1` ,此选项开启只能使用`UDP`协议

参考链接


发布者

《Ubuntu架设OpenVPN实现内网穿透》上有4条评论

    1. frp 属于后起之秀,目前来说还不是足够成熟,一些平台,比如群晖,自身没有携带,编译安装也比较麻烦。对于标准的Linux服务器来说,frp 算是一个不错的选择。更多的是使用习惯的问题吧。
    1. 这个貌似需要使用专用的代理服务器软件实现,默认情况下,这些开源软件没有实现这么复杂的功能,不过一般都有商业版本来补充这些功能。

      当然,如果用户不多,可以试试docker给每个用户单独部署一个docker进程,每个docker进程映射一个独立的端口出来,用户使用自己的独立docker服务器。

      当然也可以共享一个端口,根据链接地址的不同重定向到不同的用户使用的docker进程上。

回复 默默 取消回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注