Files
openvpn-manager/scripts/install.sh
T
cnbugs 2b0f144abc Docs: add IP forwarding/NAT section for client-to-LAN access
The most common OpenVPN deployment scenario is letting remote users
access the server's LAN (office/home network). This requires:
1. net.ipv4.ip_forward=1
2. iptables MASQUERADE on the LAN-facing interface
3. push 'route <LAN-net>' so clients know to send LAN traffic through VPN

Previously this was only mentioned in the FAQ row 'ping不通服务端',
with no actionable instructions. Users (including the project's own
first deployment) hit this exact issue and had to figure it out from
forum posts.

Changes:
  README.md:
  - New section 'IP 转发与内网访问' before 防火墙与公网暴露
  - Covers: enabling ip_forward (immediate + persistent via sysctl.d),
    MASQUERADE rules for one/multiple LAN interfaces, push routes,
    verification commands, troubleshooting table, full checklist
  - FAQ table: add explicit row for 'gateway reachable, LAN not'
  - Features table: add '内网转发' row
  - TOC: link new section

  scripts/install.sh:
  - Auto-enable ip_forward on install (idempotent, persistent via
    /etc/sysctl.d/99-openvpn-manager.conf)
  - Skip silently in containerized environments (no /proc/sys write)
  - Print reminder about manual MASQUERADE rule with link to docs
2026-08-10 00:26:34 +08:00

217 lines
7.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# openvpn-manager 一键部署脚本
# 适用: Ubuntu 20.04+/Debian 11+/CentOS Stream 9+
# 行为: 装依赖 → 编译前端 → 编译 Go 二进制 → 装到 /opt/openvpn-manager → 写 systemd
# 用法: sudo ./install.sh [卸载参数 -u] [--port 8089] [--user admin] [--pass xxxx]
set -euo pipefail
APP_NAME="openvpn-manager"
INSTALL_DIR="/opt/openvpn-manager"
SERVICE_NAME="openvpn-manager"
# 默认配置(可被命令行覆盖)
PORT=8089
ADMIN_USER="admin"
ADMIN_PASS="admin123"
JWT_SECRET="$(openssl rand -hex 32 2>/dev/null || head -c 64 /dev/urandom | xxd -p -c 64)"
usage() {
cat <<EOF
用法: $0 [选项]
-u, --uninstall 卸载(停止服务, 删除 /opt/openvpn-manager 与 systemd 单元)
--port PORT Web 监听端口 (默认 8089)
--user USER 管理员用户名 (默认 admin)
--pass PASS 管理员密码 (默认 admin123)
--dir DIR 安装目录 (默认 /opt/openvpn-manager)
-h, --help 显示本帮助
示例:
sudo $0
sudo $0 --port 9090 --user root --pass 'StrongPass!2026'
sudo $0 -u
EOF
}
uninstall() {
echo "==> 停止并禁用服务"
systemctl stop "$SERVICE_NAME" 2>/dev/null || true
systemctl disable "$SERVICE_NAME" 2>/dev/null || true
rm -f "/etc/systemd/system/${SERVICE_NAME}.service"
systemctl daemon-reload
echo "==> 删除安装目录 $INSTALL_DIR"
rm -rf "$INSTALL_DIR"
echo "==> 完成(已保留源码目录, 如需彻底清理请手动 rm -rf 源码目录)"
}
# ---------- 参数解析 ----------
while [[ $# -gt 0 ]]; do
case "$1" in
-u|--uninstall) uninstall; exit 0 ;;
--port) PORT="$2"; shift 2 ;;
--user) ADMIN_USER="$2"; shift 2 ;;
--pass) ADMIN_PASS="$2"; shift 2 ;;
--dir) INSTALL_DIR="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) echo "未知参数: $1"; usage; exit 1 ;;
esac
done
# ---------- 权限检查 ----------
if [[ $EUID -ne 0 ]]; then
echo "请使用 root 运行: sudo $0"
exit 1
fi
# ---------- 发行版识别 ----------
. /etc/os-release 2>/dev/null || true
echo "==> 操作系统: ${PRETTY_NAME:-unknown}"
SCRIPTPATH="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
SRC_DIR="$( cd -- "$SCRIPTPATH/.." &> /dev/null && pwd )"
echo "==> 源码目录: $SRC_DIR"
echo "==> 安装目录: $INSTALL_DIR"
# ---------- 包管理器 ----------
if command -v apt-get >/dev/null 2>&1; then
PKG="apt-get"
PKG_INSTALL="apt-get install -y --no-install-recommends"
PKG_UPDATE="apt-get update -qq"
DEPS=(curl ca-certificates openssl openvpn easy-rsa nodejs npm golang-go git)
elif command -v dnf >/dev/null 2>&1; then
PKG="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf makecache -q"
DEPS=(curl ca-certificates openssl openvpn easy-rsa nodejs npm golang git)
elif command -v yum >/dev/null 2>&1; then
PKG="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum makecache fast -q"
DEPS=(curl ca-certificates openssl openvpn easy-rsa nodejs npm golang git)
else
echo "不支持的发行版(需 apt/dnf/yum 之一)"
exit 1
fi
echo "==> 使用包管理器: $PKG"
echo "==> 更新包索引"
$PKG_UPDATE || true
echo "==> 安装系统依赖"
$PKG_INSTALL "${DEPS[@]}" || {
echo "依赖安装失败, 请检查网络/源"; exit 1;
}
# ---------- 校验版本 ----------
echo "==> 检查工具版本"
node -v
npm -v
go version
openssl version
openvpn --version | head -1
# 若 Go < 1.21, 警告但不中断(本项目最低 1.21)
GO_VER=$(go version | awk '{print $3}' | sed 's/go//')
echo "==> Go 版本: $GO_VER"
# ---------- 构建前端 ----------
echo "==> 构建前端 (npm install + build)"
cd "$SRC_DIR/frontend"
npm install --include=dev --no-audit --no-fund
npm run build
# ---------- 构建后端 ----------
echo "==> 编译 Go 后端二进制"
cd "$SRC_DIR/backend"
go build -ldflags "-s -w" -o "$SRC_DIR/bin/openvpn-manager" ./cmd/server
# ---------- 安装 ----------
echo "==> 安装到 $INSTALL_DIR"
mkdir -p "$INSTALL_DIR"/{bin,data,dist}
cp -r "$SRC_DIR/bin/openvpn-manager" "$INSTALL_DIR/bin/"
cp -r "$SRC_DIR/dist/"* "$INSTALL_DIR/dist/"
# 写入环境变量文件(便于 systemd 引用)
cat > "$INSTALL_DIR/.env" <<EOF
OVPNMGR_HOST=0.0.0.0
OVPNMGR_PORT=$PORT
OVPNMGR_ADMIN_USER=$ADMIN_USER
OVPNMGR_ADMIN_PASS=$ADMIN_PASS
OVPNMGR_JWT_SECRET=$JWT_SECRET
OVPNMGR_OPENVPN_BIN=$(command -v openvpn)
OVPNMGR_EASYRSA_BIN=$(command -v easyrsa || echo easyrsa)
EOF
chmod 600 "$INSTALL_DIR/.env"
# 渲染 systemd 单元(替换环境变量)
sed -e "s|Environment=OVPNMGR_PORT=.*|Environment=OVPNMGR_PORT=$PORT|" \
-e "s|Environment=OVPNMGR_ADMIN_USER=.*|Environment=OVPNMGR_ADMIN_USER=$ADMIN_USER|" \
-e "s|Environment=OVPNMGR_ADMIN_PASS=.*|Environment=OVPNMGR_ADMIN_PASS=$ADMIN_PASS|" \
-e "s|Environment=OVPNMGR_JWT_SECRET=.*|Environment=OVPNMGR_JWT_SECRET=$JWT_SECRET|" \
-e "s|/opt/openvpn-manager|$INSTALL_DIR|g" \
"$SRC_DIR/systemd/${SERVICE_NAME}.service" > "/etc/systemd/system/${SERVICE_NAME}.service"
systemctl daemon-reload
systemctl enable "$SERVICE_NAME"
systemctl restart "$SERVICE_NAME"
# ---------- 健康检查 ----------
sleep 2
HEALTH_URL="http://127.0.0.1:${PORT}/api/health"
echo "==> 健康检查 $HEALTH_URL"
for i in 1 2 3 4 5; do
if curl -fsS "$HEALTH_URL" >/dev/null 2>&1; then
echo "✓ 服务已就绪"
break
fi
if [[ $i -eq 5 ]]; then
echo "✗ 健康检查失败, 查看: journalctl -u $SERVICE_NAME -n 50"
exit 1
fi
sleep 1
done
# ---------- 启用 IP 转发 (客户端访问服务端 LAN 的前提) ----------
echo "==> 启用 IPv4 转发 (客户端访问服务端 LAN 需要)"
if [[ -w /proc/sys/net/ipv4/ip_forward ]]; then
echo 1 > /proc/sys/net/ipv4/ip_forward
# 持久化(下次重启不丢)
CONF_FILE="/etc/sysctl.d/99-openvpn-manager.conf"
if [[ ! -f "$CONF_FILE" ]] || ! grep -q "^net.ipv4.ip_forward=1" "$CONF_FILE" 2>/dev/null; then
echo "net.ipv4.ip_forward=1" > "$CONF_FILE"
sysctl -p "$CONF_FILE" >/dev/null 2>&1 || true
fi
echo " ✓ IP 转发已启用 (持久化到 $CONF_FILE)"
echo " 提示: 如需让客户端访问服务端 LAN 网段, 还需手动添加 iptables NAT 规则:"
echo " sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o <LAN网卡> -j MASQUERADE"
echo " 详见 README \"IP 转发与内网访问\" 章节"
else
echo " ! 无法写入 /proc/sys/net/ipv4/ip_forward (容器环境?) — 跳过"
echo " 如需客户端访问服务端 LAN, 请在宿主机启用: sysctl -w net.ipv4.ip_forward=1"
fi
# ---------- 完成提示 ----------
cat <<EOF
================================================================
OpenVPN Manager 安装完成
================================================================
访问地址 : http://<服务器IP>:${PORT}
用户名 : ${ADMIN_USER}
密码 : ${ADMIN_PASS}
安装目录 : ${INSTALL_DIR}
数据目录 : ${INSTALL_DIR}/data
配置单元 : /etc/systemd/system/${SERVICE_NAME}.service
常用命令:
systemctl status ${SERVICE_NAME} # 查看状态
systemctl restart ${SERVICE_NAME} # 重启
systemctl stop ${SERVICE_NAME} # 停止
journalctl -u ${SERVICE_NAME} -f # 跟踪日志
${INSTALL_DIR}/bin/openvpn-manager --help
卸载:
sudo $0 -u
================================================================
EOF