×

linux学习笔记

wireguard安装与配置

dingpeng dingpeng 发表于2025-09-30 浏览10 评论0

#!/bin/bash
# wg-manager.sh - WireGuard 跨平台管理脚本 (使用 192.168.108.0/24 网段)

set -e

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

# 变量定义 - 修改为 192.168.108.0/24 网段
CONFIG_DIR="/etc/wireguard"
SERVER_CONFIG="$CONFIG_DIR/wg0.conf"
SERVER_PUBLIC_KEY="$CONFIG_DIR/server_public.key"
SERVER_PRIVATE_KEY="$CONFIG_DIR/server_private.key"
CLIENTS_DIR="$CONFIG_DIR/clients"
NETWORK="192.168.108.0/24"
SERVER_IP="192.168.108.1"
PORT="51820"

# 日志函数
log() {
    echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"
}

warn() {
    echo -e "${YELLOW}[警告]${NC} $1"
}

error() {
    echo -e "${RED}[错误]${NC} $1"
    exit 1
}

# 检测操作系统
detect_os() {
    if [ -f /etc/os-release ]; then
        . /etc/os-release
        OS=$ID
        OS_VERSION=$VERSION_ID
    else
        OS=$(uname -s)
    fi
    log "检测到操作系统: $OS $OS_VERSION"
}

# 安装 WireGuard
install_wireguard() {
    log "开始安装 WireGuard..."
    
    case $OS in
        ubuntu|debian)
            sudo apt update || warn "apt update 失败,继续安装..."
            sudo apt install -y wireguard-tools resolvconf qrencode || {
                warn "仓库安装失败,尝试编译安装..."
                compile_install
            }
            ;;
        centos|rhel|fedora|rocky|almalinux|opencloudos)
            if command -v dnf >/dev/null 2>&1; then
                sudo dnf install -y wireguard-tools qrencode || {
                    sudo dnf install -y epel-release
                    sudo dnf install -y wireguard-tools qrencode
                }
            else
                sudo yum install -y wireguard-tools qrencode || {
                    sudo yum install -y epel-release
                    sudo yum install -y wireguard-tools qrencode
                }
            fi
            ;;
        *)
            warn "不支持的操作系统 $OS,尝试编译安装..."
            compile_install
            ;;
    esac
    
    # 验证安装
    if command -v wg >/dev/null 2>&1; then
        log "WireGuard 安装成功: $(wg --version)"
    else
        error "WireGuard 安装失败"
    fi
}

# 编译安装
compile_install() {
    log "开始编译安装 WireGuard..."
    
    # 安装编译依赖
    case $OS in
        ubuntu|debian)
            sudo apt install -y git build-essential libmnl-dev pkg-config
            ;;
        *)
            if command -v dnf >/dev/null 2>&1; then
                sudo dnf groupinstall -y "Development Tools"
                sudo dnf install -y git libmnl-devel pkgconfig gcc-c++
            elif command -v yum >/dev/null 2>&1; then
                sudo yum groupinstall -y "Development Tools"
                sudo yum install -y git libmnl-devel pkgconfig gcc-c++
            fi
            ;;
    esac
    
    # 编译安装 wireguard-tools
    cd /tmp
    rm -rf wireguard-tools
    git clone https://git.zx2c4.com/wireguard-tools
    cd wireguard-tools/src
    make
    sudo make install
    
    # 安装 qrencode(可选)
    if command -v apt >/dev/null 2>&1; then
        sudo apt install -y qrencode
    elif command -v dnf >/dev/null 2>&1; then
        sudo dnf install -y qrencode
    elif command -v yum >/dev/null 2>&1; then
        sudo yum install -y qrencode
    fi
}

# 启用 IP 转发
enable_ip_forward() {
    log "启用 IP 转发..."
    
    # 临时启用
    echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward >/dev/null
    
    # 永久启用
    if grep -q "net.ipv4.ip_forward" /etc/sysctl.conf; then
        sudo sed -i 's/^#*net.ipv4.ip_forward=.*/net.ipv4.ip_forward=1/' /etc/sysctl.conf
    else
        echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
    fi
    
    sudo sysctl -p >/dev/null 2>&1
    log "IP 转发已启用"
}

# 安全的文件操作函数
create_secure_file() {
    local file_path="$1"
    local content="$2"
    
    # 创建目录
    sudo mkdir -p "$(dirname "$file_path")"
    
    # 创建临时文件
    local temp_file=$(mktemp)
    echo "$content" > "$temp_file"
    
    # 复制并设置权限
    sudo cp "$temp_file" "$file_path"
    sudo chmod 600 "$file_path"
    sudo chown root:root "$file_path"
    
    # 清理临时文件
    rm -f "$temp_file"
}

# 生成随机客户端IP (192.168.108.2 - 192.168.108.254)
generate_client_ip() {
    local base_ip="192.168.108"
    local random_suffix=$(( RANDOM % 253 + 2 ))  # 2-254
    echo "${base_ip}.${random_suffix}"
}

# 初始化服务端
init_server() {
    log "初始化 WireGuard 服务端..."
    log "使用网段: $NETWORK"
    log "服务器IP: $SERVER_IP"
    
    sudo mkdir -p $CONFIG_DIR
    sudo mkdir -p $CLIENTS_DIR
    
    # 生成服务器密钥
    if [ ! -f "$SERVER_PRIVATE_KEY" ]; then
        log "生成服务器密钥对..."
        sudo wg genkey | sudo tee $SERVER_PRIVATE_KEY | sudo wg pubkey | sudo tee $SERVER_PUBLIC_KEY >/dev/null
        sudo chmod 600 $SERVER_PRIVATE_KEY $SERVER_PUBLIC_KEY
    fi
    
    # 获取默认网卡
    DEFAULT_IFACE=$(ip route | grep default | awk '{print $5}' | head -1)
    [ -z "$DEFAULT_IFACE" ] && DEFAULT_IFACE="eth0"
    
    # 创建服务端配置
    create_secure_file "$SERVER_CONFIG" "
[Interface]
PrivateKey = $(sudo cat $SERVER_PRIVATE_KEY)
Address = $SERVER_IP/24
ListenPort = $PORT
SaveConfig = false

# 流量转发规则
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o $DEFAULT_IFACE -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o $DEFAULT_IFACE -j MASQUERADE
"

    log "服务端配置已创建: $SERVER_CONFIG"
    log "服务器公钥: $(sudo cat $SERVER_PUBLIC_KEY)"
}

# 启动服务端
start_server() {
    log "启动 WireGuard 服务端..."
    
    sudo systemctl enable wg-quick@wg0
    if sudo systemctl is-active wg-quick@wg0 >/dev/null 2>&1; then
        sudo systemctl restart wg-quick@wg0
    else
        sudo systemctl start wg-quick@wg0
    fi
    
    sleep 2
    if sudo systemctl is-active wg-quick@wg0 >/dev/null 2>&1; then
        log "WireGuard 服务端启动成功"
    else
        error "WireGuard 服务端启动失败"
    fi
}

# 添加客户端
add_client() {
    local client_name=$1
    local client_ip=$2
    
    [ -z "$client_ip" ] && client_ip=$(generate_client_ip)
    
    log "添加客户端: $client_name (IP: $client_ip)"
    
    # 生成客户端密钥
    local client_private_key=$(wg genkey)
    local client_public_key=$(echo $client_private_key | wg pubkey)
    
    # 获取服务器公网IP(用于客户端配置)
    local server_public_ip=$(curl -s -4 ifconfig.me || curl -s -4 ipinfo.io/ip || echo "YOUR_SERVER_IP")
    
    # 创建客户端配置
    local client_config="$CLIENTS_DIR/$client_name.conf"
    local client_config_content="[Interface]
PrivateKey = $client_private_key
Address = $client_ip/24
DNS = 8.8.8.8

[Peer]
PublicKey = $(sudo cat $SERVER_PUBLIC_KEY)
Endpoint = $server_public_ip:$PORT
AllowedIPs = 192.168.108.0/24
PersistentKeepalive = 25"
    
    create_secure_file "$client_config" "$client_config_content"
    
    # 添加到服务端配置
    sudo wg set wg0 peer "$client_public_key" allowed-ips "$client_ip/32"
    
    # 保存到服务端配置文件中
    echo "
# Client: $client_name
[Peer]
PublicKey = $client_public_key
AllowedIPs = $client_ip/32" | sudo tee -a $SERVER_CONFIG > /dev/null

    # 生成二维码(如果安装了 qrencode)
    if command -v qrencode >/dev/null 2>&1; then
        sudo qrencode -t ansiutf8 < "$client_config"
        sudo qrencode -o "$CLIENTS_DIR/$client_name.png" < "$client_config"
        log "客户端二维码已生成: $CLIENTS_DIR/$client_name.png"
    fi
    
    log "客户端添加成功!"
    echo "=========================================="
    echo "客户端名称: $client_name"
    echo "客户端IP: $client_ip"
    echo "客户端公钥: $client_public_key"
    echo "配置文件: $client_config"
    echo "=========================================="
    
    # 显示客户端配置
    echo -e "\n客户端配置内容:"
    sudo cat "$client_config"
}

# 批量添加内网节点
add_internal_nodes() {
    log "开始批量添加内网节点..."
    log "使用网段: $NETWORK"
    
    local nodes=("node1" "node2" "node3" "node4")
    local start_ip=2  # 从 192.168.108.2 开始
    
    for i in "${!nodes[@]}"; do
        local client_name="${nodes[$i]}"
        local client_ip="192.168.108.$((start_ip + i))"
        log "添加节点: $client_name -> $client_ip"
        add_client "$client_name" "$client_ip"
        echo
    done
    
    log "内网节点批量添加完成"
    log "节点IP分配:"
    for i in "${!nodes[@]}"; do
        echo "  ${nodes[$i]} -> 192.168.108.$((start_ip + i))"
    done
}

# 显示状态
show_status() {
    log "WireGuard 状态:"
    sudo wg show
    
    echo -e "\n连接的客户端:"
    sudo wg show | grep -A5 "peer" | grep -E "peer:|allowed ips:" | sed 's/peer:/客户端:/;s/allowed ips:/IP地址:/'
    
    echo -e "\nVPN 网络信息:"
    echo "网段: $NETWORK"
    echo "服务器: $SERVER_IP"
    echo "端口: $PORT"
    
    echo -e "\n配置文件列表:"
    sudo ls -la $CLIENTS_DIR/ 2>/dev/null || warn "客户端配置目录不存在"
}

# 显示使用说明
show_usage() {
    echo -e "${BLUE}WireGuard 管理脚本 (网段: $NETWORK)${NC}"
    echo "用法: $0 [选项]"
    echo
    echo "选项:"
    echo "  install        安装 WireGuard 并启用 IP 转发"
    echo "  server         初始化并启动服务端"
    echo "  add-client <名称> [IP]  添加客户端"
    echo "  add-nodes      批量添加内网节点 (node1-node4)"
    echo "  status         显示状态"
    echo "  restart        重启服务"
    echo "  full-setup     完整安装配置(安装+服务端+内网节点)"
    echo
    echo "示例:"
    echo "  $0 install           # 安装 WireGuard"
    echo "  $0 full-setup        # 完整安装配置"
    echo "  $0 add-client mypc   # 添加客户端"
    echo "  $0 status            # 查看状态"
}

# 完整安装配置
full_setup() {
    log "开始完整安装配置 WireGuard..."
    log "VPN 网段: $NETWORK"
    detect_os
    install_wireguard
    enable_ip_forward
    init_server
    start_server
    add_internal_nodes
    show_status
    log "完整安装配置完成!"
    
    echo -e "\n${GREEN}下一步操作:${NC}"
    echo "1. 在云服务器安全组开放 $PORT UDP 端口"
    echo "2. 将客户端配置文件分发到对应节点"
    echo "3. 在客户端安装 WireGuard 并导入配置"
    echo "4. 使用 VPN IP 建立 Docker Swarm 集群"
    echo -e "\n${YELLOW}重要信息:${NC}"
    echo "服务器公钥: $(sudo cat $SERVER_PUBLIC_KEY)"
    echo "VPN 网段: $NETWORK"
    echo "服务器内网IP: $SERVER_IP"
}

# 主函数
main() {
    case $1 in
        install)
            detect_os
            install_wireguard
            enable_ip_forward
            ;;
        server)
            init_server
            start_server
            ;;
        add-client)
            if [ -z "$2" ]; then
                error "请提供客户端名称"
            fi
            add_client "$2" "$3"
            ;;
        add-nodes)
            add_internal_nodes
            ;;
        status)
            show_status
            ;;
        restart)
            sudo systemctl restart wg-quick@wg0
            log "服务已重启"
            ;;
        full-setup)
            full_setup
            ;;
        *)
            show_usage
            ;;
    esac
}

# 脚本入口
if [ $# -eq 0 ]; then
    show_usage
else
    main "$@"
fi