Ubuntu部署Wireguard笔记

2,342 阅读3分钟

WireGuard 服务安装配置指南

1. 系统准备

# 更新镜像并安装WireGuard
apt update && apt install -y wireguard

# 开启IP转发
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

image.png

2. 生成密钥对

# 创建配置目录
mkdir -p /etc/wireguard && chmod 0777 /etc/wireguard
cd /etc/wireguard
umask 077

# 生成服务器密钥
wg genkey | tee server_privatekey | wg pubkey > server_publickey

# 生成客户端密钥(可生成多个)
wg genkey | tee client1_privatekey | wg pubkey > client1_publickey

image.png

image.png

3. 服务端配置

# 创建配置文件(注意替换eth0为实际网卡名)
cat > wg0.conf <<EOF
[Interface]
PrivateKey = $(cat server_privatekey)
Address = 10.0.8.1/24
ListenPort = 50814
DNS = 8.8.8.8
MTU = 1420

# 流量转发规则(eth0需替换)
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# 客户端1配置
PublicKey = $(cat client1_publickey)
AllowedIPs = 10.0.8.10/32
EOF

image.png

image.png

image.png

4. 启动服务

# 设置开机自启
systemctl enable wg-quick@wg0

# 启动服务
wg-quick up wg0

# 检查状态
wg show

image.png

image.png

5. 客户端配置

# 生成客户端配置
cat > client1.conf <<EOF
[Interface]
PrivateKey = $(cat client1_privatekey)
Address = 10.0.8.10/32
DNS = 8.8.8.8
MTU = 1420

[Peer]
PublicKey = $(cat server_publickey)
Endpoint = [服务器公网IP]:50814
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF

image.png

6. 多客户端配置

在服务端配置中追加新的Peer段:

# 生成新客户端密钥
wg genkey | tee client2_privatekey | wg pubkey > client2_publickey

# 追加到wg0.conf
cat >> wg0.conf <<EOF

[Peer]
# 客户端2配置
PublicKey = $(cat client2_publickey)
AllowedIPs = 10.0.8.11/32
EOF

# 重载配置
wg syncconf wg0 <(wg-quick strip wg0)

7. 客户端使用说明

Windows:

  1. 安装官方WireGuard客户端
  2. 导入生成的client1.conf文件

image.png

Linux:

# 安装客户端
apt install wireguard

# 使用配置
wg-quick up ./client1.conf

关键注意事项:

  1. 防火墙需放行UDP 50814端口
  2. eth0需替换为服务器实际公网网卡名
  3. 每个客户端应有独立的IP地址
  4. MTU值可根据网络情况调整(默认1420)
  5. 配置文件需妥善保管,PrivateKey不可泄露

常用命令:

  • 查看连接状态:wg show
  • 临时关闭服务:wg-quick down wg0
  • 查看运行日志:journalctl -u wg-quick@wg0 -f

image.png

8. 其他命令

wg set 命令

# peer 添加客户端公钥 allowed-ips 用于添加互联ip以及网段
wg set wg0 peer [客户端公钥] allowed-ips 10.0.8.11/32

# 移除客户端
sudo wg set wg0 peer [客户端公钥] remove

wg addconf命令

echo '
[Peer]
# 这是新客户端的公钥
PublicKey = [客户端公钥]
# 这是为新客户端分配的IP
AllowedIPs = 10.0.0.11/32
' | sudo tee /new_peer.conf

# 添加配置
sudo wg addconf wg0 new_peer.conf

9. 将当前运行配置保存

# wg0为wireguard接口
wg-quick save wg0

客户端配置脚本

#!/bin/bash

# 设置错误处理:任何命令失败则退出脚本
set -e

# 配置常量
WG_INTERFACE="对应的隧道接口"
SERVER_CONFIG_FILE="/etc/wireguard/$WG_INTERFACE.conf"
SERVER_PUBLIC_KEY_FILE="server_publickey"
SERVER_ENDPOINT="对应的公网地址:50814"
DEFAULT_DNS="8.8.8.8"
DEFAULT_MTU="1420"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# 函数:生成随机名称(数字加字母组合并与时间戳挂钩)
generate_random_name() {
    local timestamp=$(date +%s)  # 获取当前时间戳
    local random_chars=$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 6)
    echo "${timestamp}${random_chars}"
}

# 函数:打印彩色消息
print_status() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

print_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

print_info() {
    echo -e "${CYAN}[INFO]${NC} $1"
}

# 函数:验证IP地址格式
validate_ip() {
    local ip=$1
    local stat=1
    
    if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        OIFS=$IFS
        IFS='.'
        ip=($ip)
        IFS=$OIFS
        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
        stat=$?
    fi
    return $stat
}

# 函数:检查IP地址是否已被使用
is_ip_used() {
    local ip=$1
    # 检查wg show输出中是否包含该IP
    if wg show "$WG_INTERFACE" 2>/dev/null | grep -q "$ip/32"; then
        return 0 # IP已被使用
    else
        return 1 # IP未被使用
    fi
}

# 函数:确认操作
confirm() {
    local prompt="$1"
    local default="${2:-y}"
    
    if [ "$default" = "y" ]; then
        prompt="$prompt [Y/n] "
    else
        prompt="$prompt [y/N] "
    fi
    
    while true; do
        read -p "$prompt" answer
        answer=${answer:-$default}
        
        case "$answer" in
            y|Y|yes|YES)
                return 0
                ;;
            n|N|no|NO)
                return 1
                ;;
            *)
                echo "请输入 y 或 n"
                ;;
        esac
    done
}

# 函数:显示服务器网络信息
show_server_network_info() {
    echo
    print_info "=== 服务器网络信息 ==="
    
    # 获取服务器接口地址
    if ip addr show "$WG_INTERFACE" &>/dev/null; then
        SERVER_ADDR=$(ip -4 addr show "$WG_INTERFACE" | grep -oP '(?<=inet\s)\d+(\.\d+){3}/\d+')
        print_info "服务器接口地址: $SERVER_ADDR"
        
        # 提取网络地址和掩码
        NETWORK_ADDR=$(echo "$SERVER_ADDR" | cut -d'/' -f1)
        NETWORK_MASK=$(echo "$SERVER_ADDR" | cut -d'/' -f2)
        
        # 计算网络段
        IFS=. read -r i1 i2 i3 i4 <<< "$NETWORK_ADDR"
        IFS=. read -r m1 m2 m3 m4 <<< $(cidr_to_netmask "$NETWORK_MASK")
        
        NETWORK_SEGMENT=$(printf "%d.%d.%d.%d" "$((i1 & m1))" "$((i2 & m2))" "$((i3 & m3))" "$((i4 & m4))")
        print_info "网络段: $NETWORK_SEGMENT/$NETWORK_MASK"
    else
        print_warning "无法获取服务器接口信息,$WG_INTERFACE 接口可能未启动"
        
        # 尝试从配置文件获取
        if [ -f "$SERVER_CONFIG_FILE" ]; then
            SERVER_ADDR=$(grep -E "^Address" "$SERVER_CONFIG_FILE" | head -1 | awk '{print $3}')
            if [ -n "$SERVER_ADDR" ]; then
                print_info "从配置文件获取的服务器地址: $SERVER_ADDR"
                
                NETWORK_ADDR=$(echo "$SERVER_ADDR" | cut -d'/' -f1)
                NETWORK_MASK=$(echo "$SERVER_ADDR" | cut -d'/' -f2)
                
                # 计算网络段
                IFS=. read -r i1 i2 i3 i4 <<< "$NETWORK_ADDR"
                IFS=. read -r m1 m2 m3 m4 <<< $(cidr_to_netmask "$NETWORK_MASK")
                
                NETWORK_SEGMENT=$(printf "%d.%d.%d.%d" "$((i1 & m1))" "$((i2 & m2))" "$((i3 & m3))" "$((i4 & m4))")
                print_info "网络段: $NETWORK_SEGMENT/$NETWORK_MASK"
            fi
        fi
    fi
    
    # 显示已分配的客户端IP
    print_info "已分配的客户端IP地址:"
    if wg show "$WG_INTERFACE" &>/dev/null; then
        wg show "$WG_INTERFACE" | grep "allowed ips" | awk '{print "  - " $3}'
    else
        print_warning "无法获取已分配IP列表,WireGuard 接口可能未启动"
    fi
    
    echo
}

# 函数:将CIDR掩码转换为点分十进制格式
cidr_to_netmask() {
    local bits=$1
    local mask=$((0xffffffff << (32 - bits) & 0xffffffff))
    printf "%d.%d.%d.%d" \
        $((mask >> 24)) \
        $((mask >> 16 & 0xff)) \
        $((mask >> 8 & 0xff)) \
        $((mask & 0xff))
}

# 主脚本开始
clear
echo "=== WireGuard 客户端配置生成脚本 ==="
echo

# 检查服务器公钥文件是否存在
if [ ! -f "$SERVER_PUBLIC_KEY_FILE" ]; then
    print_error "服务器公钥文件不存在: $SERVER_PUBLIC_KEY_FILE"
    exit 1
fi

# 获取客户端名称
while true; do
    read -p "请输入客户端名称 (直接回车将使用随机名称): " name
    
    # 如果用户没有输入名称,则生成随机名称
    if [ -z "$name" ]; then
        name=$(generate_random_name)
        print_info "使用随机生成的客户端名称: $name"
        break
    fi
    
    # 检查名称是否已存在
    if [ -d "./$name" ]; then
        print_warning "客户端 '$name' 的配置已存在"
        if confirm "是否覆盖现有配置?" "n"; then
            rm -rf "./$name"
            break
        else
            continue
        fi
    else
        break
    fi
done

# 显示服务器网络信息
show_server_network_info

# 获取客户端IP地址
while true; do
    read -p "请分配客户端IP地址: " ipaddr
    
    if [ -z "$ipaddr" ]; then
        print_error "IP地址不能为空"
        continue
    fi
    
    if ! validate_ip "$ipaddr"; then
        print_error "IP地址格式无效: $ipaddr"
        continue
    fi
    
    if is_ip_used "$ipaddr"; then
        print_error "IP地址已被使用: $ipaddr"
        echo "当前已使用的IP地址:"
        wg show "$WG_INTERFACE" | grep "allowed ips" | awk '{print "  - " $3}'
        echo
        continue
    fi
    
    break
done

# 创建客户端目录
mkdir -p "./$name"
cd "./$name"

# 生成密钥对
print_status "创建客户端公私钥中..."
privatekey="${name}_privatekey"
publickey="${name}_publickey"

wg genkey | tee "$privatekey" | wg pubkey > "$publickey"

# 创建配置文件
print_status "生成客户端配置文件..."
cat > "$name.conf" <<EOF
[Interface]
PrivateKey = $(cat "$privatekey")
Address = $ipaddr/32
DNS = $DEFAULT_DNS
MTU = $DEFAULT_MTU

[Peer]
PublicKey = $(cat ../"$SERVER_PUBLIC_KEY_FILE")
Endpoint = $SERVER_ENDPOINT
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF

print_success "客户端配置创建完成: $(pwd)/$name.conf"

# 显示配置内容预览
if confirm "是否查看配置文件内容?" "y"; then
    echo
    echo "=== 配置文件内容 ==="
    cat "$name.conf"
    echo
fi

# 确认是否启用客户端
if confirm "是否立即启用客户端?" "y"; then
    print_status "正在启用客户端..."
    
    # 尝试添加对等节点
    if sudo wg set "$WG_INTERFACE" peer "$(cat "$publickey")" allowed-ips "$ipaddr/32"; then
        print_success "客户端 $name ($ipaddr/32) 已成功启用"
        
        # 保存配置到持久存储
        if confirm "是否保存配置到持久存储?" "y"; then
            sudo wg-quick save "$WG_INTERFACE"
            print_success "配置已保存到持久存储"
        fi
    else
        print_error "启用客户端失败,请检查WireGuard服务状态"
        exit 1
    fi
else
    print_warning "客户端未启用,您可以在需要时手动启用"
    echo "启用命令: sudo wg set $WG_INTERFACE peer $(cat "$publickey") allowed-ips $ipaddr/32"
fi

# 显示配置摘要
echo
echo "=== 配置摘要 ==="
echo "客户端名称: $name"
echo "IP 地址: $ipaddr/32"
echo "配置文件: $(pwd)/$name.conf"
echo
print_success "客户端配置流程完成!"