在 macOS 上通过 Homebrew 安装 OpenVPN 后,确实不像 GUI 客户端那样直观,为了关联自动化让大模型写了一份 Shell 管理方案。
一、脚本方案
1.前提条件:
- OpenVPN 已安装:
brew install openvpn
- 基础命令能运行:
sudo openvpn --config ~/Downloads/myvpn.ovpn
创建脚本 ~/Downloads/ovpn.sh 并修改 CONFIG_FILE 的路径为你实际 .ovpn 文件的路径:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| #!/bin/bash
CONFIG_FILE="$HOME/openvpn/client.ovpn"
PASS_FILE="$HOME/openvpn/pass.txt"
PID_FILE="/tmp/openvpn_script.pid"
LOG_FILE="/tmp/openvpn_script.log"
start_vpn() { if [ ! -f "$PASS_FILE" ]; then echo "❌ 错误: 找不到密码文件: $PASS_FILE" echo "请创建一个包含两行(用户名/密码)的文本文件。" exit 1 fi
if [ -f "$PID_FILE" ]; then echo "⚠️ OpenVPN 似乎已经在运行 (PID: $(cat $PID_FILE))。" echo "如果确定未运行,请删除 $PID_FILE 后重试。" else echo "🚀 正在启动 OpenVPN (使用自动登录)..."
openvpn --daemon \ --writepid "$PID_FILE" \ --config "$CONFIG_FILE" \ --log "$LOG_FILE" \ --auth-user-pass "$PASS_FILE"
sleep 2
if [ -f "$PID_FILE" ] && ps -p $(cat $PID_FILE) > /dev/null; then echo "✅ OpenVPN 启动成功! (PID: $(cat $PID_FILE))" echo "📄 日志位置: $LOG_FILE" else echo "❌ 启动失败,请检查日志: $LOG_FILE" echo "常见原因: sudo权限、密码错误、证书过期或配置文件路径不对。" rm -f "$PID_FILE" fi fi }
stop_vpn() { if [ -f "$PID_FILE" ]; then PID=$(cat "$PID_FILE") echo "🛑 正在停止 OpenVPN (PID: $PID)..." kill "$PID" rm -f "$PID_FILE" echo "✅ OpenVPN 已停止。" else echo "⚠️ 未找到运行中的 OpenVPN (PID 文件不存在)。" fi }
status_vpn() { if [ -f "$PID_FILE" ]; then PID=$(cat "$PID_FILE") if ps -p "$PID" > /dev/null; then echo "🟢 OpenVPN 正在运行 (PID: $PID)" echo "--- 最后 5 行日志 ---" tail -n 5 "$LOG_FILE" else echo "🔴 PID 文件存在 ($PID) 但进程未运行。可能已崩溃。" fi else echo "⚪ OpenVPN 未运行。" fi }
case "$1" in start) start_vpn ;; stop) stop_vpn ;; restart) stop_vpn sleep 1 start_vpn ;; status) status_vpn ;; log) echo "📄 正在追踪日志 (按 Ctrl+C 退出)..." tail -f "$LOG_FILE" ;; *) echo "用法: $0 {start|stop|restart|status|log}" exit 1 ;; esac
|
2.配置“免密运行”白名单
由于上面的脚本需要 Root 权限才能正常运行,每次执行脚本都要输入密码,因此做一下调整
- 移动脚本
1
| sudo mv ovpn.sh /usr/local/bin/myvpn
|
把名字改成了 myvpn,这样你以后在终端直接敲 myvpn 就行
- 修改权限(关键步骤)
我们要把脚本的所有者设为 root,这样普通用户就无法修改脚本内容(防止有人往里面加恶意代码然后利用免密权限运行)。
1 2
| sudo chown root:wheel /usr/local/bin/myvpn sudo chmod 755 /usr/local/bin/myvpn
|
- 获取你的用户名
- 编辑 sudoers 配置文件
我们需要使用 visudo 命令来编辑权限,它会检查语法错误,防止你把系统改坏。
1
| sudo visudo -f /etc/sudoers.d/myvpn_config
|
请把 your_username 替换为你在上一步查到的用户名!
1
| your_username ALL=(ALL) NOPASSWD: /usr/local/bin/myvpn
|
保存退出。
3.最后成果
以后你需要管理 VPN 时,只需要在终端输入以下命令:
- 启动:
sudo myvpn start
- 停止:
sudo myvpn stop
- 状态:
sudo myvpn status
神奇之处在于: 虽然你加了 sudo,但因为我们配置了白名单,系统不会再要求你输入密码了!
二、Docker 方案(推荐)
1. 配置结构
1 2 3 4 5 6
| $ tree [14:53:47] . ├── conf │ ├── auth.txt │ └── client.ovpn ├── docker-compose.yaml
|
2. docker-compose.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| services: openvpn_client: image: dperson/openvpn-client:aarch64 container_name: openvpn-client cap_add: - NET_ADMIN volumes: - ./conf:/vpn dns: - 223.5.5.5 ports: - 3128:3128 - 1080:1080 devices: - /dev/net/tun:/dev/net/tun command: "-c /vpn/client.ovpn"
3proxy: image: tarampampam/3proxy:1 container_name: openvpn-to-proxy network_mode: "service:openvpn_client" depends_on: - openvpn_client
|
3. client.ovpn
示例内容
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 26 27 28 29 30 31 32 33 34 35 36 37 38
| client
dev tun
proto udp
remote x.x.x.x 2294
resolv-retry infinite
nobind
persist-key persist-tun
route x.x.x.x 255.255.0.0
<ca> -----BEGIN CERTIFICATE----- your-content -----END CERTIFICATE----- </ca>
<cert> -----BEGIN CERTIFICATE----- your-content -----END CERTIFICATE----- </cert>
<key> -----BEGIN PRIVATE KEY----- your-content -----END PRIVATE KEY----- </key>
auth-user-pass auth.txt
verb 3
|
4. 说明
auth.txt 的内容是用户名+换行+密码(没有+号)
- 启动后即可通过
socks5://127.0.0.1:1080 或者 http://127.0.0.1:3128 访问 VPN 网络
评论