我的最终方案:全局 Nginx 统一管理多个项目

预计阅读时间:10 分钟

这是「把自己部署到互联网上」系列的第 23 篇。

前两篇连续讨论了 Nginx:第 21 篇讲 Nginx 应该装在系统里,还是放进 Docker 容器;第 22 篇讲为什么我没有给每个项目都起一个 Nginx 容器。到这里,思路已经明确。

我的个人服务器后面不只跑博客,还可能跑个人官网、作品站、小工具和实验项目。如果每个项目都各自暴露端口、处理 HTTPS、维护 Nginx 配置,后面会越来越难管理。

所以我的最终方案是:全局 Nginx 统一管理多个项目的公网入口

这篇不是最终配置文件,而是后续部署博客和官网时遵循的整体架构。下一篇再进入公共网络、配置文件和启动检查。

主要解决的问题

公网入口不能乱

一台服务器可以有多个项目,但对外访问入口最好集中。用户访问博客或官网,不应该记端口,最终都应该通过标准的 80 和 443 访问。

证书不能散

HTTPS 证书如果分散到每个项目里,后面续期、挂载、reload 和备份都会变麻烦。

数据库和内部服务不能暴露公网

项目内部服务应该留在内部网络里,由 Nginx 统一代理,数据库只给项目内部访问。

多项目要能扩展

今天只有博客,明天可能有官网,后天还有其他工具。新增项目时,接入方式应该固定,而不是每次重新设计。

迁移要清楚

以后换服务器时,我要知道 Nginx 配置在哪里,证书在哪里,项目在哪里,数据在哪里。

这些问题合起来,就是一句话:外部入口集中,内部项目独立

整体架构设计

整体架构大概是:

公网用户
  -> 域名 DNS
  -> 服务器 80/443
  -> 全局 Nginx 容器
  -> 不同项目服务

更具体一点:

blog.aicultiv.com -> 全局 Nginx -> blog-app 容器
www.aicultiv.com  -> 全局 Nginx -> site-app 容器或静态目录
api.aicultiv.com  -> 全局 Nginx -> api-service 容器

数据库不对公网开放:

blog-app 容器 -> blog-db 容器

每个项目内部可以用自己的 Docker Compose 管理应用、数据库、缓存和后台任务。

但公网入口统一交给全局 Nginx。

全局 Nginx 管外部访问,项目 Compose 管内部服务,数据库只服务项目内部,HTTPS 证书集中放在统一位置。

服务器目录

为了长期维护,我会先规划服务器目录,例如:

/opt/coduty/
  nginx/
    compose.yml
    conf.d/
    certs/
    logs/
  projects/
    blog/
      compose.yml
      .env
      data/
    site/
      compose.yml
      .env
      dist/
  backups/
  scripts/

这不是唯一标准,大家可按照自己的习惯,自主规划。核心是:

  • 全局 Nginx 单独一个目录,每个项目单独一个目录,配置、证书、日志、数据分开放,备份和脚本有明确位置
  • 想改 Nginx,就去 nginx/conf.d
  • 想看证书,就去 nginx/certs
  • 想看博客项目,就去 projects/blog
  • 目录结构会直接影响后续排查和迁移

全局 Nginx 的第一职责是接管公网入口,所以它会绑定宿主机的 80 和 443。示意配置如下:

services:
  nginx:
    image: nginx:alpine
    container_name: global-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./conf.d:/etc/nginx/conf.d:ro
      - ./certs:/etc/nginx/certs:ro
      - ./logs:/var/log/nginx
    networks:
      - public

networks:
  public:
    external: true

这里有几个要点:

  1. 只有全局 Nginx 绑定公网 80 和 443
  2. 其他项目尽量不直接映射公网端口
  3. Nginx 配置通过挂载进入容器,方便编辑、备份和迁移
  4. 证书也通过挂载进入容器
  5. Nginx 加入一个外部公共网络,后面需要被代理的项目服务也加入这个网络

公共网络

全局 Nginx 要代理到不同项目容器,就必须能访问它们。不同 Compose 项目默认不一定能互相访问,所以我会创建一个公共网络,例如:

docker network create coduty-public

全局 Nginx 加入这个网络,需要被 Nginx 访问的应用容器也加入这个网络。项目内部服务仍然使用自己的默认网络。数据库通常不加入公共网络,只给项目内部应用访问。

项目服务示意:

services:
  app:
    networks:
      - default
      - coduty-public

networks:
  coduty-public:
    external: true

这样外部入口和内部数据服务就分开了。

域名转发由全局 Nginx 的 server 配置处理。例如博客:

server {
    listen 80;
    server_name blog.example.com;

    location / {
        proxy_pass http://blog-app:8000;
        proxy_set_header Host $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;
    }
}

这只是 HTTP 示例。后面配置 HTTPS 时,还要加 443、证书路径和 HTTP 到 HTTPS 跳转。

重点是:域名匹配放在全局 Nginx,项目服务只在内部提供端口,Nginx 根据域名转发到对应项目

新增项目流程

新增项目时,流程会比较固定:

  1. 项目服务加入公共网络
  2. 确认服务名和端口
  3. 在全局 Nginx 增加 server 配置
  4. 检查 Nginx 语法
  5. reload Nginx
  6. 配置 DNS 和 HTTPS。

SSL证书管理

证书也要集中管理。我的倾向是放在全局 Nginx 目录下,例如:

/opt/coduty/nginx/certs/
  example.com/
    fullchain.pem
    privkey.pem

Nginx 配置引用这些证书。这样证书申请、部署、续期和 reload 都集中在一个地方。如果后面使用通配符证书,比如 *.example.com,多个子域名可以共用同一套证书。具体通配符证书通常涉及 DNS 验证和私钥保护,后面需要单独处理

小结

全局 Nginx 统一入口,并不意味着项目混在一起。相反,项目内部要保持独立。

博客项目有自己的 compose.yml.env、应用容器、数据库容器、数据卷、初始化脚本和备份目录。

官网项目也可以有自己的构建流程、静态文件目录和部署容器。

全局 Nginx 只关心一件事:这个域名应该转发到哪个内部服务。它不直接管理项目内部数据库,也不承担业务逻辑

这个方案的好处很明确

  1. 公网入口清晰,只有全局 Nginx 占用 80 和 443
  2. 端口暴露更少,项目内部服务不直接暴露公网
  3. 证书集中管理
  4. 新增项目有固定接入流程
  5. 访问失败时可以按 DNS、安全组、防火墙、全局 Nginx、项目容器、应用日志逐层排查
  6. 迁移时 Nginx 配置、证书和项目目录都有固定位置。

风险也要提前规避:

  1. 全局 Nginx 会成为关键节点,一旦配置错误,可能影响多个项目
  2. 所以需要操作严格规范:改配置前备份;改完先检查语法;通过后再 reload;
  3. 每个域名一个配置文件,不把所有规则堆在一个大文件里
  4. 日志要能查。

容器化 Nginx 可以这样检查配置:

docker exec global-nginx nginx -t

检查通过后再 reload:

docker exec global-nginx nginx -s reload

配置文件建议拆开:

conf.d/
  blog.aicultiv.com.conf
  www.aicultiv.com.conf
  api.aicultiv.com.conf

最终方案可以概括为:

  • 公网只进入全局 Nginx80 和 443
  • Nginx 根据域名转发到不同项目
  • 项目内部仍然独立,用 Docker Compose 管理应用、数据库和数据卷
  • 数据库不暴露公网
  • 证书集中管理
  • 新增项目按统一规则接入

这个方案不是最复杂的,也不一定是正确的,条条大路通罗马,挺适合我的应用场景:一台机器,多个项目,一个人长期维护。

下一篇会把方案落到操作层面:全局 Nginx 容器实战,公共网络、配置文件与启动检查。


本文由 楸木 原创,转载请注明出处。

相关推荐

发现更多