Skip to content

安全加固与端口收敛

部署完成后最重要的一步:确保业务端口不直接暴露公网,只有 Traefik 的 80/443(和 SSH)对外。

收敛原则

端口用途是否公网
80 / 443Traefik 入口✅ 开放
122SSH✅ 开放
3000 / 8080前端 / 后端❌ 仅本机
3306 / 6379MySQL / Redis❌ 仅本机
6443 / 10250K3s 系统❌ 仅内网

访问关系:公网 → 80/443 → Traefik → 内部服务,业务端口不直接对外。

1. 端口绑定 127.0.0.1

docker-compose 中把端口从 0.0.0.0 改绑到 127.0.0.1

yaml
services:
  frontend:
    ports:
      - "127.0.0.1:3000:3000"    # 之前是 "3000:3000"(等价 0.0.0.0)
  backend:
    ports:
      - "127.0.0.1:8080:8080"
  mysql:
    ports:
      - "127.0.0.1:3306:3306"
  redis:
    ports:
      - "127.0.0.1:6379:6379"

为什么服务还能访问

Traefik 是通过桥接网络 IP(如 172.19.0.3:3000)访问容器,与宿主端口映射无关。改绑 127.0.0.1 不影响路由,只阻止公网直连。

2. 固定容器 IP

Docker 容器重建后 IP 可能变化,导致 K8s Endpoints 指向失效。在 compose 中固定:

yaml
services:
  frontend:
    networks:
      home:
        ipv4_address: 172.19.0.3

networks:
  home:
    name: ljdou-home_default
    external: true            # 引用已存在的网络

固定后,K8s Endpoints 与容器 IP 长期一致,不再担心 502。

3. 健康检查

depends_on 默认只等容器「启动」而非「就绪」。MySQL 启动需要时间,后端可能抢跑导致连接失败。给依赖加健康检查:

yaml
services:
  mysql:
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-proot123"]
      interval: 5s
      timeout: 5s
      retries: 20

  redis:
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 10

  backend:
    depends_on:
      mysql:
        condition: service_healthy      # 等 MySQL 就绪再启动
      redis:
        condition: service_healthy

4. 验证

bash
# 容器状态应显示 (healthy)
docker ps

# 确认业务端口不再监听 0.0.0.0
ss -tlnp | grep -E '0.0.0.0:(3000|8080|3306|6379)' || echo "已收敛"

# 确认后端数据库连接正常
docker logs ljdou-backend | grep -i mysql

最终防护建议

即使宿主机端口已收敛,仍建议在云安全组层面只放行 80 / 443 / 122,形成双层防护:

公网 → 云安全组(80/443/122) → 服务器防火墙 → Traefik → 服务

宿主机上宝塔面板(14639)、宝塔 MySQL(13306)、Traefik 仪表盘(18080)等端口,如无必要也应一并收敛。

基于 VitePress 构建