该脚本可用于自动为 WireGuard 服务器生成新的客户端(Peer)配置,并将必要的 Peer 信息自动追加到服务端配置文件
主要:
- 交互式参数输入,支持参数记忆,方便重复操作
- 自动分配唯一客户端虚拟 IP,避免 IP 冲突
- 自动生成并保存客户端密钥,服务端公钥和预共享密钥
- 自动将新 Peer 信息追加到服务端配置文件
- 客户端配置输出到指定目录,便于统一管理和分发
- 检测到 qrencode 程序时自动输出二维码,方便手机扫码导入 WireGuard 配置
适用场景:
- 批量为 WireGuard 服务器添加新客户端(如公司员工、多个移动设备等)
- 需要便捷地生成客户端配置文件和二维码,提升 WireGuard 运维效率
#!/bin/bash
set -e
# =========================
# WireGuard 客户端生成器
# =========================
INI_FILE="./wg-client-gen.ini"
declare -A ini_defaults
# 1. 读取 ini 配置(如果存在)
if [[ -f "$INI_FILE" ]]; then
echo "🔎 检测到默认参数文件: $INI_FILE"
while IFS='=' read -r key value; do
key=$(echo "$key" | sed 's/^[ \t]*//;s/[ \t]*$//')
value=$(echo "$value" | sed 's/^[ \t]*//;s/[ \t]*$//')
[[ -z "$key" || "$key" == \#* ]] && continue
ini_defaults["$key"]="$value"
done < "$INI_FILE"
fi
# 2. 交互式输入参数,并支持 ini 默认值
echo "========= WireGuard 客户端配置生成 ========="
read -rp "请输入 WireGuard 服务端配置文件路径 (如 /etc/wireguard/wg0.conf) [${ini_defaults[WG_CONF]}]: " WG_CONF
WG_CONF="${WG_CONF:-${ini_defaults[WG_CONF]}}"
while [[ -z "$WG_CONF" || ! -f "$WG_CONF" ]]; do
echo "❌ 配置文件无效,请重新输入"
read -rp "请输入 WireGuard 服务端配置文件路径 (如 /etc/wireguard/wg0.conf): " WG_CONF
done
read -rp "请输入服务端 Endpoint (如 1.1.1.1:11820) [${ini_defaults[ENDPOINT]}]: " ENDPOINT
ENDPOINT="${ENDPOINT:-${ini_defaults[ENDPOINT]}}"
while [[ -z "$ENDPOINT" ]]; do
echo "❌ Endpoint 不能为空"
read -rp "请输入服务端 Endpoint (如 1.1.1.1:11820): " ENDPOINT
done
read -rp "请输入客户端名称(李明) [${ini_defaults[CLIENT_NAME]}]: " CLIENT_NAME
CLIENT_NAME="${CLIENT_NAME:-${ini_defaults[CLIENT_NAME]}}"
while [[ -z "$CLIENT_NAME" ]]; do
echo "❌ 客户端名称不能为空"
read -rp "请输入客户端名称(李明): " CLIENT_NAME
done
# 输出目录默认值为“服务端配置文件名去扩展名-client”
CFG_BASENAME=$(basename "$WG_CONF" .conf)
DEFAULT_OUTPUT_DIR="${CFG_BASENAME}-client"
read -rp "请输入输出目录 (留空则使用默认: ${DEFAULT_OUTPUT_DIR}) [${ini_defaults[OUTPUT_DIR]}]: " OUTPUT_DIR
OUTPUT_DIR="${OUTPUT_DIR:-${ini_defaults[OUTPUT_DIR]}}"
OUTPUT_DIR="${OUTPUT_DIR:-${DEFAULT_OUTPUT_DIR}}"
mkdir -p "$OUTPUT_DIR"
# AllowedIPs 获取,默认 0.0.0.0/0,支持记忆和交互
DEFAULT_ALLOWEDIPS="${ini_defaults[ALLOWEDIPS]:-0.0.0.0/0}"
read -rp "请输入本客户端的 AllowedIPs (如 0.0.0.0/0 或 10.8.0.2/32) [${DEFAULT_ALLOWEDIPS}]: " ALLOWEDIPS
ALLOWEDIPS="${ALLOWEDIPS:-${DEFAULT_ALLOWEDIPS}}"
while [[ -z "$ALLOWEDIPS" ]]; do
echo "❌ AllowedIPs 不能为空"
read -rp "请输入本客户端的 AllowedIPs (如 0.0.0.0/0 或 10.8.0.2/32): " ALLOWEDIPS
done
# 获取服务端 IP 网段(如 10.9.0.x)
SERVER_ADDRESS=$(grep -m1 '^Address' "$WG_CONF" | cut -d '=' -f2 | tr -d '[:space:]' | cut -d'/' -f1)
SUBNET=$(echo "$SERVER_ADDRESS" | awk -F. '{print $1"."$2"."$3}')
USED_IPS=$(grep -oP 'AllowedIPs\s*=\s*\K([0-9\.]+)' "$WG_CONF"; grep -oP 'Address\s*=\s*\K([0-9\.]+)' "$WG_CONF")
# 查找可用 IP
for i in $(seq 2 254); do
CANDIDATE="$SUBNET.$i"
if ! echo "$USED_IPS" | grep -qw "$CANDIDATE"; then
CLIENT_IP="$CANDIDATE"
break
fi
done
if [[ -z "$CLIENT_IP" ]]; then
echo "❌ 没有可用 IP 地址,请检查配置"
exit 1
fi
# 生成密钥
CLIENT_PRIVATE_KEY=$(wg genkey)
CLIENT_PUBLIC_KEY=$(echo "$CLIENT_PRIVATE_KEY" | wg pubkey)
PRESHARED_KEY=$(wg genpsk)
# 获取服务端 public key
SERVER_PRIVATE_KEY=$(grep -m1 '^PrivateKey' "$WG_CONF" | awk -F '= ' '{print $2}' | tr -d ' ')
SERVER_PUBLIC_KEY=$(echo "$SERVER_PRIVATE_KEY" | wg pubkey)
# 获取服务端端口
SERVER_PORT=$(grep -m1 '^ListenPort' "$WG_CONF" | awk -F '= ' '{print $2}' | tr -d ' ')
# 用户确认
echo "📋 即将生成新的 WireGuard 客户端配置:"
echo "➡ 客户端名称: $CLIENT_NAME"
echo "➡ 分配地址: $CLIENT_IP/32"
echo "➡ 服务端 Endpoint: $ENDPOINT"
echo "➡ 输出目录: $OUTPUT_DIR"
echo "➡ 服务端端口: $SERVER_PORT"
echo "➡ AllowedIPs: $ALLOWEDIPS"
read -rp "✅ 确认继续?(y/N): " CONFIRM
[[ "$CONFIRM" != "y" && "$CONFIRM" != "Y" ]] && echo "🚫 已取消" && exit 0
# 追加到服务端配置
cat <<EOF >> "$WG_CONF"
# === Auto-generated Peer: $CLIENT_NAME ===
[Peer]
# $CLIENT_NAME
PublicKey = $CLIENT_PUBLIC_KEY
PresharedKey = $PRESHARED_KEY
AllowedIPs = $CLIENT_IP/32
EOF
echo "✅ 已添加到服务端配置:$WG_CONF"
# 生成客户端配置
CLIENT_CONF_PATH="$OUTPUT_DIR/$CLIENT_IP.conf"
cat <<EOF > "$CLIENT_CONF_PATH"
# WireGuard 客户端配置 - $CLIENT_NAME
[Interface]
PrivateKey = $CLIENT_PRIVATE_KEY
Address = $CLIENT_IP/32
# Client: $CLIENT_NAME
[Peer]
# Server
PublicKey = $SERVER_PUBLIC_KEY
PresharedKey = $PRESHARED_KEY
Endpoint = $ENDPOINT
AllowedIPs = $ALLOWEDIPS
PersistentKeepalive = 25
EOF
echo "✅ 客户端配置文件生成成功:$CLIENT_CONF_PATH"
# 3. 记录交互参数到固定 ini(当前执行目录)
cat <<EOF > "$INI_FILE"
WG_CONF=$WG_CONF
ENDPOINT=$ENDPOINT
CLIENT_NAME=$CLIENT_NAME
OUTPUT_DIR=$OUTPUT_DIR
ALLOWEDIPS=$ALLOWEDIPS
EOF
echo "🔖 此次交互参数已写入: $INI_FILE"
# 4. 检测 qrencode 并输出二维码
if command -v qrencode >/dev/null 2>&1; then
echo "ℹ️ 检测到 qrencode,生成二维码如下(可直接扫码导入 WireGuard 客户端):"
qrencode -t ansiutf8 < "$CLIENT_CONF_PATH"
# 也可以输出为图片文件:
# qrencode -o "$OUTPUT_DIR/client-$CLIENT_NAME-$CLIENT_IP.png" < "$CLIENT_CONF_PATH"
else
echo "⚠️ 未检测到 qrencode,跳过二维码生成"
fi