全局 Nginx 容器实战:公共网络、配置文件与启动检查

预计阅读时间:10 分钟

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

上一篇我确定了 Nginx 方案:

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

这一篇开始落到操作层面。目标是先把全局 Nginx 容器跑起来,确认它具备接入多个项目的基础能力:能占用 80 和 443,配置文件在宿主机可维护,加入公共 Docker 网络,日志能查看,配置能检查,也能安全 reload

开始前,-服务器已经完成基础准备:

  • 可以用普通用户登录
  • Docker 和 Docker Compose 可用
  • 云平台安全组和系统防火墙已放行 80、443,且当前没有其他服务占用这两个端口。

可以先检查服务器端口:

sudo ss -lntp | grep -E ':80|:443'

如果系统 NginxApacheCaddy 或其他服务已经占用 80/443,会导致全局 Nginx 容器就绑定。我的服务器是新买的,所以说不太可能出现这种情况,如果已有服务占用了,就要考虑下把占用服务停掉,重新分配端口。

准备目录

我会把全局 Nginx 的配置、证书和日志放到固定位置,例如:

/opt/coduty/nginx/
  docker-compose.yml
  conf.d/
  certs/
  logs/

创建目录:

sudo mkdir -p /opt/coduty/nginx/conf.d
sudo mkdir -p /opt/coduty/nginx/certs
sudo mkdir -p /opt/coduty/nginx/logs

如果日常维护用户是 coduty,顺便调整操作权限:

sudo chown -R coduty:coduty /opt/coduty

存放路径自由发挥,不一定必须叫 /opt/coduty

关键是结构清楚:

Nginx 有独立目录,配置放 conf.d,证书放 certs,日志放 logs,Compose 文件放在入口目录下。

以后迁移服务器时,这套目录就是入口配置的主要资产。

创建公共 Docker 网络

全局 Nginx 容器要代理到不同项目容器,就必须和这些容器网络互通。

先创建一个外部公共网络:

docker network create coduty-public # 网络名可以按照自己的习惯命名

如果网络已经存在,就不需要重复创建。可以查看:

docker network ls

为什么要公共网络?

因为每个 Compose 项目默认有自己的内部网络。博客有博客的网络,官网有官网的网络。

全局 Nginx 如果不加入对应网络,就不能直接通过服务名访问项目容器

我的设计是:

  1. 项目保留自己的默认内部网络
  2. 只有需要被全局 Nginx 代理的应用容器,额外加入 coduty-public
  3. 数据库容器通常不加入公共网络,只给项目内部应用访问

编写全局 Nginx 的 Compose 文件。

进入刚才创建好的目录:

cd /opt/coduty/nginx

创建 docker-compose.yml

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

networks:
  coduty-public:
    external: true # 这个是关键,其他要通信的容器,也必须要有这一行

这里的重点参数解释下:

  • container_name 固定容器名,方便后续执行 docker exec global-nginx nginx -t
  • restart: unless-stopped 让容器在异常退出或服务器重启后自动拉起
  • ports 只映射 80 和 443
  • conf.dcerts 以只读方式挂载,避免容器内误改
  • logs 挂载到宿主机,方便查看和备份
  • coduty-public 是前面创建的外部网络。

准备最小配置。

创建 /opt/coduty/nginx/conf.d/default.conf

server {
    listen 80;
    server_name _;

    location / {
        return 200 "global nginx is running\n";
    }
}

这个配置暂时不代理项目,也不处理 HTTPS,只用于验证全局入口是否正常。先用最小配置确认 Nginx 能启动、80 端口能访问、安全组和防火墙都没问题,再逐步接入项目。

启动容器。

/opt/coduty/nginx 下执行:

docker compose up -d
docker ps 
docker logs global-nginx

如果启动失败,按顺序查:80/443 是否被占用,coduty-public 网络是否存在,挂载目录是否存在,配置文件是否有语法错误。容器没起来时,docker exec 用不了,可以先看:

docker compose logs

检查配置并 reload

全局 Nginx 是入口服务,每次改配置都要先执行检查:

docker exec global-nginx nginx -t

通过后再重载:

docker exec global-nginx nginx -s reload

千万不要跳过 nginx -t。后面博客、官网、作品站都接入后,一个错误配置可能影响多个站点。

自己的业务还好,再改下就好,公司的业务,还是建议慎重一些。

访问验证

如果服务器 IP 是 1.2.3.4,可以访问:

http://1.2.3.4

或执行:

curl http://1.2.3.4

预期返回:

global nginx is running

如果访问不到,按链路排查:容器是否运行;Nginx 是否监听 80;安全组是否放行;系统防火墙是否放行;本机是否能 curl http://127.0.0.1。如果本机能访问、外部不能访问,问题大概率在安全组、防火墙或公网链路;如果本机也不能访问,重点查容器、端口绑定和 Nginx 配置。

后续接入项目

博客应用容器叫 blog-app,监听 8000 端口,并加入了 coduty-public 网络,Nginx 配置可以写成:

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;
    }
}

这里的关键是 blog-app 必须能被 Nginx 容器解析到。也就是说,Nginx 和博客应用必须在同一个 Docker 网络里,并且服务名、容器名或网络别名要匹配。

可以进入 Nginx 容器测试:

docker exec -it global-nginx sh
wget -qO- http://blog-app:8000

如果失败,检查项目容器是否运行、是否加入公共网络、名称是否写对、应用是否监听正确端口。还要注意:如果应用只监听容器内的 127.0.0.1,其他容器可能访问不到,通常应监听 0.0.0.0 的服务端口。

配置文件

配置文件也要拆分。不要把所有站点写进一个巨大文件。推荐一个应用一个文件:

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

新增项目加一个文件,删除项目也能明确清理。后面 HTTPS 的 80 跳转和 443 证书配置,也可以放在对应站点文件里。

日志

日志方面,因为挂载到了宿主机 /opt/coduty/nginx/logs,可以直接查看:

ls -lh /opt/coduty/nginx/logs
docker logs global-nginx

后面可以按站点拆日志:

access_log /var/log/nginx/blog.access.log;
error_log /var/log/nginx/blog.error.log;

这样博客和官网的问题能分开排查。

常见问题

常见问题也很明确。

  • 端口被占用时,先用 ss 查谁占用了 80/443,不要随便改端口逃避
  • Nginx 找不到项目容器时,用 docker network inspect coduty-public 看两个容器是否在同一网络
  • 配置改了没生效时,先 nginx -t,再 reload,并检查挂载路径是否正确
  • 外部访问不到时,按 DNS、安全组、防火墙、Nginx 容器、端口监听、域名匹配、项目服务、Nginx 日志逐层查

到这里,全局 Nginx 还缺少HTTPS,也没有真正代理博客项目,但已经具备统一入口的基础:

目录清楚,公共网络存在,容器能启动,配置能检查,日志能查看,后续项目可以按固定方式接入

下一篇做阶段性复盘:从 Conda 到 Docker,再到全局 Nginx,我终于理清了部署架构。


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

相关推荐

发现更多