对外公网部署

小艾同学 ... 大约 10 分钟

# 对外公网部署

# 一、前置检查:22001 端口状态确认

在开始任何对外方案前,先确认服务在目标端口正常监听,且防火墙策略与预期一致。

# 1.1 确认端口监听地址

在知识库服务器上执行:

# Linux
ss -tlnp | grep 22001

# Windows
netstat -ano | findstr :22001
1
2
3
4
5

关注 LISTEN 后面的地址:

  • 显示 127.0.0.1:22001:服务仅本机可访问,适合后面所有“代理/隧道”方案,但不适合直接端口映射。
  • 显示 0.0.0.0:22001 或 :::22001:服务监听所有网卡,内网可直接通过 服务器IP:22001 访问,但也意味着有被意外暴露的风险,需要重点控制防火墙。

如果服务可以配置监听地址,生产环境建议改为 127.0.0.1:22001,把“对外”完全交给代理层处理,避免端口无意中暴露。

# 1.2 防火墙放行规则(仅在需要“直接暴露”时使用)

如果选择方案一(直接端口映射),需要在知识库服务器本机防火墙放行 22001,同时确保云安全组/路由器端口映射也放行。如果选择代理/隧道方案,通常不需要在知识库服务器上对外开放 22001。

# Linux firewalld 示例(仅在方案一需要)
sudo firewall-cmd --permanent --add-port=22001/tcp
sudo firewall-cmd --reload
1
2
3

# 二、方案一:直接端口映射(最简,仅限测试/受控内网)

适用场景:临时演示、完全可控的内网环境、有固定公网 IP 且仅对已知 IP 开放。
风险:知识库端口直接暴露,不推荐用于生产;扫描器会直接探测 22001 等服务端口。

# 2.1 架构

客户端 → 公网IP:22001(或路由器映射端口) → 知识库服务器:22001
1

# 2.2 配置步骤

情形 A:云服务器有公网 IP

  1. 在云平台安全组中放行入方向 TCP:22001,源 IP 尽量限制为已知客户端出口 IP,不要用 0.0.0.0/0。
  2. 确认知识库服务监听 0.0.0.0:22001 或 内网IP:22001(127.0.0.1 不可从外部直接访问)。
  3. 客户端连接地址填写:http://公网IP:22001(或 https://,如果服务本身启用了 TLS)。

情形 B:内网服务器 + 路由器端口映射

  1. 在路由器中将公网端口(建议不要用 22001,改为随机高端口,如 39201)映射到内网知识库服务器的 22001。
  2. 客户端填写:http://公网IP:39201。

# 2.3 客户端切换写法

客户端中可保存为一条“直连”配置,地址形如 http://IP:端口。切换到该配置即直连 22001。

⚠️ 强烈建议:如果走这个方案,至少在知识库前置一层简单的IP 白名单,并在用完后及时关闭端口映射。生产环境请直接进入方案二或方案三。


# 三、方案二:Nginx / Caddy 反向代理(生产推荐,有公网 IP 或域名)

适用场景:有公网 IP、有域名,希望统一入口、启用 HTTPS、隐藏后端端口、叠加访问控制。这是生产环境最常规的做法:外部只访问 80/443,Nginx 把请求转发到本机 127.0.0.1:22001。

# 3.1 架构

客户端 → 域名:443(HTTPS) → Nginx → 127.0.0.1:22001(知识库)
1

Nginx 与知识库服务部署在同一台机器时,proxy_pass 写 127.0.0.1:22001,知识库可保持 127.0.0.1 监听,22001 完全不暴露。

# 3.2 Nginx 配置示例

创建 /etc/nginx/conf.d/knowledge.conf:

server {
    listen 443 ssl http2;
    server_name kb.example.com;   # 替换为你的域名

    ssl_certificate     /etc/nginx/ssl/kb.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/kb.example.com.key;

    # 安全响应头(按需)
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;

    location / {
        proxy_pass http://127.0.0.1:22001;
        proxy_http_version 1.1;

        proxy_set_header Host              $http_host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 知识库常见的长连接 / 流式响应支持
        proxy_read_timeout 300s;
        proxy_buffering off;
    }
}

# HTTP 跳转 HTTPS
server {
    listen 80;
    server_name kb.example.com;
    return 301 https://$host$request_uri;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

关键指令说明:

指令 作用
proxy_pass http://127.0.0.1:22001; 将请求转发到本机 22001
proxy_set_header Host $http_host; 保留客户端访问的域名和端口,避免后端生成错误的跳转链接
X-Forwarded-For / X-Real-IP 让知识库能拿到真实客户端 IP,便于审计和限流
proxy_buffering off; 如果知识库有流式问答/SSE,避免代理缓冲导致响应延迟

检查并重载:

sudo nginx -t && sudo systemctl reload nginx
1

# 3.3 客户端切换写法

客户端中新增配置:

  • 地址:https://kb.example.com
  • 端口:留空(HTTPS 默认 443)或按客户端要求填写 443

切换到该配置即可通过域名走 Nginx 访问,客户端完全不需要知道 22001。

# 3.4 在 Nginx 层叠加基础安全

即使知识库自身有登录,也建议在 Nginx 层做一层收敛:

  • IP 白名单(如仅允许公司出口 IP / VPN 网段):
    allow 203.0.113.0/24;
    allow 10.0.0.0/8;
    deny  all;
    
    1
    2
    3
  • 请求体大小限制:client_max_body_size 100m;(按知识库上传文件上限调整)。
  • 限流(防止接口被刷):可结合 limit_req_zone 使用。

# 四、方案三:frp 内网穿透(无公网 IP,有云服务器中转)

适用场景:知识库部署在没有公网 IP 的内网/办公网,但有一台带公网 IP 的云服务器作为中转。frp 是成熟的 TCP 反向代理工具,适合把内网 22001 暴露到公网服务器的某个端口。

# 4.1 架构

客户端 → 云服务器公网IP:远程端口 → frps(云服务器) → frpc(内网) → 127.0.0.1:22001
1

# 4.2 云服务器(frps)配置

frps.toml:

bindPort = 7000
# 建议开启 token 认证
auth.method = "token"
auth.token = "替换为强随机字符串"

# Dashboard(可选,用于查看隧道状态)
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "替换为强密码"
1
2
3
4
5
6
7
8
9
10

云服务器安全组放行:7000/tcp(frp 通信)、7500/tcp(Dashboard,可选),以及你计划对外使用的远程端口(下方示例用 22001,但更推荐换一个非默认端口,如 39201)。

# 4.3 内网知识库侧(frpc)配置

frpc.toml:

serverAddr = "云服务器公网IP"
serverPort = 7000

auth.method = "token"
auth.token = "替换为与 frps 一致的 token"

[[proxies]]
name = "knowledge-base-22001"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22001
remotePort = 39201      # 公网侧使用的端口,建议不要用 22001
1
2
3
4
5
6
7
8
9
10
11
12

启动 frpc 后,客户端访问 http://云服务器公网IP:39201,流量经 frps → frpc → 本机 22001。

# 4.4 客户端切换写法

客户端中新增配置:

  • 地址:http://云服务器公网IP
  • 端口:39201(或你在 remotePort 中设定的值)

切换到该配置即通过 frp 隧道访问内网知识库。注意:frp TCP 隧道本身不终结 HTTPS;如果要对公网启用 HTTPS,应在云服务器的 frps 前面再加一层 Nginx 反向代理到 127.0.0.1:39201,或者使用 frp 的 HTTPS 类型代理(需域名和证书)。

# 4.5 frp 方案的安全要点

  • 务必开启 token 认证,不要裸奔 bindPort。
  • remotePort 不要用 22001,避免扫描器直接命中知识库常见端口。
  • 云服务器安全组对 remotePort 的入方向尽量限制源 IP,或至少在 frps 前面用 Nginx 做 IP 白名单和限流。
  • 定期更新 frp 版本,关注 Dashboard 异常连接。

# 五、方案四:零信任组网 / VPN 类方案(无公网 IP,最高收敛)

适用场景:不希望把任何知识库端口暴露到公网,只允许授权设备像在局域网一样访问 22001。代表方案:Tailscale、ZeroTier、企业 VPN。Tailscale 基于 WireGuard,零端口暴露,适合“远程办公安全访问内网知识库”的场景。

# 5.1 架构(以 Tailscale Subnet Router 为例)

授权客户端(安装 Tailscale) → WireGuard 加密隧道 → 内网 Subnet Router → 知识库服务器:22001
1

客户端不需要知道公网 IP 或隧道端口,只需要访问内网 IP:22001,组网层负责把流量安全地送到内网。

# 5.2 关键配置步骤

  1. 注册 Tailscale,创建 tailnet。
  2. 在内网一台常开机器上安装 Tailscale,并开启 Subnet Router,把知识库所在内网网段广播到 tailnet:
    tailscale up --advertise-routes=192.168.1.0/24
    
    1
    然后在 Tailscale 管理后台批准该路由。
  3. 授权客户端安装 Tailscale 并登录同一 tailnet,接受路由:
    tailscale up --accept-routes
    
    1
  4. 在 Tailscale ACL 中限制只有特定用户/设备可以访问知识库服务器的 22001 端口,不要默认全通。

# 5.3 客户端切换写法

客户端中新增配置:

  • 地址:http://知识库服务器内网IP(如 http://192.168.1.50)
  • 端口:22001

前提:客户端设备已加入 Tailscale/ZeroTier 网络,并获授权。切换到该配置即可通过加密隧道访问 22001,公网上不存在任何暴露的 22001 端口。

# 5.4 适用判断

条件 是否适合零信任组网
用户是员工/固定合作方,可安装客户端 ✅ 非常适合
需要给完全陌生的外部用户“打开就能用” ❌ 不适合,仍需方案二/三
对“零端口暴露”有硬性安全要求 ✅ 首选
不想维护公网服务器和证书 ✅ 有优势

# 六、方案对比与选型建议

维度 方案一:直接端口映射 方案二:Nginx 反向代理 方案三:frp 内网穿透 方案四:零信任组网
前置条件 公网 IP 或路由器管理权 公网 IP + 域名 公网云服务器 授权设备可装客户端
22001 是否暴露公网 是 否(仅本机) 否(仅本机) 否(仅内网)
HTTPS 支持 依赖服务自身 原生支持 需额外叠加 隧道加密,应用层可再 HTTPS
配置复杂度 最低 中 中高 中
安全收敛能力 弱 强(白名单/限流/证书) 中(依赖 frps 安全配置) 最强(身份+ACL)
适合外部陌生用户 不推荐 ✅ ✅(配合 Nginx) ❌
推荐使用场景 临时测试 生产环境,有域名 无公网 IP 但有云服务器 员工/固定伙伴远程访问

选型建议:

  • 有公网 IP 和域名 → 直接走 方案二,这是最标准、最可控的生产方案。
  • 没有公网 IP,但有一台云服务器 → 方案三 frp + 云服务器 Nginx,兼顾可达性和安全。
  • 用户是员工或固定合作方,安全要求高 → 方案四 Tailscale/ZeroTier,零端口暴露。
  • 只有测试/临时演示 → 可以用方案一,但用完立即关闭映射,并限制源 IP。

# 七、通用安全加固清单(任何对外方案都应关注)

无论选择哪种方案,建议逐项确认:

  • [ ] 知识库服务不要监听 0.0.0.0:22001,除非确实在受控内网且无代理层。生产环境优先 127.0.0.1:22001。
  • [ ] 对外入口不用 22001 作为公网端口,改用非默认端口,降低扫描命中率。
  • [ ] 如果走 HTTP/HTTPS,强制 HTTPS,禁用弱 TLS 版本。
  • [ ] 在代理/隧道/组网层限制源 IP 或设备身份,不要默认对全网开放。
  • [ ] 对知识库的上传接口、问答接口做请求体大小和频率限制,防止被当成免费算力代理刷接口。
  • [ ] 定期检查 ss -tlnp 和代理/隧道日志,确认没有多余的对外监听。
  • [ ] 客户端切换配置时,不同方案的地址、端口、协议(http/https)要分开保存,避免把“直连 22001”的配置误用于公网环境。

# 八、故障排查速查

现象 优先检查
客户端连不上代理/域名 DNS 解析、Nginx server_name、防火墙 443/80
Nginx 返回 502 知识库是否在 127.0.0.1:22001 正常监听;proxy_pass 地址是否正确
frp 隧道建立但访问超时 云安全组是否放行 remotePort;frpc 的 localIP/localPort 是否正确
Tailscale 能 ping 通内网但 22001 不通 Subnet Router 路由是否批准;知识库服务器本机防火墙是否放行 22001;Tailscale ACL 是否允许该端口
客户端切换后仍连旧服务 检查客户端是否真正应用了新配置;部分客户端会缓存连接,切换后建议手动重连

文档结论:客户端已支持“填写地址自动切换”的前提下,最推荐的生产路径是 方案二(Nginx 反向代理 + HTTPS + IP 白名单);没有公网 IP 时用 方案三(frp + 云服务器) 作为过渡;安全要求最高的员工/伙伴访问走 方案四(Tailscale/ZeroTier)。方案一仅用于测试,且应严格限制源 IP 和时效。所有方案共通的底线是:不要让 22001 以裸端口形式长期暴露在公网。