CentOS 7 部署 WireGuard(RPM 安装 + 分流不影响互联网 + 一键新增用户脚本)



1)目标与原则

目标

核心原则(分流)


2)准备:确认系统与内核

cat /etc/redhat-release
uname -r

CentOS7 上 WireGuard 的 kmod 模块经常是“按内核版本编译”的,所以 uname -r 要记住。


3)安装:从 3 个 RPM 包开始(推荐本地安装)

3.1 创建目录

mkdir -p /root/wg_rpm
cd /root/wg_rpm

3.2 下载 3 个包

这 3 个是常用的最小组合:

# wireguard-tools(工具)
curl -LO "https://mirrors.aliyun.com/elrepo/elrepo/el7/x86_64/RPMS/wireguard-tools-1.0.20210914-1.el7.x86_64.rpm"

# kmod 元包(依赖壳)
curl -LO "https://mirrors.aliyun.com/rpmfusion/free/el/updates/7/x86_64/k/kmod-wireguard-1.0.20201221-1.el7.x86_64.rpm"

# wireguard noarch(common 依赖)
curl -LO "https://mirrors.aliyun.com/rpmfusion/free/el/updates/7/x86_64/w/wireguard-1.0.20201221-1.el7.noarch.rpm"

3.3 关键:下载“内核绑定模块包”

uname -r 如果是 3.10.0-1160.el7.x86_64,就下载:

curl -LO "https://mirrors.aliyun.com/rpmfusion/free/el/updates/7/x86_64/k/kmod-wireguard-3.10.0-1160.el7.x86_64-1.0.20201221-1.el7.x86_64.rpm"

如果不是 1160,把文件名里的 3.10.0-1160.el7.x86_64 换成你实际内核版本。

你之前报错“需要:kmod-wireguard-3.10.0-1160...”就是因为只装了元包,没有装这个“内核绑定包”。

3.4 一次性安装

yum localinstall -y ./*.rpm

3.5 验证

modprobe wireguard
lsmod | grep wireguard || echo "wireguard module not loaded"
wg --version

4)服务端配置(CentOS7)

下面以一个简单网段为例:

4.1 生成密钥(务必分清 .key / .pub)

mkdir -p /etc/wireguard
cd /etc/wireguard
umask 077

wg genkey | tee server.key | wg pubkey > server.pub
wg genkey | tee client.key | wg pubkey > client.pub

echo "=== server.key(私钥) ==="; cat server.key
echo "=== server.pub(公钥) ==="; cat server.pub
echo "=== client.key(私钥) ==="; cat client.key
echo "=== client.pub(公钥) ==="; cat client.pub

只记一句:

4.2 写服务端 /etc/wireguard/wg0.conf

vim /etc/wireguard/wg0.conf

内容:

[Interface]
Address = 10.66.66.1/24
ListenPort = 51820
PrivateKey = <填 server.key 内容>

[Peer]
PublicKey = <填 client.pub 内容>
AllowedIPs = 10.66.66.2/32

建议不要写 SaveConfig = true,容易出现“文件改了但运行态还是旧 peer”的坑。

4.3 启动与开机自启

wg-quick up wg0
systemctl enable wg-quick@wg0

验证:

ip addr show wg0
ss -lunp | grep 51820
wg show wg0

4.4 放行 UDP 51820

firewalld:

firewall-cmd --add-port=51820/udp --permanent
firewall-cmd --reload

如果你用 iptables,测试先粗放(后面再细化):

iptables -I INPUT -p udp --dport 51820 -j ACCEPT
iptables -I INPUT -i wg0 -j ACCEPT
iptables -I INPUT -i wg0 -p icmp -j ACCEPT

5)客户端配置(Windows / Linux)

Windows WireGuard 新建 tunnel,粘贴(示例):

[Interface]
PrivateKey = <填 client.key 内容>
Address = 10.66.66.2/24

[Peer]
PublicKey = <填 server.pub 内容>
Endpoint = 你的服务器公网IP:51820
PersistentKeepalive = 25

# 分流:只走 10.66.66.0/24,不影响互联网
AllowedIPs = 10.66.66.0/24

验证:


6)一键新增用户脚本(自动分配 IP + 生成客户端配置 + 热加载)

把下面脚本保存为:/root/add_wg_user.sh

#!/usr/bin/env bash
set -euo pipefail

WG_IF="wg0"
WG_DIR="/etc/wireguard"
WG_CONF="${WG_DIR}/${WG_IF}.conf"

NET_PREFIX="10.66.66"
CIDR="24"
SERVER_IP_LAST="1"

DEFAULT_ALLOWED_IPS="${NET_PREFIX}.0/${CIDR}"
DEFAULT_ENDPOINT="110.42.98.59:51820"

usage() {
  cat <<EOF
用法:
  $0 <username> [--ip-last N] [--endpoint IP:PORT] [--allowed "10.66.66.0/24,192.168.10.0/24"]

示例:
  $0 user3
  $0 user4 --ip-last 10
  $0 user5 --allowed "10.66.66.0/24,192.168.10.0/24"
  $0 user6 --endpoint "1.2.3.4:51820"
EOF
}

die() { echo "ERROR: $*" >&2; exit 1; }

[[ $# -lt 1 ]] && usage && exit 1
NAME="$1"; shift
[[ "$NAME" =~ ^[a-zA-Z0-9._-]+$ ]] || die "username 只能包含字母数字 . _ -"

IP_LAST=""
ENDPOINT="$DEFAULT_ENDPOINT"
ALLOWED_IPS="$DEFAULT_ALLOWED_IPS"

while [[ $# -gt 0 ]]; do
  case "$1" in
    --ip-last) IP_LAST="${2:-}"; shift 2 ;;
    --endpoint) ENDPOINT="${2:-}"; shift 2 ;;
    --allowed) ALLOWED_IPS="${2:-}"; shift 2 ;;
    -h|--help) usage; exit 0 ;;
    *) die "未知参数:$1(用 -h 查看帮助)" ;;
  esac
done

[[ -f "$WG_CONF" ]] || die "找不到 $WG_CONF"

# 读取服务器公钥(优先用 server.pub)
SERVER_PUB=""
if [[ -f "${WG_DIR}/server.pub" ]]; then
  SERVER_PUB="$(tr -d '\r\n' < "${WG_DIR}/server.pub")"
else
  if ip link show "$WG_IF" >/dev/null 2>&1; then
    SERVER_PUB="$(wg show "$WG_IF" public-key 2>/dev/null || true)"
  fi
fi
[[ -n "$SERVER_PUB" ]] || die "读取服务器公钥失败(建议放 ${WG_DIR}/server.pub)"

# 自动分配下一个可用 IP
if [[ -z "$IP_LAST" ]]; then
  USED_LASTS="$(grep -Eo "${NET_PREFIX}\.[0-9]{1,3}/32" "$WG_CONF" \
    | awk -F'[./]' '{print $4}' \
    | sort -n | uniq || true)"

  for n in $(seq 2 254); do
    [[ "$n" == "$SERVER_IP_LAST" ]] && continue
    echo "$USED_LASTS" | grep -qx "$n" && continue
    IP_LAST="$n"
    break
  done
fi

[[ -n "$IP_LAST" ]] || die "没有可用 IP 了(10.66.66.2~254 都被占用)"
[[ "$IP_LAST" =~ ^[0-9]+$ ]] || die "--ip-last 必须是数字"
(( IP_LAST >= 2 && IP_LAST <= 254 )) || die "--ip-last 必须在 2~254"

CLIENT_IP="${NET_PREFIX}.${IP_LAST}/${CIDR}"
CLIENT_ALLOWED_IP="${NET_PREFIX}.${IP_LAST}/32"

umask 077
CLIENTS_DIR="${WG_DIR}/clients"
mkdir -p "$CLIENTS_DIR"

CLIENT_KEY_FILE="${CLIENTS_DIR}/${NAME}.key"
CLIENT_PUB_FILE="${CLIENTS_DIR}/${NAME}.pub"
CLIENT_CONF_FILE="${CLIENTS_DIR}/${NAME}.conf"

[[ -f "$CLIENT_KEY_FILE" || -f "$CLIENT_CONF_FILE" ]] && die "用户文件已存在,换名或先备份删除"

wg genkey | tee "$CLIENT_KEY_FILE" | wg pubkey > "$CLIENT_PUB_FILE"
CLIENT_PUB="$(tr -d '\r\n' < "$CLIENT_PUB_FILE")"
CLIENT_KEY="$(tr -d '\r\n' < "$CLIENT_KEY_FILE")"

cat > "$CLIENT_CONF_FILE" <<EOF
[Interface]
PrivateKey = ${CLIENT_KEY}
Address = ${CLIENT_IP}

[Peer]
PublicKey = ${SERVER_PUB}
Endpoint = ${ENDPOINT}
PersistentKeepalive = 25
AllowedIPs = ${ALLOWED_IPS}
EOF

TS="$(date '+%F_%H%M%S')"
BK="${WG_CONF}.bak.${TS}"
cp -a "$WG_CONF" "$BK"

grep -qF "$CLIENT_PUB" "$WG_CONF" && die "wg0.conf 已存在该公钥,备份在:$BK"

{
  echo ""
  echo "# ${NAME} added ${TS}"
  echo "[Peer]"
  echo "PublicKey = ${CLIENT_PUB}"
  echo "AllowedIPs = ${CLIENT_ALLOWED_IP}"
} >> "$WG_CONF"

# 热加载(不中断现有连接)
if ip link show "$WG_IF" >/dev/null 2>&1; then
  wg set "$WG_IF" peer "$CLIENT_PUB" allowed-ips "$CLIENT_ALLOWED_IP" || true
fi

echo "OK: 已新增用户:${NAME}"
echo "  - 分配 IP:${CLIENT_IP}"
echo "  - 服务器配置已更新:${WG_CONF}"
echo "  - 服务器配置备份:${BK}"
echo "  - 客户端配置文件:${CLIENT_CONF_FILE}"
echo ""
echo "把这个文件发给用户导入即可:"
echo "  ${CLIENT_CONF_FILE}"

给执行权限:

chmod +x /root/add_wg_user.sh

6.1 新增用户示例

自动分配下一个 IP:

/root/add_wg_user.sh user2

指定 IP 最后一段:

/root/add_wg_user.sh user2 --ip-last 3

让用户额外能访问内网段(仍然分流,不影响互联网):

/root/add_wg_user.sh user2 --allowed "10.66.66.0/24,192.168.10.0/24"

脚本输出里会给你:


7)排障最有效的两条命令

7.1 看握手(服务端)

wg show wg0

看有没有:

7.2 抓包判断“端口通不通 / 服务端回不回”

tcpdump -ni any udp port 51820

8)子网互通怎么做(继续分流,不影响互联网)

当你需要让客户端访问远端内网(例如 192.168.10.0/24):

客户端 AllowedIPs 加上:

AllowedIPs = 10.66.66.0/24, 192.168.10.0/24

然后“远端内网回程”通常有两种方式:

这一段跟你的实际网卡/网关有关,确定后再上最终配置就行。


已有10位网友发表了看法:

发表评论

必填

选填

选填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。