# 网络代理

# 代理服务器

:Proxy Server ,用于代替一个主机与其它主机进行通信。

  • 工作在会话层,代理应用层的消息。
  • 按协议分类:
    • SSH 代理
    • FTP 代理
    • HTTP 代理
    • HTTPS 代理
    • SOCKS 代理:全称为 SOCKetS ,工作在应用层与传输层之间,比 HTTP 代理更底层、更快。
      • SOCKS4 只支持 TCP 连接,而 SOCKS5 还支持 UDP 连接、密码认证。
      • FTP、HTTP、SOCKS 代理都是明文通信,而 SSH、HTTPS、shadowsocks 代理是加密通信。
  • 按代理反向分类:
    • 正向代理 :侧重于代替 client ,向 server 发出访问请求。
    • 反向代理 :侧重于代替 server ,接收 client 的访问请求。
  • 用途:
    • 可以使 client 访问到某些代理服务器才能访问的网络,像 VPN 的功能。
    • 可以担任防火墙,过滤 client 发送、接收的数据。
    • 可以动态更改将 client 的流量转发到哪个 server ,比如实现负载均衡。
    • 可以隔离 server 与 client ,使得 server 不知道 client 的真实 IP 、 client 不知道 server 的真实 IP 。
  • 缺点:
    • client 的通信数据都要经过代理服务器,可能被监听、篡改。

# Squid

:一个代理服务器,采用 C++ 语言开发。

  • 官网 (opens new window)
  • 支持 FTP、HTTP、HTTPS 代理协议。
  • 常用作简单的 HTTP 正向代理服务器。
  • 也可用于反向代理,缓存 HTTP 服务器的响应报文,但比 Nginx 的功能少。

# 部署

  • 用 yum 安装:
    yum install squid
    systemctl start squid
    systemctl enable squid
    
  • 或者用 docker-compose 部署:
    version: '3'
    
    services:
      squid:
        container_name: squid
        image: sameersbn/squid:3.5.27-2
        restart: unless-stopped
        ports:
          - 3128:3128
        volumes:
          - ./conf:/etc/squid/
    

# 配置

用 yum 安装 Squid 时,开启正向代理的步骤:

  1. 编辑配置文件 /etc/squid/squid.conf

    http_port 3128
    
    # 定义一个 acl 组,名为 local_ip ,指向源 IP 为 10.0.0.1/24 的流量
    # acl local_ip src 10.0.0.1/24
    
    # 定义一个 acl 组,用密码文件进行身份认证
    auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwd
    acl auth_user proxy_auth REQUIRED
    
    # 允许指定 acl 组的流量
    # http_access allow local_ip
    http_access allow auth_user
    # 禁止剩下的所有流量
    http_access deny all
    
    # 不缓存所有响应报文
    cache deny all
    cache_mem 10MB
    
    # 默认会在 HTTP 请求 Headers 中加入 X-Forwarded-For ,声明客户端的真实 IP 。这里删除该 Header
    forwarded_for delete
    
    # 记录访问日志
    access_log /var/log/squid/access.log squid
    # 每隔 30 天翻转一次日志
    logfile_rotate 30
    
    # 可选将当前代理的 HTTP 请求,转发给另一个代理服务器,实现代理链
    # cache_peer 10.1.1.1 parent 80 0 no-query no-digest
    # never_direct allow all
    
  2. 生成密码文件:

    yum install httpd-tools
    htpasswd -bc /etc/squid/passwd root ******
    
  3. 测试使用该代理:

    systemctl restart squid
    curl -x http://root:******@127.0.0.1:3128 cip.cc
    

# SOCKS5

  • 用 docker-compose 部署一个 SOCKS5 服务器:
    version: '3'
    
    services:
      socks5:
        container_name: socks5
        image: serjs/go-socks5-proxy:v0.0.3
        restart: unless-stopped
        environment:
          PROXY_USER: root
          PROXY_PASSWORD: ******
        ports:
          - 1080:1080
    

# Shadowsocks

:一种基于 SOCKS5 协议的代理协议,简称为 ss ,常用于实现 VPN 。

  • 官方文档 (opens new window)
  • 支持设置密码、加密传输数据。
  • 原理:
    1. 在一台主机上运行 ss 服务器。
    2. 在本机运行 ss 客户端,将本机的流量发送到 ss 服务器,被它代理转发。
  • ShadowsocksR :简称为 SSR ,是 shadowsocks 的分叉项目。

# Shadowsocks-libev

:一个 ss 代理服务器软件。

  • 于 2015 年发布,采用 C 语言开发,于 2020 年停止更新。
  • 支持 AEAD Cipher 加密算法。
  • 支持 Obfs 混淆,可以将 ss 流量伪装成 http 流量。
  • 用 Docker 部署服务器:
    docker run -d --name shadowsocks \
            --restart unless-stopped \
            -p 8388:8388 \
            shadowsocks/shadowsocks-libev:v3.3.5 \
            ss-server -s 0.0.0.0 -k ****** -m aes-256-gcm
    
    服务器的命令:
    ss-server               # 启动服务器
            -c config.json  # 使用指定的配置文件
            -s 0.0.0.0      # 设置服务器监听的 IP
            -p 8388         # 设置服务器监听的端口
            -k ******       # 设置服务器的认证密码
            -m aes-256-gcm  # 设置服务器的加密方式
            -v              # 显示详细日志
    

# Shadowsocks-rust

:一个 ss 代理服务器软件。

  • 用 Docker 部署服务器:
    docker run -d --name ssserver-rust \
            --restart unless-stopped \
            -p 8388:8388 \
            -v /root/shadowsocks-rust/config.json:/etc/shadowsocks-rust/config.json \
            ghcr.io/shadowsocks/ssserver-rust:v1.14.3
    
    配置文件示例:
    {
        "server": "0.0.0.0",
        "server_port": 8388,
        "password": "******",
        "method": "chacha20-ietf-poly1305",
        "fast_open": false
    }
    

# 客户端

Windows 版 ss 客户端 (opens new window)

  • 运行 ss 客户端之后,它会连接到 ss 服务器,同时在本机监听一个代理端口。
  • 本机的进程可以通过 HTTP、Socket 代理协议,将数据发送到该代理端口,然后 ss 客户端会将这些数据转发到 ss 服务器,实现正向代理。
  • 也可以开启 ss 客户端的全局模式,代理本机的所有流量。

Linux 版 ss 客户端 :

  • 它是一个命令行工具,功能较少,不能连接多个 ss 服务器,在本机提供的代理端口只支持 Socket 协议。

  • 部署示例:

    # 安装
    pip3 install shadowsocks
    
    # 编辑配置文件
    cat > ss.json <<EOF
    {
        "server": "10.0.0.1",
        "server_port": 8388,
        "local_address": "127.0.0.1",
        "local_port": 8388,
        "password": "******",
        "timeout": 5,
        "method": "aes-256-cfb"
    }
    EOF
    
    # 启动客户端
    sslocal -c ss.json -d start
    

    一个 sslocal 客户端只能连接一个 ss 服务器。

  • 可以再运行代理服务器 privoxy ,监听一个 HTTP 代理端口,将该端口的流量转发到 Socket 代理端口。

    # 安装
    yum install -y privoxy
    systemctl start privoxy
    systemctl enable privoxy
    
    # 编辑配置文件
    sed '/listen-address  127.0.0.1:8118/d' /etc/privoxy/config -i
    cat >> /etc/privoxy/config <<EOF
    listen-address  0.0.0.0:8118
    
    # 将 HTTP 请求转发到该代理
    forward-socks5  /   127.0.0.1:8388 .
    # 第一个字段为 url_pattern ,取值为 / 则匹配所有 HTTP 请求
    # 第二、三个字段为代理、父级代理,取值为 . 则表示忽略
    
    # 不代理这些 HTTP 请求
    forward         10.*.*.*/      .
    forward         127.*.*.*/     .
    forward         172.16.*.*/    .
    forward         192.168.*.*/   .
    EOF
    
    # 重启
    systemctl restart privoxy
    

    试用该代理:

    curl -x 127.0.0.1:8118 google.com
    

# V2Ray

:一个代理服务器,比 ss 的功能更多。

  • GitHub (opens new window)
  • 于 2019 年发布,采用 Goalng 语言开发。是 Project V 社区研发的主要软件,后来改名为 v2fly 。
  • V2Ray 服务器的流量分为两个方向:
    • inbounds :入站流量,即客户端发送到 V2Ray 的流量。
      • 客户端可使用 V2Ray 原创的 VMess 代理协议,也兼容 HTTP、Shadowsocks 等代理协议。
    • outbounds :出站流量,即 V2Ray 将客户端的流量转发到某个网站。
  • 用 Docker 部署服务器:
    docker run -d --name v2fly \
            --restart unless-stopped \
            -v /root/v2fly/config.json:/etc/v2fly/config.json \
            -p 80:80 \
            v2fly/v2fly-core:v5.1.0 \
            run -c /etc/v2fly/config.json
    
    配置文件示例:
    {
      "inbounds": [{
        "port": 80,
        "protocol": "vmess",
        "settings": {
          // 只允许这些 id 的客户端连接
          "clients": [{ "id": "******" }]
        }
      }],
      "outbounds": [{
        "protocol": "freedom",
        "settings": {}
      }]
    }
    
  • 在 Windows 上常用的客户端软件是 v2rayN (opens new window)

# Trojan

:一个代理服务器。能加密通信,并伪装成互联网常见的 HTTPS 流量。

  • 于 2019 年发布,采用 C++ 语言开发。

# 代理客户端

  • 有的程序不支持使用代理,有的程序只支持使用 HTTP 等简单的代理协议。因此建议安装一个专用的代理客户端,通过两种方式代理其它程序的流量:
    • 透明代理(Transparent proxy):
      • 拦截其它程序发出的流量,转发到代理服务器。其它程序不会感知到代理,不需要主动使用代理。
    • 转换代理协议:
      • 通过某种代理协议连接到代理服务器,再在本机监听一个采用 HTTP 等简单代理协议的端口,将该端口收到的流量转发到代理服务器。
      • 此时,具有代理功能的程序,一般都能通过该端口使用代理。但没有代理功能的程序,依然不能使用代理。

# Proxifier

:一个 GUI 工具,用作代理客户端,收费。

  • 特点:
    • 支持 Windows、MacOS 系统,不支持 Linux 。
    • 支持 HTTP、HTTPS、SOCKS4、SOCKS5 代理协议。
    • 支持透明代理。原理如下:
      • Windows 系统上,一般程序需要调用 Winsock API 进行 Socket 通信。
      • Winsock 提供了 LSP(Layered Service Provider) 功能:允许程序自定义一个 LSP DLL 库,在一般程序调用 Winsock API 时被加载,从而可以劫持其流量。
    • 支持灵活的代理规则:将某个程序发向某 IP:Port 的 TCP 包,转发到某个代理服务器。支持通配符。
    • 支持用多个代理服务器组成代理链。
  • 用法:
    1. 安装 Proxifier 并启动。
    2. 添加代理服务器。
    3. 添加代理规则。
    4. 保持 Proxifier 运行,即可代理本机程序的流量。

# ProxyChains

:一个 Unix 系统的命令行工具,采用 C 语言开发,用作代理客户端。

  • GitHub (opens new window)
  • 支持透明代理。原理如下:
    1. 声明环境变量 LD_PRELOAD ,让程序在导入 DLL 库时,优先导入 libproxychains4.so 库。
    2. 在 libproxychains4.so 库中,重写关于 Socket 通信的函数,将程序发出的 TCP 流量转发到代理服务器。
  • 缺点:
    • 只能代理 TCP 流量,不支持 UDP、ICMP 。
    • 只能代理指定的程序,不能代理系统所有进程。
    • 只能代理采用动态链接库的程序。
      • Chrome 浏览器在沙盒中运行网页,也不会被代理。

# 部署

  1. 安装:
    wget https://github.com/rofl0r/proxychains-ng/archive/refs/tags/v4.14.tar.gz
    tar -zxvf v4.14.tar.gz
    cd proxychains-ng-4.14
    ./configure --prefix=/usr --sysconfdir=/etc
    make
    make install
    
  2. 编辑配置文件 /etc/proxychains.conf ,示例:
    quiet_mode          # 安静模式,运行时不输出过程信息
    dynamic_chain       # 自动选用 ProxyList 中可用的代理,且按顺序
    proxy_dns           # 将 DNS 请求也代理
    
    # 取消代理发向指定 IP 的数据包
    localnet 127.0.0.0/255.0.0.0
    localnet 10.0.0.0/255.0.0.0
    localnet 172.16.0.0/255.240.0.0
    localnet 192.168.0.0/255.255.0.0
    
    # 发送数据包时,修改目标 IP:Port
    dnat 1.1.1.1:80  1.1.1.2:443
    dnat 1.1.1.1:443 1.1.1.2
    dnat 1.1.1.1     1.1.1.2
    
    # 声明一组代理服务器,支持 HTTP、SOCKS4、SOCKS5 代理协议,支持设置账号密码
    [ProxyList]
    http    127.0.0.1   3128
    socks5  127.0.0.1   1080  root  ******
    
  3. 执行命令:
    proxychains4 curl cip.cc  # 在代理下执行一条命令
    proxychains4 bash         # 创建一个 shell ,在其中执行的命令都采用代理
    

# redsocks

:一个 Linux 系统的命令行工具,采用 C 语言开发,用作代理客户端。

  • GitHub (opens new window)
  • 支持透明代理。原理如下:
    1. redsocks 连接到代理服务器,并在本机监听一个端口,将该端口收到的流量转发到代理服务器。
    2. 用户手动配置 iptables 防火墙规则,将本机发出的 TCP 流量重定向到 redsocks 端口。
  • 缺点:
    • 需要手动配置 iptables 规则,比较麻烦。
    • 有些程序可能无视 iptables 规则。

# 部署

  1. 用 apt 安装:
    apt install redsocks
    
    或者手动编译后安装:
    git clone https://github.com/darkk/redsocks
    cd redsocks
    make
    cp redsocks /usr/bin/redsocks
    
  2. 编辑配置文件 /etc/redsocks.conf ,示例:
    base {
        log_debug  = off;
        log_info   = on;
        log        = stderr;    # 日志的保存位置,可改为 "file:/var/log/redsocks.log" 文件
        daemon     = on;
        redirector = iptables;
    }
    
    redsocks {
        // 在本机监听的端口
        local_ip   = 127.0.0.1;
        local_port = 12345;
    
        // 要连接的代理服务器
        ip       = 10.0.0.1;
        port     = 1080;
        type     = socks5;
        login    = <username>;
        password = <password>;
    }
    
    • 可以定义多个 redsocks{} 代理配置。
  3. 用 systemctl 保持运行:
    systemctl restart redsocks
    systemctl enable  redsocks
    
    或者手动启动:
    redsocks -c /etc/redsocks.conf
    
  4. 添加 iptables 规则:
    iptables -t nat -A OUTPUT -p tcp -d 192.168.1.0/24 -j REDIRECT --to-ports 12345   # 编辑 nat 表,将本机发出的某些流量重定向 REDSOCKS 端口
    iptables -t nat -L OUTPUT   # 查看 iptables 规则
    
    系统重启时会重置 iptables 规则。因此建议将配置 iptables 的命令保存为一个 shell 脚本,每次系统重启时执行它。

# Clash

:一个通用的代理客户端,采用 Golang 语言开发。

  • GitHub (opens new window)
  • 支持 HTTP、SOCKS、Shadowsocks、Vmess 等多种代理协议。
  • 支持 Linux、MacOS、Windows、Android 系统。
  • 在 Linux 系统上支持透明代理。
    • 原理与 redsocks 类似,需要手动配置 iptables 规则。

# 反向代理

实现反向代理的常见工具:

  • LVS
    • :可实现第四层的 TCP/UDP 代理。
  • F5
    • :一个通过硬件实现负载均衡的服务器,基于 BIG-IP 协议。
  • HAProxy
    • :一个反向代理服务器,可实现第四层的 TCP 代理、第七层的 HTTP 代理。
  • Nginx
    • :一个反向代理服务器,可实现第四层的 TCP 代理、第七层的 HTTP 代理。
  • keepalived
    • :基于 IPVS 技术 ,可实现第四层的 TCP/UDP 代理。
  • frp

# LVS

:Linux 虚拟服务器(Linux Virtual Server),是 Linux 的一个内核模块,通过转发 TCP/UDP 数据包,实现第四层的反向代理。

  • LVS 工作在内核态,比 Nginx 等用户态代理的性能更高。

  • 原理:

    • 创建一些 IPVS(IP Virtual Server)作为负载均衡器。
      • 每个 IPVS 绑定一个 Virtual IP ,称为 VIP 。
      • 每个 IPVS 负责将将访问 VIP 的 TCP、UDP 流量反向代理到某些后端的 IP 。这里将后端称为 Real Server 。
    • 配置 iptables 规则,将访问 VIP 的流量交给 IPVS 处理。
  • 有多种反向代理模式:

    • DR 模式(direct routing)
      • 原理:改写请求报文的目标 MAC 地址,将直接它转发给 Real Server 。而 Real Server 直接返回响应报文给 client ,不经过 IPVS 。
      • 优点:
        • 代理速度最快。
      • 缺点:
        • IPVS 所在的主机 IP ,与 Real Server IP ,必须位于同一个 VLAN 子网,否则不能将请求报文转发到 Real Server 。
        • 转换请求报文时不能修改目标端口,因此反向代理时不支持端口映射。假设 Real Server 监听的端口是 80 ,则 IPVS 监听的端口也只能是 80 。
    • NAT 模式
      • 原理:
        1. client 发出请求报文,dst_ip 为 IPVS 的 VIP ,src_ip 为 client_ip 。
        2. IPVS 收到请求报文,进行 DNAT ,将 dst_ip 改为 Real Server IP 。然后转发给 Real Server 。
        3. Real Server 收到请求报文,返回响应报文,dst_ip 为 client_ip ,src_ip 为 Real Server IP 。
        4. IPVS 收到响应报文,进行 SNAT ,将 src_ip 改为 VIP 。然后转发给 client 。
      • 优点:
        • 实现了透明代理。
      • 缺点:
        • 请求报文、响应报文都要经过 IPVS 处理,因此代理速度较慢。
        • 需要将 VIP 配置为 Real Server 主机的网关,否则 Real Server 的响应报文的 dst_ip 为 client_ip ,会直接发给 client ,不会经过 IPVS 的 SNAT 。这也限制了 IPVS 与 Real Server 必须位于同一个子网。
    • TUN 模式
      • 原理:
        1. IPVS 将 client 的请求报文,封装成新的 IP 包,dst_ip 为 Real Server IP 。然后转发给 Real Server 。
        2. Real Server 收到 IP 包,解包之后发现这些数据是 IPVS 发来的,还知道了 client_ip ,于是直接将响应报文发送给 client 。
      • 优点:
        • 支持 IPVS 与 Real Server 位于不同子网。
        • 响应报文不经过 IPVS ,因此性能比 NAT 模式高。
      • 缺点:
        • 需要 Real Server 所在主机支持 IP Tunneling 协议,才能解包。
  • 支持多种负载均衡算法:

    rr    # round robin(轮询),将请求报文轮流转发给各个后端,使得每个后端收到的请求数差不多相等。这是默认策略
    wrr   # weight round robin(加权轮询),给每个后端设置权重,权重更大的后端,更大概率收到请求
    
    sh    # source hashing ,计算请求报文的源 IP 的哈希值,将哈希值相同的请求转发给同一个后端
    dh    # destination hashing ,计算报文的目标 IP 的哈希值
    
    lc    # least connection(最少连接),监控每个后端的当前 TCP 连接数,将请求转发给连接数最少的后端
    wlc   # weight least connection(加权的 lc )
    
    lblc  # locality based least connections(基于局部的最少连接),记录每个请求的目标 IP 上一次使用的后端,作为转发规则,如果目标后端负载过大,则采用 lc 算法
    lblcr # locality based least connections with replication(带复制的 lblc ),记录每个请求的目标 IP 使用的一组后端,采用 lc 从组中选出一个后端
    
    sed   # shortest expected delay ,监控每个后端的平均响应耗时,将请求转发给耗时最短的后端
    nq    # never queue ,优先将请求转发给当前连接数为 0 的后端,如果不存在这样的后端,则采用 sed 算法
    
  • 可安装 ipvsadm 命令来管理 IPVS 。

    ipvsadm
        -A    # 新增 IPVS
        -D    # 删除 IPVS
        -L    # 列出所有 IPVS
        -n    # 将 ip、port 显示成数字,而不是服务名
    
        -t <vip:port> # --tcp-service ,指定 IPVS 监听的地址
        -u <vip:port> # --ucp-service
    
        -r <ip:port>  # --real-server ,指定 IPVS 反向代理的后端
        -s rr         # --scheduler ,负载均衡算法
        -w <int>      # --weight ,指定 real-server 的权重
        -p 300        # --persistent ,如果某个 client_ip 多次发出请求,间隔不超过该时长,则会被转发到同一个 real-server
    
        # 反向代理模式
        -g            # --gatewaying ,DR 模式,这是默认模式
        -m            # --masquerading ,NAT 模式
        -i            # --ipip ,TUN 模式
    
    • 例:
      ipvsadm -Ln
      ipvsadm -A -t 10.0.0.1:80 -s rr               # 新增一个 IPVS ,监听地址为 10.0.0.1:80 ,负载均衡算法为 rr
      ipvsadm -a -t 10.0.0.1:80 -r 10.0.0.2:80 -m   # 在 IPVS 中新增一条规则,反向代理 10.0.0.2:80 ,反向代理模式为 NAT
      

# keepalived

:一个命令行工具,用于实现高可用的反向代理。

  • GitHub (opens new window)
  • 原理:
    • 基于 IPVS 技术,反向代理多个 upstream 实例,支持健康检查。
    • 可部署多个 keepalived 实例,基于 VRRP 协议实现高可用。
  • 用途:
    • 常见的反向代理方案如下:
      • 网站部署一个 upstream 实例时,如果故障,用户就访问不了。通常部署一组 upstream 实例,用 Nginx 反向代理。用户只需访问 Nginx ,访问流量会被 Nginx 被转发到某个 upstream 实例。
      • Nginx 支持对这些 upstream 进行健康检查,只将流量转发到健康的 upstream 实例。即使个别 upstream 实例故障,用户依然能正常访问 Nginx 。
    • 上述方案实现了 upstream 的高可用,但 Nginx 本身存在单点故障的风险。
      • 虽然 Nginx 很少故障,但 Nginx 所在主机可能因为断电等原因宕机。
      • 即使在多个主机上分别部署一个 Nginx 实例,但域名只能解析到一个主机 IP ,并不能实现 Nginx 的高可用。
    • 可使用 keepalived 实现高可用的反向代理:
      • 在至少 2 个主机上分别部署一个 Nginx 实例。(也可省略 Nginx ,让 keepalived 直接反向代理 upstream )
      • 在至少 2 个主机上分别部署一个 keepalived 实例,反向代理上述一组 Nginx 。
      • 这组 keepalived 实例,相互之间通过 VRRP 协议通信,自动选举出一个当前可用的 keepalived 实例,担任 MASTER 节点,其它实例担任备用节点。
      • MASTER 节点会广播 Gratuitous ARP 消息,将一个 VIP 解析到自己的 Mac 地址。当前子网的其它主机发送请求到 VIP 时,实际上是发送到 MASTER 节点。
      • 当 MASTER 节点故障时,会自动选举一个备用节点,担任新的 MASTER 节点,并将 VIP 解析到新的 MASTER 节点,因此其它主机能继续访问 VIP 。
    • Nginx 等代理工具只能实现 upstream 的高可用(负载均衡+健康检查+故障转移),不能实现自身的高可用。而 keepalived 代理工具能基于 VRRP 协议实现自身的高可用。
    • 公有云平台一般不支持传播 ARP 消息,因此不能使用 keepalived 方案。

# 部署

  1. 在一个主机上安装:

    yum install keepalived
    systemctl start keepalived
    systemctl enable keepalived
    
  2. 编辑配置文件 /etc/keepalived/keepalived.conf

    # 全局配置
    global_defs {
        # router_id 10.0.0.1        # 该 VRRP 节点的名称,一般配置为主机 IP ,也可省略
        fBvrrp_skip_check_adv_addr  # 检查 VRRP 广播中的所有地址可能耗时久,如果重复收到主路由器的多次广播,则跳过检查
        # vrrp_strict               # 是否严格遵守 VRRP 协议,比如至少分配一个 VIP 、不支持 ping VIP 。建议注释该配置
    
        # vrrp_garp_master_repeat 5   # 当 MASTER 节点刚刚当选时,开始第一轮广播,广播几遍 Gratuitous ARP 消息
        # vrrp_garp_master_delay 5    # 当 MASTER 节点刚刚当选时,等几秒开始第二轮广播。如果配置为 0 ,则不会第二轮广播
        # vrrp_garp_master_refresh 0  # 当 MASTER 节点运行时,每隔几秒广播一轮 Gratuitous ARP 消息。默认配置为 0 ,表示只有第一轮、第二轮广播
        # vrrp_garp_master_refresh_repeat 1 # 每轮广播几遍 Gratuitous ARP 消息
        # vrrp_garp_interval 0        # 广播 Gratuitous ARP 消息时,间隔几秒
        # preempt_delay 0             # 当前节点启动时,收到 VRRP 广播 ,如果发现自己的 priority 比已有的 MASTER 节点高,则会抢占 MASTER 角色。可延迟几秒才抢占,避免频繁切换 MASTER
    }
    
    # 配置该 keepalived 所属的 VRRP 集群,名称为 VI_1
    # 一个子网内可部署多个 VRRP 集群,每个 VRRP 集群称为一个 vrrp_instance ,包含多个 VRRP 节点
    # 这里不需要配置所有 VRRP 节点的 IP 。因为每个 VRRP 节点会通过局域网广播,自动发现其它 VRRP 节点,并相互通信
    # 如果几个节点的 virtual_router_id 相同,则属于同一集群,会自动选举出 MASTER 节点
    vrrp_instance VI_1 {
        # state MASTER        # 该 keepalived 的初始状态,可担任 MASTER 或 BACKUP 节点,也可省略该配置,让它自动选举
        interface eth0        # 工作在哪个网口
        virtual_router_id 51  # 该 VRRP 节点所属的虚拟路由器的 id
        priority 100          # 该 VRRP 节点的优先级。一组 VRRP 节点的优先级应该各不相同,优先级最高的节点,总是会被选举为 MASTER 节点
        advert_int 1          # 每隔几秒广播一次 VRRP 消息,给其它 VRRP 节点
        authentication {      # VRRP 节点之间的身份认证
            auth_type PASS
            auth_pass ******  # 密码,最多 8 个字符
        }
        # 可分配多个 VIP ,会自动绑定到 MASTER 节点的网口
        # VIP 必须与当前主机 IP 位于同一子网,因为其它主机只会对当前子网内的 IP 进行 ARP 查询
        virtual_ipaddress {
            10.0.0.10
            # 10.0.0.11
        }
    }
    
    # 让 keepalived 运行一个虚拟服务器,监听 VIP 的一个端口,反向代理一组 real_server
    virtual_server 10.0.0.10 80 {
        delay_loop 5            # 每隔几秒执行一次健康检查
        lb_algo wrr             # 负载均衡算法,参考 LVS 的配置
        lb_kind NAT             # 反向代理模式,参考 LVS 的配置
        persistence_timeout 60  # LVC 的持久超时。如果某个 client_ip 多次发出请求,间隔不超过该时长,则会被转发到同一个 real_server
        protocol TCP            # 代理协议,可选 TCP 或 UDP
        # sorry_server 10.0.0.2 80  # 如果所有 real_server 都未通过健康检查,则将流量转发到该 server
    
        real_server 10.0.0.1 80 {
            weight 1            # 该 real_server 的权重
    
            # 健康检查的方式,可选 HTTP_GET、SSL_GET 等
            HTTP_GET {                # 可改为 SSL_GET
                url {                 # 可对多个 url 进行健康检查
                  path /test
                  status_code 200-299 301-302 401 # 向指定 url 发出 HTTP GET 请求,然后检查响应的状态码。默认配置为 status_code 200-299
                  # digest 640205b7b0fc66c1ea91c463fac6334d   # 还可检查响应的 MD5 哈希值
                }
                url {
                  path /test2
                }
                connect_timeout 3     # 连接超时
                nb_get_retry 3        # 重试次数
                delay_before_retry 3  # 重试间隔
            }
    
            # TCP_CHECK {
            #     connect_port 80
            #     connect_timeout 3
            # }
    
            # MISC_CHECK {            # 执行 shell 脚本来健康检查
            #     misc_path "/path_to_script/script.sh <arg_list>"
            # }
        }
        real_server 10.0.0.2 80 {
            weight 1
            TCP_CHECK {
                connect_port 80
                connect_timeout 3
            }
        }
    }
    
    # 可定义多个虚拟服务器
    virtual_server 10.0.0.10 443 {
        ...
    }
    
    • 修改配置文件之后,执行 systemctl start keepalived 重启才会生效。
    • 查看日志:
      [root@CentOS ~]# tail -f /var/log/messages | grep Keepalived
      Aug 12 12:26:53 [localhost] Keepalived_vrrp[323]: VRRP_Instance(VI_1) Transition to MASTER STATE    # 该节点属于 VI_1 集群,变为 MASTER 状态
      Aug 12 12:26:54 [localhost] Keepalived_vrrp[323]: VRRP_Instance(VI_1) Entering MASTER STATE
      Aug 12 12:26:54 [localhost] Keepalived_vrrp[323]: VRRP_Instance(VI_1) setting protocol VIPs.
      Aug 12 12:26:54 [localhost] Keepalived_vrrp[323]: Sending gratuitous ARP on eth0 for 10.0.0.10      # 广播 Gratuitous ARP 消息
      Aug 12 12:26:54 [localhost] Keepalived_vrrp[323]: VRRP_Instance(VI_1) Sending/queueing gratuitous ARPs on eth0 for 10.0.0.10   # 第一轮广播
      Aug 12 12:26:59 [localhost] Keepalived_vrrp[323]: Sending gratuitous ARP on eth0 for 10.0.0.10
      Aug 12 12:26:59 [localhost] Keepalived_vrrp[323]: VRRP_Instance(VI_1) Sending/queueing gratuitous ARPs on eth0 for 10.0.0.10   # 第二轮广播
      Aug 12 12:27:04 [localhost] Keepalived_vrrp[323]: Sending gratuitous ARP on eth0 for 10.0.0.10
      
    • 执行 ip addr show eth0 查看网口,是否绑定了 VIP 。
    • 在同一子网的其它主机可以 ping 通 VIP ,或者 curl 访问 VIP 的端口。但不能使用 traceroute 命令定位 VIP ,因为 VIP 没有路由。
    • 可以只配置 vrrp_instance ,不配置 virtual_server 反向代理。相当于给当前主机增加了 VIP ,供其它主机访问。
  3. 重复上述步骤,在第二台主机上部署一个 keepalived ,配置相同,只是 priority 为 99 。

    • 建议停止主机的 firewalld ,以免阻断各节点之间的 VRRP 通信。
    • 停止第一台主机,然后检查第二台主机,它会自动切换成 MASTER 角色,并绑定 VIP 。
    • 重启第一台主机,它的 priority 最高,会抢占 MASTER 角色,并绑定 VIP ,日志如下:
      Aug 12 12:36:21 [localhost] Keepalived_vrrp[413]: VRRP_Instance(VI_1) Received advert with lower priority 99, ours 100, forcing new election
      Aug 12 12:27:04 [localhost] Keepalived_vrrp[413]: Sending gratuitous ARP on eth0 for 10.0.0.10
      
    • 同时应该只有一台主机的网口绑定 VIP 。如果多台主机绑定同一个 VIP ,则该 VIP 解析到的 Mac 地址不固定,会增加 TCP 丢包率。

# frp

:一个命令行工具,提供了反向代理、内网穿透的功能。

  • GitHub (opens new window)
  • 采用 Golang 语言开发。
  • 支持 TCP、UDP、HTTP、HTTPS 等多种代理协议。
  • 采用 C/S 架构工作。
    • frps :服务器,部署在任一主机上,不需访问外部,只需被 frpc、用户访问。
      • frps 所在主机通常拥有一个固定的外网 IP ,供外网用户访问。
      • 用户向 frps 发送网络包时,会先被 frps 转发到 frpc ,再被 frpc 转发到内网服务。
    • frpc :客户端,部署在任一主机上,不需被外部访问,只需访问到 frps、内网服务。

例:

  1. 登录一台主机,下载 frp 的发行版,编辑配置文件 frps.ini :

    [common]
    bind_port = 7000        # 让 frps 监听一个端口,供 frpc 访问,用于它们内部通信
    token = xxxxxx          # 用于 frpc 与 frps 之间的认证
    

    启动服务器:

    ./frps -c frps.ini
    

    或者用 docker-compose 部署:

    version: '3'
    
    services:
      frps:
        container_name: frps
        image: snowdreamtech/frps:0.37.0
        restart: unless-stopped
        ports:
          - 7000:7000
        volumes:
          - ./frps.ini:/etc/frp/frps.ini
    
  2. 登录另一个主机,编辑配置文件 frpc.ini :

    [common]
    server_addr = 1.1.1.1   # frps 的地址
    server_port = 7000
    token = xxxxxx
    
    # 定义一个反向代理,名称自定义
    [proxy1]
    type = tcp                  # 代理的类型
    local_ip = 10.0.0.1
    local_port = 80-90,443
    remote_port = 80-90,443     # 让 frps 监听 remote_port 端口,供用户访问,并将该端口收到的网络包转发到 local_ip:local_port
    # bandwidth_limit = 1MB     # 限制带宽,默认无限制
    # use_compression = false   # frpc 与 frps 之间通信时,是否压缩
    # use_encryption = false    # frpc 与 frps 之间通信时,是否加密
    
    # 可以定义多个反向代理
    [proxy2]
    ...
    

    启动客户端:

    ./frpc -c frpc.ini
    

    或者用 docker-compose 部署:

    version: '3'
    
    services:
      frpc:
        container_name: frpc
        image: snowdreamtech/frpc:0.37.0
        restart: unless-stopped
        volumes:
          - ./frpc.ini:/etc/frp/frpc.ini
    
  3. 让用户访问 frps 的反向代理端口:

    curl 1.1.1.1:10080
    

# VPN

:虚拟私有网络(Virtual Private Network),指由公网上的几台主机组成一个虚拟的私有网络。

  • VPN 是一个私有网络。几个主机虽然通过公网通信,但数据包会加密传输,只有加入 VPN 网络的主机才能解密。
  • VPN 常用于实现正向代理。比如某个机房的各个服务器不暴露 SSH 端口到公网,但机房的网关暴露 SSH 端口到公网,用户可通过公网 SSH 登录该网关,然后间接 SSH 登录该机房的内网服务器。
  • VPN 软件与代理软件类似,但区别在于:
    • VPN 软件通常会将两个主机在网络层连通,比如可以 ping 通。而代理软件通常会将两个主机在传输层连通,不能 ping 通,可以 curl 访问端口。
    • VPN 软件默认会对主机上所有流量进行透明代理。而代理软件默认不开启透明代理,甚至不一定支持透明代理功能。