Docker 部署 NGINX:配置静态站点与反向代理
一台主机上既要托管静态页面,又要把 /api 请求转给应用服务,还要在改配置时尽量不打断已有连接。NGINX 把这些入口统一放进声明式配置;官方 Docker 镜像再把安装、进程前台运行和跨架构分发交给容器完成。
这篇指南选择 nginx:1.31.6 作为示例版本,完成一个本机可访问的静态站点,然后把同一份 server 配置扩展为反向代理。配置文件、站点内容和容器生命周期都由宿主机命令控制,适合先在开发机或单机服务上建立可重复的运行方式。
项目来源与版本信息
| 信息 | 内容 |
|---|---|
| 项目标题 | NGINX |
| 项目描述 | NGINX 是面向 HTTP、HTTPS、邮件协议的开源 Web 服务器、反向代理、负载均衡器、API 网关和内容缓存。 |
| GitHub 仓库 | nginx/nginx |
| 官网地址 | nginx.org |
| 主要开发语言 | C 97.74%、Vim Script 1.63%、XS 0.38% |
| 开源许可证 | BSD-2-Clause |
| 最近代码更新 | 2026-09-30(GitHub pushed_at,核对日期:2026-10-10) |
先确定采用方式
NGINX 源码仓库负责软件本身;官方 Docker 镜像由 nginx/docker-nginx 维护,并发布到 Docker Hub 的 nginx Official Image。镜像默认把 NGINX 以前台方式运行,容器停止时进程状态也会被 Docker 记录下来。静态文件放在 /usr/share/nginx/html,主配置位于 /etc/nginx/nginx.conf,conf.d/*.conf 会被主配置包含。
下面这条主路径适合单机或开发环境:
| 项目 | 选择 |
|---|---|
| 镜像 | nginx:1.31.6(mainline,固定 tag) |
| 备选版本 | nginx:1.30.5(stable) |
| 方法 | image-run,单容器运行 |
| 支持架构 | 官方列表包含 amd64、arm64v8、arm32v7、ppc64le、riscv64、s390x 等 |
| 宿主机入口 | 示例绑定 127.0.0.1:8080,不会直接暴露公网 |
| 数据位置 | 宿主机 site/ 和 conf.d/;删除目录会删除对应内容 |
镜像 tag 解决的是软件版本复现,不代表已经替你完成 TLS、访问控制、日志留存或多机高可用。digest 才是不可变的镜像内容标识,严格复现时应在拉取后记录 docker image inspect 的 RepoDigest。公网入口应再放在防火墙和 TLS 反向代理之后,并为镜像更新保留回滚 tag 或 digest。
NGINX 配置的三个层次
NGINX 配置由指令和上下文组成。http 包含 server,server 再包含 location;请求先按监听端口和主机名选中 server,再按 URI 选择匹配的 location。root 决定静态文件在容器内的路径,proxy_pass 则把请求转到上游服务。官方 Beginner's Guide给出了这套层级和重载语义。
正在准备渲染...
查看源码
flowchart LR
Client[浏览器或 API 客户端] --> Port[宿主机 127.0.0.1:8080]
Port --> Nginx[NGINX 容器 :80]
Nginx --> Server[server 按端口和域名选择]
Server --> Static[location /\n/usr/share/nginx/html]
Server --> Proxy[location /api/\nproxy_pass 上游应用]
Static --> Files[(宿主机 site/)]
Proxy --> App[应用服务]这意味着“改了文件”与“改了路由”是两类操作:替换 site/index.html 通常马上能读到新内容;改动 NGINX 指令则必须先用 nginx -t 检查,再发送 reload 信号。语法检查失败时,旧 worker 继续提供服务,不能把未检查的配置直接覆盖到线上。
用 Docker 启动第一个站点
执行者需要准备 Docker Engine 或 Docker Desktop、Bash 和 curl,Compose 在本篇主路径中不是必需项。以下命令在一个新的工作目录执行;这些命令不会下载或执行 NGINX 源码,只拉取官方镜像。
创建内容和配置
mkdir -p nginx-lab/site nginx-lab/conf.d
cd nginx-lab
cat > site/index.html <<'HTML'
<!doctype html>
<html lang="zh-CN">
<meta charset="utf-8">
<title>NGINX in Docker</title>
<h1>NGINX is serving this page</h1>
HTML
cat > conf.d/default.conf <<'NGINX'
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location = /healthz {
default_type text/plain;
return 200 "ok\n";
}
location / {
try_files $uri $uri/ =404;
}
}
NGINXconf.d/default.conf只定义虚拟主机,不覆盖镜像内的主配置;挂载整个 /etc/nginx/conf.d 后,容器只会读取工作目录里的这一份站点配置。healthz 是一个应用无关的 HTTP 探针,便于脚本检查 NGINX 是否已经能够处理请求。
运行并验证
docker pull nginx:1.31.6
docker run -d \
--name nginx-lab \
--restart unless-stopped \
-p 127.0.0.1:8080:80 \
-v "$PWD/site:/usr/share/nginx/html:ro" \
-v "$PWD/conf.d:/etc/nginx/conf.d:ro" \
nginx:1.31.6
docker ps --filter name=nginx-lab
docker exec nginx-lab nginx -t
curl --fail http://127.0.0.1:8080/healthz
curl --fail http://127.0.0.1:8080/
docker logs --tail=50 nginx-lab成功信号是容器状态为 Up、nginx -t 输出 syntax is ok 和 test is successful,健康检查返回 ok,首页包含 NGINX is serving this page。如果宿主机的 8080 已被占用,把左侧端口改成其他端口,例如 18080:80,同时修改后续 curl 地址;容器内仍监听 80。
配置生效和优雅重载
先编辑 conf.d/default.conf,例如把 return 200 "ok\n"; 改成 return 200 "ready\n";,然后在工作目录执行:
docker exec nginx-lab nginx -t
docker exec nginx-lab nginx -s reload
curl --fail http://127.0.0.1:8080/healthz只有第一条命令成功才执行 reload。NGINX master 进程会先检查新配置,再让旧 worker 完成正在处理的请求;检查失败时旧配置继续工作。若容器已经退出,先看 docker logs nginx-lab,不要对一个未运行的容器反复发送 reload。
让 NGINX 反向代理应用
静态站点之外,最常见的使用方式是让 NGINX 对外提供统一入口,把 /api/ 转给后端应用。下面的配置假设应用和 NGINX 在同一个 Docker 网络中,并且应用服务名为 app、监听 3000 端口;在 Compose 中服务名就是可解析的 DNS 名称。
将 conf.d/default.conf 的 server 改为:
server {
listen 80;
server_name _;
location = /healthz {
default_type text/plain;
return 200 "ok\n";
}
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://app:3000;
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;
}
}配置中的 proxy_pass http://app:3000; 会保留 /api/ 前缀;如果后端只接受去掉前缀的路径,应用路由要求决定 proxy_pass 的写法,不能只复制这一行。Linux 上若后端运行在宿主机而不是 Docker 网络,Docker DNS 不会自动解析 app;可以把应用加入同一网络,或显式配置 host-gateway。127.0.0.1 在容器内指向 NGINX 容器本身,不是宿主机。
应用网络可用 Compose 管理,但 NGINX 主路径仍然是同一个官方镜像。一个最小的网络片段如下,后端服务的镜像和端口必须替换成真实值:
services:
nginx:
image: nginx:1.31.6
ports:
- "127.0.0.1:8080:80"
volumes:
- ./site:/usr/share/nginx/html:ro
- ./conf.d:/etc/nginx/conf.d:ro
depends_on:
- app
app:
image: your-app:version
expose:
- "3000"启动后用 curl http://127.0.0.1:8080/api/health 检查真实后端响应。depends_on 只控制启动顺序,不等于应用已经健康;长期运行应为后端增加 healthcheck,并在 NGINX 日志中核对上游连接错误。
配置环境变量模板
官方镜像入口会处理 /etc/nginx/templates/*.template,把变量替换后的文件写入 /etc/nginx/conf.d。需要在不同环境切换端口等非敏感值时,可以挂载模板目录;上游地址仍要满足同一 Docker 网络中的名称解析条件:
server {
listen ${NGINX_PORT};
server_name _;
root /usr/share/nginx/html;
location / {
try_files $uri $uri/ =404;
}
}保存为 templates/default.conf.template。这个模板只依赖挂载的静态目录,因此可以独立验证;需要把 /api/ 转给上游时,沿用前一节的 proxy_pass 配置,并把 NGINX 和应用放进同一个 Docker 网络。
docker run -d \
--name nginx-template \
-p 127.0.0.1:18080:80 \
-v "$PWD/site:/usr/share/nginx/html:ro" \
-v "$PWD/templates:/etc/nginx/templates:ro" \
-e NGINX_PORT=80 \
nginx:1.31.6
docker exec nginx-template nginx -t
curl --fail http://127.0.0.1:18080/成功信号是 nginx -t 报告语法检查通过且首页可访问。模板替换适合非敏感的地址和端口。不要把证书私钥、数据库密码或访问令牌放进环境变量模板;容器环境变量可被有 Docker 管理权限的用户读取,敏感值应交给专用 secret 机制或受限的只读挂载。
日常维护、升级和清理
日志和状态
docker ps --filter name=nginx-lab
docker logs --since=10m nginx-lab
docker inspect --format '{{.State.Status}} {{.Config.Image}}' nginx-lab官方镜像将访问和错误日志导向容器标准输出,通常直接用 docker logs 收集;如果自定义 access_log 或 error_log 到文件,必须另外挂载目录并制定轮转策略。日志能说明 NGINX 是否收到请求,不能替代上游应用的业务指标。
固定版本升级和回退
升级前先检查 NGINX CHANGES 与目标镜像的 Dockerfile,记录当前镜像 tag 或 digest,并在测试环境执行 nginx -t、静态页面和上游接口验收。把 NEW_IMAGE 替换成目标 tag 或 digest;下面的切换会短暂停止旧容器,并保留旧容器名用于失败回退:
set -euo pipefail
OLD_IMAGE=nginx:1.31.6
NEW_IMAGE="${NEW_IMAGE:-nginx:1.31.6}"
test "$NEW_IMAGE" != "$OLD_IMAGE" || { echo 'set NEW_IMAGE to a newer approved tag or digest'; exit 1; }
docker pull "$NEW_IMAGE"
docker inspect --format '{{.Config.Image}}' nginx-lab
docker stop nginx-lab
docker rename nginx-lab nginx-lab-old
docker run -d \
--name nginx-lab \
--restart unless-stopped \
-p 127.0.0.1:8080:80 \
-v "$PWD/site:/usr/share/nginx/html:ro" \
-v "$PWD/conf.d:/etc/nginx/conf.d:ro" \
"$NEW_IMAGE"
docker exec nginx-lab nginx -t
curl --fail http://127.0.0.1:8080/healthz
docker rm nginx-lab-old如果新容器的 nginx -t 或 HTTP 验收失败,先删除新容器,再执行 docker rename nginx-lab-old nginx-lab && docker start nginx-lab,恢复旧容器。验收通过后再删除 nginx-lab-old;这组命令不会删除宿主机的 site/ 和 conf.d/。NGINX 的静态内容和配置位于绑定目录,删除容器不会备份这些目录。
备份和恢复绑定目录
site/ 保存页面和静态资源,conf.d/ 保存路由配置;两者是本路径的恢复单元。先停掉容器或至少停止写入,再把目录打包到受限的备份位置:
mkdir -p backups
tar -C "$PWD" -czf "backups/nginx-lab-$(date +%Y%m%d-%H%M%S).tgz" site conf.d恢复前确认压缩包来源和目标工作目录。下面的命令会解压并覆盖同名文件,随后用配置检查和 HTTP 请求验收;备份中不存在的新增文件需要按业务判断是否清理:
docker stop nginx-lab
tar -xzf backups/nginx-lab-YYYYMMDD-HHMMSS.tgz -C "$PWD"
docker start nginx-lab
docker exec nginx-lab nginx -t
curl --fail http://127.0.0.1:8080/healthz
curl --fail http://127.0.0.1:8080/将 YYYYMMDD-HHMMSS 替换为实际备份文件名。备份不包含镜像层、Docker 网络或上游应用数据;恢复这些目录后仍需拉取目标镜像并确认上游服务可访问。
停止与卸载
docker stop nginx-lab
docker rm nginx-lab这只删除容器,不删除 nginx-lab/site、nginx-lab/conf.d 或已经拉取的镜像。确认不再需要站点内容后,再由操作者单独删除工作目录;不要把 docker rm 描述为数据备份或恢复操作。
常见问题
容器启动后马上退出。 先执行 docker logs nginx-lab,再运行 docker run --rm -v "$PWD/conf.d:/etc/nginx/conf.d:ro" nginx:1.31.6 nginx -t 检查挂载配置。常见原因是少了分号、server 或 location 花括号不匹配,或者上游主机名无法解析。
页面返回 403 或 404。 检查宿主机 site/index.html 是否存在,以及 root 是否仍指向 /usr/share/nginx/html。挂载整个 site 目录后,容器内原有默认欢迎页会被遮住;这是预期行为。
改完配置没有变化。 先执行 docker exec nginx-lab nginx -t,再执行 docker exec nginx-lab nginx -s reload。如果修改的是挂载目录之外的文件,容器不会自动看到;如果容器被重建,确认新的 docker run 仍挂载了同一目录。
反向代理出现 host not found in upstream。 proxy_pass 中的名称必须是同一 Docker 网络里的服务名或可解析 DNS 名。容器内的 localhost 只代表 NGINX 自己;后端在宿主机时要使用平台提供的宿主机地址映射,或把两个服务加入同一网络。
是否可以直接公开 8080 端口? 这篇示例绑定到 127.0.0.1,适合本机验证。公开服务应改为明确的防火墙策略,在 TLS 终止点配置证书、限制管理接口,并检查 Host、转发头和上游访问控制;不能把 HTTP 健康探针当成认证。
部署验证
本指南只完成了静态来源核对和命令级验收设计,没有在当前环境启动 NGINX 容器。实际部署时应依次观察容器保持 Up、docker exec nginx-lab nginx -t 输出 syntax is ok 与 test is successful、/healthz 返回 ok、首页包含示例文本,并在反向代理场景确认上游响应和 NGINX 日志。配置重载、升级和恢复都要重复这组检查;这些结果不能由文档阅读代替。
总结
NGINX 的 Docker 主路径适合把站点内容和 conf.d 配置放在宿主机,用固定镜像启动容器,再通过 nginx -t 和优雅 reload 控制变更。公开服务还需要 TLS、访问控制、日志轮转和可回退的镜像版本;绑定目录是站点与配置的恢复单元,不能把删除容器当成备份。
参考资料
- NGINX 官方 Beginner's Guide:配置上下文、静态文件和信号控制。
- NGINX 文档目录:按模块查找指令和默认行为。
- NGINX Docker Official Image:镜像 tag、架构、模板入口和变体说明。
- nginx/docker-nginx:官方镜像 Dockerfile、构建和维护说明。
- nginx/nginx README:源码仓库的安装、构建和模块入口。