Skip to content

🌐 网络工程 / 软考网工 ​

OpenVPN Docker 容器故障排查与修复 ​

  • 手机通过 OpenVPN 连接后能访问 GitHub,但 Google/YouTube 无法访问
  • 根本原因:
    1. DNS 配置错误: OpenVPN AS 推送的 DNS 是 127.0.0.11(Docker 内部 DNS),手机上不存在该地址
    2. NAT 缺失: VPN 子网 172.27.0.0/16 没有做 MASQUERADE,包出去了但回不来
  • 解决方法:
    1. 修改容器 /etc/resolv.conf 为公共 DNS(8.8.8.8 + 1.1.1.1)
    2. sacli 设置 vpn.client.routing.dns.0/1 为公共 DNS
    3. 容器内添加 iptables NAT: iptables -t nat -A POSTROUTING -s 172.27.0.0/16 -o eth0 -j MASQUERADE
    4. 修改 entrypoint 脚本使修复持久化
  • 关键知识点:
    • Docker 容器的 127.0.0.11 是内部 DNS 解析器,只在容器内有效
    • OpenVPN AS 配置要用 sacli 工具写入数据库,直接改 config-local.json 不生效
    • sacli ConfigPut → 写入配置,sacli Start/Stop → 重启服务
    • VPN 子网需要 NAT 才能访问外网,容器重启后 iptables 规则会丢失

反向代理(Reverse Proxy)技术 ​

正向代理 vs 反向代理 ​

  • 正向代理:代理客户端,帮客户端访问服务器(如 VPN、Fiddler)
  • 反向代理:代理服务器,帮服务器接收客户端请求(如 Nginx、HAProxy)

核心作用 ​

  1. 安全隐藏:客户端不知道真实服务器,反向代理是"面具",集中配置 WAF/防火墙
  2. 负载均衡:多台后端服务器,按策略分发请求(轮询、加权轮询、IP Hash、最少连接)
  3. SSL 终结(SSL Termination):客户端 HTTPS → Nginx 卸载 SSL → 后端明文 HTTP,减少加密开销
  4. 缓存加速:静态资源由 Nginx 直接响应,动态请求转发后端,减轻服务器压力
  5. 统一入口:多服务只暴露 80/443,按域名/路径分发(server_name + location + proxy_pass)
  6. 压缩与限流:Gzip 压缩响应、限制请求速率防 DDoS

常用 Nginx 指令 ​

  • proxy_pass:转发请求到后端地址
  • upstream:定义后端服务器组(负载均衡)
  • location:匹配请求路径
  • server_name:匹配域名

实际例子 ​

客户端 → Nginx :443 (HTTPS) → :8000 (MkDocs)

好处:加 HTTPS、绑域名、隐藏端口、统一管理

考试/面试要点 ​

  • 正向代理代表客户端,反向代理代表服务器
  • 负载均衡四种算法:轮询、加权轮询、IP Hash、最少连接
  • SSL 终结在代理层卸载加密

Nginx 负载均衡轮询配置 ​

基础配置(默认轮询算法) ​

基础配置(默认轮询算法) ​

nginx
http {
    upstream backend {
        server web01;
        server web02;
        server web03;
    }

    server {
        listen 80;
        server_name yourdomain.com;

        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

关键点 ​

  • upstream 块定义后端服务器组
  • 默认算法就是轮询(round-robin):依次分配 web01 → web02 → web03
  • proxy_pass http://backend; 中的 backend 对应 upstream 起的名字
  • server 后可加 :port(如 server web01:8080;),不写默认 80
  • proxy_set_header 把客户端真实信息传给后端

轮询变体 ​

nginx
# 1. 加权重(默认 weight=1)
upstream backend {
    server web01 weight=3;
    server web02;
    server web03;
}

# 2. ip_hash(同一客户端固定到同一后端)
upstream backend {
    ip_hash;
    server web01;
    server web02;
    server web03;
}

# 3. least_conn(最少连接数优先)
upstream backend {
    least_conn;
    server web01;
    server web02;
    server web03;
}

# 4. fair(按响应时间,第三方模块)
upstream backend {
    fair;
    server web01;
    server web02;
    server web03;
}

常用参数 ​

参数作用
weight=N权重,默认为 1
max_fails=N失败次数上限(默认 1),配合 fail_timeout
fail_timeout=10s失败超时时间(默认 10s)
backup备用服务器,其他全挂才启用
down永久下线,不参与负载
max_conns=N限制最大并发连接数
nginx
upstream backend {
    server web01 weight=3 max_fails=2 fail_timeout=10s;
    server web02 weight=2;
    server web03 weight=1;
    server web04 backup;       # 备用机
}

操作命令 ​

bash
nginx -t          # 检查配置语法
nginx -s reload   # 重载配置(不中断服务)
systemctl restart nginx

配置位置 ​

  • 主配置:/etc/nginx/nginx.conf
  • 站点配置:/etc/nginx/conf.d/ 或 /etc/nginx/sites-enabled/
  • 推荐 include /etc/nginx/conf.d/*.conf; 拆分

Stream 模块(四层负载均衡) ​

适用 TCP/UDP 层(如 MySQL、Redis、游戏服务器),不是 HTTP。

适用:TCP/UDP 服务负载(MySQL、Redis、游戏服务器等)。

nginx
stream {
    upstream web_cluster {
        server web01:80;
        server web02:80;
        server web03:80;
    }
    server {
        listen 80;
        proxy_pass web_cluster;
        proxy_connect_timeout 3s;
        proxy_timeout 600s;
    }
}

stream 模块注意 ​

  • 没有 proxy_read_timeout / proxy_send_timeout(HTTP proxy_pass 才有的)
  • proxy_timeout 控制 nginx↔客户端 连接的空闲超时,不是后端响应时间
  • TCP 层发不出去就超时,没法定义"业务响应超时"

故障转移 ​

nginx
server {
    listen 80;
    proxy_pass web_cluster;
    proxy_connect_timeout 3s;
    proxy_timeout 600s;

    proxy_next_upstream on;          # 默认就是 on,可不写
    proxy_next_upstream_tries 2;     # 总尝试次数
    proxy_next_upstream_timeout 5s;  # 整个重试超时时间
}

注意: stream 的 proxy_next_upstream 只对连接阶段生效(握手失败、连接被拒、连接超时),不能像 HTTP proxy 一样根据 500/502/503 等业务返回码切换。



sing-box 代理部署(RainYun 服务器) ​

背景 ​

  • 服务器:RainYun R9(北京机房),4 核 8G 内存
  • 系统:Debian 12 (bookworm)
  • 目的:为 OpenRouter API (openrouter.ai) 提供国内反向代理,解决 API 访问问题
  • 方案:使用 sing-box 做反向代理(非 VPN/代理上网,仅代理特定 API 域名)

安装过程 ​

1. 一键安装

bash
wget -O /usr/local/bin/sing-box-as-a-service.sh https://raw.githubusercontent.com/SagerNet/sing-box/refs/heads/dev/docs/sing-box-as-a-service.sh
chmod +x /usr/local/bin/sing-box-as-a-service.sh
bash /usr/local/bin/sing-box-as-a-service.sh

安装选项:1-安装;2-卸载;3-查看版本;5-安装为 systemd 服务(推荐)

2. 生成的文件

  • 配置文件:/etc/sing-box/config.json
  • 服务文件:/usr/lib/systemd/system/sing-box.service

配置架构 ​

Inbound(入站)— VLESS + Reality ​

json
{
  "type": "vless",
  "tag": "vless-in",
  "listen": "::",
  "listen_port": 443,
  "users": [{
    "name": "admin",
    "uuid": "你的UUID",
    "flow": "xtls-rprx-vision"
  }],
  "multiplex": {"enabled": false},
  "tls": {
    "enabled": true,
    "server_name": "www.microsoft.com",
    "reality": {
      "enabled": true,
      "handshake": {"server": "www.microsoft.com", "server_port": 443},
      "private_key": "你的私钥",
      "short_id": ["你的short_id"]
    }
  }
}

关键概念:

  • VLESS:轻量级代理协议,比 VMess 更高效
  • Reality:TLS 伪装技术,流量看起来像访问正常网站
    • server_name:伪装成访问 www.microsoft.com
    • handshake:实际与微软服务器进行 TLS 握手
  • XTLS-Vision:流控技术,提高代理效率
  • 端口 443:使用标准 HTTPS 端口,不被识别为代理

Outbound(出站)— 两种模式 ​

  • Direct(直连):请求直接发送到目标服务器
  • Block(拦截):拒绝连接,用于阻止不必要的流量

路由规则 ​

json
"route": {
  "rules": [
    {"domain_suffix": [".anthropic.com"], "outbound": "block"},
    {"domain_suffix": [".openrouter.ai"], "outbound": "direct"}
  ],
  "final": "direct"
}

服务管理 ​

bash
systemctl enable --now sing-box
systemctl status sing-box
journalctl -u sing-box -f

OpenClaw 配置代理 ​

在 systemd drop-in 中设置 HTTPS_PROXY:

bash
mkdir -p /etc/systemd/system/openclaw-gateway.service.d
cat > /etc/systemd/system/openclaw-gateway.service.d/proxy.conf << 'EOF'
[Service]
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
EOF
systemctl daemon-reload && systemctl restart openclaw-gateway

注意事项 ​

  • sing-box 仅代理特定 API 域名,不影响服务器其他服务
  • Reality 的 server_name 需选真实存在的网站
  • UUID 和密钥需妥善保管,泄露会导致未授权访问

客户端配置 — Clash Verge 远程导入 ​

  • 从 sing-box 配置中提取节点参数,生成 Clash Meta(mihomo)格式的 .yaml 配置文件
  • 服务器上开 HTTP 服务:python3 -m http.server 8080 -d <配置文件目录> &
  • Clash Verge 导入 URL:http://服务器IP:8080/配置文件.yaml
  • 优点:以后更新配置只需改服务器文件,Clash 端点刷新即可,不用每次本地导入
  • ⚠️ 用完记得关 HTTP 服务:kill $(lsof -t -i:8080)
  • 防火墙需放行对应端口:firewall-cmd --add-port=8080/tcp --permanent && firewall-cmd --reload

Mac 生成 SSH 密钥 ​

基本命令 ​

bash
ssh-keygen -t ed25519 -C "邮箱@example.com"

默认保存到 ~/.ssh/id_ed25519,一路回车即可。

指定文件名 ​

bash
ssh-keygen -t ed25519 -f ~/.ssh/mykey -C "邮箱"

传公钥到服务器 ​

bash
ssh-copy-id -i ~/.ssh/id_ed25519.pub 用户名@服务器IP

Mac 无 ssh-copy-id 的替代方案 ​

bash
cat ~/.ssh/id_ed25519.pub | ssh 用户名@服务器 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

注意 ​

  • ed25519 优于 RSA(更安全更快),除非老设备不支持
  • 兼容老设备用 ssh-keygen -t rsa -b 4096
  • 私钥别泄露,公钥可公开

ed25519 是什么 ​

定义 ​

ed25519 是一种非对称加密算法,具体是椭圆曲线数字签名算法(EdDSA)。

名称拆解 ​

  • Ed = Edwards 曲线(椭圆曲线变体)
  • 25519 = Curve25519(曲线参数名,Daniel Bernstein 设计)

在 SSH 中的作用 ​

生成公钥/私钥对。公钥放服务器验证身份,私钥自己留着证明身份。

与其他算法对比 ​

  • ed25519:密钥短、速度快、安全性高,首选
  • RSA:老牌兼容性好,但需 4096 位才够安全
  • ecdsa:比 RSA 好,有潜在随机数漏洞

优势 ​

  1. 密钥短(公钥仅 68 字符 vs RSA 几百字符)
  2. 生成和验证速度快
  3. 抗侧信道攻击,不依赖随机数质量
  4. 256 位密钥 ≈ RSA 3072 位安全强度

SSH 公钥存放位置 ​

服务器端路径 ​

~/.ssh/authorized_keys

设置步骤 ​

bash
mkdir -p ~/.ssh && chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys
cat 公钥.pub >> ~/.ssh/authorized_keys

Mac 一行命令传公钥 ​

bash
cat ~/.ssh/id_ed25519.pub | ssh 用户名@IP "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

权限要求 ​

  • ~/.ssh/ → 700(rwx------)
  • authorized_keys → 600(rw-------)
  • 权限不对 SSH 会忽略公钥文件

authorized_keys 放多个公钥 ​

直接放(推荐) ​

~/.ssh/authorized_keys 里一行放一把公钥,SSH 依次匹配:

ssh-ed25519 AAAA...公钥1 用户1@电脑1
ssh-ed25519 AAAA...公钥2 用户2@电脑2

吊销某把公钥直接删对应行即可。

分文件放(进阶) ​

在 /etc/ssh/sshd_config 中配置:

AuthorizedKeysFile .ssh/authorized_keys .ssh/keys/%u/%t/%k

然后按用户/用途分目录存放公钥。一般没必要,直接塞 authorized_keys 最简单。


SSH 本地端口转发 -L(VNC 场景) ​

基本命令 ​

bash
ssh -N -L 5900:127.0.0.1:5900 bbben@192.168.31.60

参数拆解 ​

参数含义
sshSSH 客户端
-N不执行远程命令,只建立隧道,适合纯端口转发
-L 本地端口:目标地址:目标端口建立本地端口转发(Local forwarding)
bbben@192.168.31.60SSH 登录用户和远程主机

完整语法:

text
-L [本地地址:]本地端口:目标地址:目标端口

数据流向 ​

text
本机 127.0.0.1:5900
        ↓ SSH 加密隧道
远程 SSH 主机
        ↓ 由远程主机发起连接
远程侧 127.0.0.1:5900

这里的 127.0.0.1:5900 是从远程 SSH 主机的视角访问的目标,不是本机的回环地址。

VNC 应用场景 ​

  • 远程机上的 VNC Server 只监听 127.0.0.1:5900,不直接暴露到网络。
  • 建立隧道后,本机访问 127.0.0.1:5900,等价于通过 SSH 访问远程机的 127.0.0.1:5900。
  • VNC Viewer 连接 127.0.0.1:5900 即可。

三种 SSH 转发对比 ​

类型参数数据流向常见用途
本地转发-L本地端口 → 远程侧可访问的目标访问远程内网服务、VNC、数据库
远程转发-R远程端口 → 本地侧可访问的目标把本地服务提供给远程侧访问
动态转发-D本地 SOCKS 代理 → 按请求动态访问目标临时代理、浏览远程网络

-N 与 -f ​

  • -N:不打开远程 Shell,也不执行命令,只保留转发连接。
  • -f:认证完成后转入后台,常与 -N 搭配使用:
bash
ssh -fN -L 5900:127.0.0.1:5900 bbben@192.168.31.60

后台隧道需要额外考虑断线重连和进程管理;长期使用可交给 systemd 或 autossh 管理。


Tailscale 组网与局域网访问 ​

纯命令行登录 ​

  1. 安装:curl -fsSL https://tailscale.com/install.sh | sh
  2. 执行 sudo tailscale up,终端会输出一个授权 URL
  3. 用任意能上网的设备(手机/电脑浏览器)打开该 URL,用 Tailscale 账号登录并授权
  4. 服务器终端会自动完成认证
  5. 其他方式:--auth-key=tskey-auth-xxx(预共享密钥,适合自动化部署)
  6. 本质:CLI 发起请求,浏览器完成授权,两步分离

Tailscale IP 与子网掩码 ​

问题:Tailscale 分配的 IP 为什么只有第一段 100 相同,第二三段都不同?

解答:Tailscale 使用 100.64.0.0/10 网段,/10 表示前 10 位是网络位:

100 = 01100100(二进制)
/10 要求前 10 位固定:01100100 01xxxxxx ...
第二字节只有前 2 位固定(必须是 01),后 6 位可变

所以第二字节范围 64-127,第三四字节完全自由,22 位主机位可分配约 419 万台

子网掩码对照:

  • /24(255.255.255.0):前 24 位固定,254 台主机
  • /16(255.255.0.0):前 16 位固定,65534 台主机
  • /10(255.192.0.0):前 10 位固定,约 419 万台主机

关键理解:不是前几位数字相同才算同一子网,而是按位数算。/10 只要求前 10 位一样,第一个字节相同 + 第二个字节前两位相同就够了

CIFS 挂载(客户端访问 Samba 共享) ​

命令:sudo mount -t cifs //100.x.x.x/共享名 /mnt/samba -o username=用户,password=***

逐项拆解:

  • sudo:挂载是系统级操作,需要 root 权限
  • mount -t cifs:把远程 SMB/CIFS 共享映射到本地目录
  • //IP/共享名:远程地址 + 共享名(// 固定格式)
  • /mnt/samba:本地挂载点

安全写法(密码写文件避免明文泄露):

bash
echo "username=用户" | sudo tee /root/.smbpasswd
echo "password=密码" | sudo tee -a /root/.smbpasswd
chmod 600 /root/.smbpasswd
sudo mount -t cifs //IP/共享 /mnt/samba -o credentials=/root/.smbpasswd

常用挂载选项:uid=1000(所有者), gid=1000(组), iocharset=utf8(中文乱码), vers=3.0(SMB协议版本), ro(只读)

卸载:sudo umount /mnt/samba,有进程在用时报 target is busy

服务器端安装客户端工具:

bash
# smbclient 是命令行工具,cifs-utils 提供 mount -t cifs 支持
# 都是客户端工具,不监听端口,不需要管理服务
sudo apt install smbclient cifs-utils

是否需要一直挂载?

  • 挂载点本身几乎不占资源,但网络断了会卡死(进程等待、命令卡住)
  • 偶尔用:手动 mount / umount
  • 经常用:用 autofs 自动挂载(访问时挂载,闲置 5 分钟自动卸载)
  • autofs 配置:echo "/mnt/samba -fstype=cifs,credentials=/root/.smbpasswd ://IP/共享" >> /etc/auto.smb

小弟二号打造的知识体系