跳到主要内容

Linux 上的 VPN 并不一定需要窗口。很多人整天待在终端里,通过 SSH 操作机器,或者管理根本没有桌面的服务器。对他们来说,用一条命令就能启动的隧道更简单,也更容易自动化。简单的代价是:命令行允许你做图形工具不会让你做的事,比如把你正在输入的那个 SSH 会话本身切断。

本文讲的是 Linux 命令行下的 VPN 用法。我们不教什么是 VPN,也不重复 Linux 设置指南里的桌面安装步骤。这里假设你已经有一份来自雇主、学校实验室或自己服务器的配置文件,想要在 shell 里把它启动、保持、检查并干净地关闭。

什么时候命令行是合适的工具

出现下面任一情况时,选择命令行。

  • 机器没有桌面。 比如 VPS、橱柜里的树莓派,或没有显示器的家用服务器。
  • 你通过 SSH 连接。 你只想为某项工作开一条隧道,用完干净退出。
  • 你想写成脚本。 比如只有隧道存在时才通过它运行的备份任务,或定时检查隧道状态的 cron 任务。
  • 你想看到全部过程。 终端输出会显示每一步,比只写“失败”的菜单好得多。

如果你用的是整天切换 Wi-Fi 的笔记本,则选择图形工具。NetworkManager 会响应这些变化,而一条普通命令不会。在 NetworkManager 中添加 VPN一文讲的就是那一侧。

连接前的五项检查

在这里花三十秒,可以避免大部分麻烦。

  1. 文件属于谁? 运行 ls -l wg0.conf 或检查 .ovpn 文件。它应该属于你或 root,且其他人不可读,因为里面可能有私钥。chmod 600 文件名 可以解决。
  2. 隧道是否已经启动? ip link show type wireguard 和 ip addr | grep tun 能显示遗留的接口。两个同名隧道会冲突。
  3. 当前路由是什么? 保存 ip route 和 ip -6 route 的输出,之后用来对比,出问题时也能据此恢复。
  4. DNS 现状如何? resolvectl status 会在隧道改动之前显示当前的服务器。
  5. 有没有第二条进入途径? 如果你在用 SSH,启动全隧道之前,先确认可以通过其他方式进入机器,比如控制台或带外会话。

连接前,先用 IP 检测页面记下你的公网地址。你需要“之前”的值,才能看出变化。

从终端连接的三种方式

工具 命令 适合 注意
wg-quick sudo wg-quick up wg0 WireGuard 配置,一条命令设置地址、路由和 DNS 需要解析器钩子,DNS 行才会生效
openvpn sudo openvpn --config work.ovpn .ovpn 文件,在前台运行并输出进度 会占用终端,除非作为服务或守护进程运行
nmcli nmcli connection up work 已保存在 NetworkManager 中的配置 配置必须事先存在

这些工具不要混用。如果 NetworkManager 已经在管理名为 wg0 的接口,就不要再执行 wg-quick up wg0。选定一个管理者。想了解这些工具背后两种协议的取舍,请阅读 WireGuard 与 OpenVPN 对比和 OpenVPN 详解。

逐步启动隧道

用 wg-quick 运行 WireGuard。 把文件放到 /etc/wireguard/wg0.conf,然后执行:

sudo wg-quick up wg0
sudo wg show
sudo wg-quick down wg0

wg show 的输出会列出对端、endpoint 和“latest handshake”时间。如果半分钟后仍没有握手那一行,说明服务器没有应答。接口名来自文件名,所以 office.conf 对应的接口叫 office。

前台运行 OpenVPN。 运行客户端并阅读输出。

sudo openvpn --config ~/work.ovpn

成功时,最后会出现一行表示初始化序列已完成。按 Ctrl+C 停止。如果凭据保存在文件里,加上 --auth-user-pass /path/to/auth.txt,并让该文件只有 root 可读。要在后台运行,加上 --daemon 和 --log /var/log/openvpn-work.log,然后阅读日志。

在 shell 中使用 NetworkManager。 如果配置已存在,nmcli connection up work 和 nmcli connection down work 就够了,nmcli -p connection show work 会打印完整配置。

实验时的小技巧:再开一个终端,运行 watch -n 2 'ip route; echo; resolvectl status | head -20',隧道一启动,你就能看到路由和 DNS 的变化。

SSH 陷阱:别锯断自己坐着的树枝

这是命令行下最常见的错误。如果你通过 SSH 连着服务器,又启动了全隧道,默认路由就会改变。服务器可能把回应你 SSH 客户端的数据包送进隧道,而客户端期待它们来自原来的路径。会话随即卡死,往往还无法重新登录。

避免的办法如下。

  1. 为自己的地址豁免。 连接之前,为 SSH 客户端的地址添加一条经原网关的路由,例如 sudo ip route add 203.0.113.10 via 192.0.2.1 dev eth0。把数值换成你自己的,取自之前保存的 ip route 输出。
  2. 使用窄隧道。 把 AllowedIPs 设为你需要的几个子网,而不是 0.0.0.0/0,这样默认路由不会被改动。
  3. 用计时器测试。 带一个“死人开关”启动隧道:sudo wg-quick up wg0; sleep 120; sudo wg-quick down wg0,在终端复用工具中运行,一旦你丢了会话,隧道会自己关闭。
  4. 保留控制台。 云服务器和家用服务器应该有一条不依赖你正在更改的网络的进入途径。

上面的 192.0.2.0/24 和 203.0.113.0/24 是为文档保留的地址段,作为示例很安全;请换成你自己的。

退出登录后保持运行

在终端里启动的隧道会随终端一起结束。可以用下面任一方式。

  • WireGuard 用 systemd。 sudo systemctl enable --now wg-quick@wg0 会立即启动,并在每次开机时启动。sudo systemctl status wg-quick@wg0 显示是否在运行。用 sudo systemctl disable --now wg-quick@wg0 关闭。
  • OpenVPN 用 systemd。 发行版通常提供读取客户端目录中文件的客户端单元,名字类似 openvpn-client@NAME。把配置放到那里并启用单元,具体路径因发行版而异,请查看软件包说明。
  • tmux 或 screen 用于快速测试。 在会话中运行前台命令后分离。用一个下午没问题,但不适合你要依赖的场景。

如果服务必须在网络就绪之后启动,请确认单元等待 network-online 目标。在开机比 Wi-Fi 更快的机器上,启动过早的隧道会失败并一直保持关闭。

证明它确实在工作

不要相信沉默。做四项检查。

ip route get 1.1.1.1
sudo wg show
resolvectl query example.org
curl -s https://example.org -o /dev/null -w "%{http_code}\n"
  1. ip route get 显示发往外部地址的流量走哪个接口。对于全隧道,它应该是 VPN 接口。
  2. wg show 应该报告最近的握手,且传输计数器在增长。
  3. resolvectl query 显示是哪条链路应答了 DNS 查询,为什么这很重要,可以在 Cloudflare Learning 网站的DNS 是什么里了解。如果应答来自你的 Wi-Fi 链路,说明域名查询绕过了隧道。
  4. curl 确认普通网页流量可用。

然后把你的公网地址与之前保存的值对比。包含泄漏和故障行为在内的完整测试方法见如何测试 VPN。如果你担心隧道中断时流量外泄,请阅读 Linux VPN kill switch。

一个简短的场景可以说明这些环节如何配合。阿杰维护着一台家用服务器,希望每晚的备份通过隧道传到办公室的机器上。他写了一个小脚本:启动隧道,等到 wg show 报告握手,执行复制,然后无论复制成功与否都关闭隧道。由于脚本不对默认路由做任何保存或恢复,他使用只覆盖办公室子网的窄 AllowedIPs,服务器的普通流量完全不变。日志记录了握手时间和退出状态,所以哪天失败了,第二天早上很容易诊断。

断开并清理

关闭之后,机器应该回到最初的状态。

  1. 停止隧道:sudo wg-quick down wg0,前台的 OpenVPN 按 Ctrl+C,服务则用 sudo systemctl stop。
  2. 把 ip route 与保存的副本对比。隧道遗留的路由可以用 sudo ip route del 删除。
  3. 检查 resolvectl status,隧道的 DNS 条目应已从主链路上消失。
  4. 删除为 SSH 而添加的临时路由。
  5. 删除为测试创建的凭据,例如主目录里的 auth 文件。

如果崩溃留下了遗留接口,sudo ip link delete wg0 可以删除它。

按提示信息排查

看到的信息 通常含义 可以尝试
RTNETLINK answers: Operation not permitted 没有以 root 身份运行 加上 sudo
Cannot find device "wg0" 接口未启动,或名称与文件名不一致 检查文件名,运行 ip link
Error: Unknown device type 内核或工具不支持 WireGuard 安装 wireguard-tools,检查内核
TLS Error: TLS key negotiation failed 数据包没有到达 OpenVPN 服务器 检查服务器地址、端口和系统时间
没有握手 密钥错误、endpoint 错误或端口被拦截 检查公钥和 endpoint,换一个网络试试
已连接但 DNS 失败 DNS 行被忽略 检查解析器钩子,使用 resolvectl status
连接后会话卡死 默认路由被移走 重启或通过控制台进入,参考上文 SSH 建议

VPN 无法连接中更完整的清单同样适用。

总结

在 Linux 终端中连接 VPN,归结为一套简短流程:连接前做检查并保存路由,用一个工具启动隧道,在改变默认路由之前保护好 SSH 会话,若需要在退出登录后保持就作为服务运行,用路由、握手、DNS 和 IP 检测证明它在工作,最后清理干净。如果你更想使用现成的桌面应用,下载页面和价格页面展示了选项。

常见问题

没有桌面环境也能在 Linux 上连接 VPN 吗?

可以。在服务器或最小化安装的系统上,使用配置文件,通过 wg-quick、openvpn 程序或 nmcli 就能启动隧道,不需要图形会话。

为什么 VPN 一启动我的 SSH 会话就卡住了?

全隧道会改变默认路由,发给你 SSH 客户端的回包可能改走隧道,而不是原来的接口。通过 SSH 连接前,请先为你自己的地址添加路由,或使用分流配置。

关闭终端后如何让 VPN 继续运行?

把它作为 systemd 服务运行,例如 wg-quick@wg0 或 openvpn 的客户端单元,而不是放在前台。终端复用工具也可用于测试。

如何在终端里确认流量走了隧道?

确认接口存在、默认路由指向它、WireGuard 报告了最近的握手,并且 IP 检测页面显示的是隧道的地址而不是你平时的地址。

在命令行使用 VPN 需要 root 权限吗?

创建网络接口和修改路由需要管理员权限,所以通常用 sudo 运行命令。不要长时间以 root 身份运行整个 shell。

关于作者

Bob Kanokphon Thongdee,XPASS VPN 创始人

Bob Kanokphon Thongdee

  • XPASS VPN 创始人
  • eSIMonline.asia 联合创始人
  • 7 年以上网络营销经验
  • Cojourney Visa 与 Cojourney Travel 创始人

短途出行或忙碌的一个月,需要 VPN?

XPASS 提供按天数计算的预付通行证。一次付款,不会自动续费。

查看通行证

继续阅读

设备指南

如何在 Linux 上设置 VPN

分步说明:下载 Linux 版 VPNclient 安装程序,在终端中运行,用 My Pass 上的信息登录并连接。

阅读约 6 分钟

VPN 安全

WireGuard 与 OpenVPN 有什么区别

WireGuard 和 OpenVPN 都能建立加密隧道,但设计、复杂度和灵活性不同。本文用通俗的方式比较,并说明该怎样选择。

阅读约 9 分钟

VPN 安全

OpenVPN 详解:TCP、UDP 与安全性

OpenVPN 如何建立隧道、TCP 与 UDP 为何手感不同、怎样的配置才算安全,以及连接失败时如何一步步排查。

阅读约 9 分钟

VPN 安全

如何自己评测 VPN:一份测试清单

许多 VPN 评测是为赚取佣金而写的。这份清单教你自己测试任何 VPN:哪些能验证,哪些不能,以及如何给结果打分。

阅读约 9 分钟

故障排除

VPN 连接不上?逐步排查方法

VPN 连接不上时的清晰排查顺序:通行证状态、登录信息、Wi-Fi 与移动数据、权限、防火墙、应用冲突和错误提示。

阅读约 8 分钟