使用 OpenVPN 远程访问家里的 NAS

110 阅读6分钟

1. 动机

  1. 希望将 NAS 放在家里,原因是家里的宽带速率高,比起在深圳使用4G卡上网的高。
  2. 尝试过 tailscale 或者 zerotier 之类的打洞,不好用,经常断连,且速度不高。
  3. 尝试过 frp 内网穿透,但是这种没有准入限制,被人扫到端口一直在爆破账号密码。

综上,计划使用标准的 VPN 来远程访问,一来标准 VPN 协议被 NAS 原生支持,二来我在国内有服务器可以搭建,不用担心一些不可抗力。

2. 安装 OpenVPN

官方的安装方法如下,详见文档:

# sudo mkdir -p /etc/apt/keyrings
# curl -fsSL https://swupdate.openvpn.net/repos/repo-public.gpg | sudo tee /etc/apt/keyrings/openvpn-repo-public.asc
# sudo echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/openvpn-repo-public.asc] https://build.openvpn.net/debian/openvpn/stable focal main" > /etc/apt/sources.list.d/openvpn-aptrepo.list
# sudo apt update
# sudo apt install openvpn
# sudo proxychains4 apt install openvpn-dco-dkms

第2版更新:这一步建议先执行 apt search openvpn 来看一下已知的源里面有没有,有就可以直接安装,不需要用官方的源,官方的源要用代理很麻烦。我后来在腾讯云里面的源发现了有 openVPN 2.6 ,能直接安装,就不需要搞一堆代理了,省事~

apt update
apt install openvpn
apt install openvpn-dco-dkms openvpn-systemd-resolved easy-rsa # 执行安装 openvpn 时提示我建议安装这些库,就都安装了。其中的 easy-rsa 后面要用。

3. 构建证书密钥及配置文件

配置文件需要好多个公钥私钥乱七八糟的,先列一个表,有个总体概览。参考文档

文件服务器配置需要客户端配置需要私密
ca.crt-
ca.key--
dh{n}.pem--
server.crt--
server.key-
client.crt--
client.key-
ta.key

3.1 初始化 rsa 工具

第一步:准备 Easy-RSA 环境

mkdir ~/openVPN
cd ~/openVPN/
make-cadir ./build-ca
# 此时目录结构为
# openVPN
# └── build-ca
#     ├── easyrsa -> /usr/share/easy-rsa/easyrsa
#     ├── openssl-easyrsa.cnf
#     ├── vars
#     └── x509-types -> /usr/share/easy-rsa/x509-types

第二步:配置 vars 文件

# 复制配置模板(如有 vars 文件就可以忽略这一步)
cp vars.example vars
# 编辑配置文件
nano vars

推荐的配置为:

set_var EASYRSA_REQ_COUNTRY     "CN"                # "国家"
set_var EASYRSA_REQ_PROVINCE    "Beijing"           # "省份"
set_var EASYRSA_REQ_CITY        "Beijing"           # "城市"
set_var EASYRSA_REQ_ORG         "MyCompany"         # "公司"
set_var EASYRSA_REQ_EMAIL       "admin@example.com" # "邮件"
set_var EASYRSA_REQ_OU          "IT Department"     # "部门"
set_var EASYRSA_KEY_SIZE        2048                # 密钥大小(推荐 2048 或 4096)
set_var EASYRSA_CA_EXPIRE       3650                # CA 证书有效期(默认 3650 天,即 10 年)
set_var EASYRSA_CERT_EXPIRE     825                 # 服务器和客户端证书有效期(默认 825 天)
set_var EASYRSA_ALGO            rsa                 # 使用的加密算法
set_var EASYRSA_DIGEST          "sha256"            # 摘要算法

第三步:初始化 PKI

# 初始化 PKI(公钥基础设施)
./easyrsa init-pki

# 输出:
# Notice
# ------
# 'init-pki' complete; you may now create a CA or requests.
# Your newly created PKI dir is:
# * ~/openvpn/build-ca/pki
# Using Easy-RSA configuration:
# * ~/openvpn/build-ca/vars

目录结构:

复制
pki/
├── private/      # 私钥目录(重要!需要保密)
├── reqs/         # 证书请求目录
└── issued/       # 已签发的证书目录

3.2 生成各种文件

先搞一个产物目录,用来保存所有的证书,以便于之后构建配置文件。

mkdir ~/openvpn/configs

生成 CA 证书和 DH 文件。

# 生成 CA 证书,产物在:~/openvpn/build-ca/pki/ca.crt
./easyrsa build-ca nopass

# 生成 DH 文件(默认参数是 2048),产物在:~/openvpn/build-ca/pki/dh.pem
./easyrsa gen-dh

# 复制产物
cp ~/openvpn/build-ca/pki/ca.crt ~/openvpn/configs/
cp ~/openvpn/build-ca/pki/dh.pem ~/openvpn/configs/

生成服务器端的证书。假设服务器的名字叫 center

./easyrsa gen-req center nopass
# Private-Key and Public-Certificate-Request files created.
# Your files are:
# * req: ~/openvpn/build-ca/pki/reqs/center.req
# * key: ~/openvpn/build-ca/pki/private/center.key

./easyrsa sign server center
# Certificate created at:
# * ~/openvpn/build-ca/pki/issued/center.crt

# 复制产物
cp ~/openvpn/build-ca/pki/issued/center.crt ~/openvpn/configs/
cp ~/openvpn/build-ca/pki/private/center.key ~/openvpn/configs/

生成客户端的证书,如果有多个客户端,建议生成多个,比如 alicebob

./easyrsa gen-req alice nopass
# Private-Key and Public-Certificate-Request files created.
# Your files are:
# * req: ~/openvpn/build-ca/pki/reqs/alice.req
# * key: ~/openvpn/build-ca/pki/private/alice.key

./easyrsa sign client alice
# Certificate created at:
# * ~/openvpn/build-ca/pki/issued/alice.crt

# 复制产物
cp ~/openvpn/build-ca/pki/issued/alice.crt ~/openvpn/configs/
cp ~/openvpn/build-ca/pki/private/alice.key ~/openvpn/configs/

# 一行命令执行完(偷懒版,需替换里面的 bob 为对应的 client 名称):
# NAME=bob bash -c './easyrsa gen-req "$NAME" nopass && ./easyrsa sign client "$NAME" && cp ~/openvpn/build-ca/pki/{issued/"$NAME".crt,private/"$NAME".key} ~/openvpn/configs/'

(如果有需要的话,)启用 tls-auth 会更加安全,尤其是对于 udp 模式。启用 tls-auth 需要生成 ta.key ,这需要用 openvpn 来生成。

cd ~/openvpn/configs/
openvpn --genkey secret ta.key

最后看一下配置文件目录下有哪些文件,下一步就准备用这些文件来生成配置文件了。

tree ~/openvpn/configs/
# ~/openvpn/configs/
# ├── ca.crt
# ├── center.crt
# ├── center.key
# ├── dh.pem
# ├── alice.crt
# ├── alice.key
# ├── bob.crt
# ├── bob.key
# └── ta.key

3.2 构建服务器端和客户端配置文件

配置文件我偏好使用单文件形式,即将公钥私钥等文件都写进ovpn文件。配置文件的格式可以见OpenVPN 2.6 服务器端+客户端示例配置文件(含中文注释)

server 端文件模版

port 1194
proto udp ; or "tcp"
dev tun
topology subnet
server 10.4.0.0 255.255.255.0
ifconfig-pool-persist /var/log/openvpn/ipp.txt
;push "route 192.168.10.0 255.255.255.0"
client-to-client
keepalive 10 120
user openvpn  ; 初始化后将 OpenVPN 进程权限降低到 openvpn 用户
group openvpn ; 初始化后将 OpenVPN 进程权限降低到 openvpn 用户组
persist-tun
status     /var/log/openvpn/openvpn-status.log
log-append /var/log/openvpn/openvpn.log
verb 3
;mute 20

; ==== inline certificates and keys ====
<ca>
# 将 ca.crt 的内容填入这里
</ca>
<dh>
# 将 dh.pem 的内容填入这里
</dh>
<cert>
# 将 center.crt 的内容填入这里
</cert>
<key>
# 将 center.key 的内容填入这里
</key>

; ==== enable tls-auth ====
; 服务器端的方向是 0
key-direction 0
<tls-auth>
# 将 ta.key 的内容填入这里
</tls-auth>

client 端文件模板(以客户端 alice 为例,其中的[server-ip]需要替换成服务器地址,可以IP形式也可以域名形式)

client
dev tun
proto udp ; or "tcp"
remote [server-ip] 1194
resolv-retry infinite
nobind
;user openvpn
;group openvpn
persist-tun
;mute-replay-warnings
remote-cert-tls server
verb 3
;mute 20

; ==== inline certificates and keys ====
<ca>
# 将 ca.crt 的内容填入这里
</ca>
<cert>
# 将 alice.crt 的内容填入这里
</cert>
<key>
# 将 alice.key 的内容填入这里
</key>

; ==== enable tls-auth ====
; 客户端的方向是 1
key-direction 1
<tls-auth>
# 将 ta.key 的内容填入这里
</tls-auth>

4. 注册系统服务(开机自启动)

首先创建一个 openvpn 用户和用户组,将 OpenVPN 进程权限降低到 openvpn 用户/用户组。

groupadd -r openvpn
useradd -r -s /usr/sbin/nologin -g openvpn -c "OpenVPN Service User" openvpn

# 验证创建结果
id openvpn
getent group openvpn

检查 openvpn 是否支持 systemd,一般用 apt 安装的都会支持。

openvpn --version | grep systemd
# ... enable_systemd=yes ...

把服务器的配置文件复制到 /etc/openvpn/server/ 目录下,然后用 systemctl 来管理。systemctl 管理时候,server名字的 @ 后面的名字,要跟配置文件名字保持一致。参考文档

sudo cp ~/openvpn/configs/center.ovpn /etc/openvpn/server/center.conf
sudo systemctl start openvpn-server@center  # 启动 openvpn
sudo systemctl enable openvpn-server@center # 设置开机启动
sudo systemctl status openvpn-server@center # 检查状态

需要注意,如果发现 openvpn 服务器的 client-to-client 不生效,可能与系统配置有关。需要按照下面的操作配置一下 ipv4 转发(我暂时没有用 ipv6 )。

sudo sysctl -w net.ipv4.ip_forward=1
sysctl net.ipv4.ip_forward
sudo sysctl -p /etc/sysctl.conf