Nginx安装系列|Docker安装篇:容器化部署一步到位,环境隔离升级回滚都不怕
本文详细介绍了使用Docker部署Nginx的完整流程。从准备工作到镜像拉取、容器运行、生产级配置,再到升级和卸载,每个步骤都配有详细命令和预期输出。重点讲解了目录规划、配置挂载、日志持久化等关键实践,并提供了常见问题解决方案。文章特别推荐使用Alpine版本的Nginx镜像,以及精确锁定版本号等最佳实践,确保生产环境稳定运行。
用 Docker 跑 Nginx,是现在很多团队的标配选择。环境隔离、版本切换、配置可版本化、迁移零成本——这些好处在你第一次用容器部署完 Nginx 之后就会深刻体会到。本文从零开始,每一步命令都有注释和期待返回,第一次接触 Docker 的同学也能顺利跟下来。
一、动手前的准备工作
磨刀不误砍柴工。用 Docker 安装 Nginx,前提是 Docker 本身得先跑起来。这一章把环境摸清楚,避免后面踩坑。
1.1 支持的操作系统
Docker 对系统的要求比编译安装宽松很多,以下系统均支持,本文全覆盖:
| 发行版系列 | 具体系统版本 | 内核要求 |
|---|---|---|
| Debian 系 | Ubuntu 20.04 / 22.04 / 24.04 | ≥ 3.10 |
| Debian 系 | Debian 10 / 11 / 12 | ≥ 3.10 |
| Red Hat 系 | CentOS 7 / 8 Stream | ≥ 3.10 |
| Red Hat 系 | Rocky Linux 8 / 9、AlmaLinux 8 / 9 | ≥ 3.10 |
| Red Hat 系 | RHEL 8 / 9 | ≥ 3.10 |
云服务器绝大多数都满足内核要求,只要不是五六年前的老镜像,基本不用担心这个。
1.2 最低配置要求
| 资源项 | 最低要求 | 推荐配置(生产环境) |
|---|---|---|
| CPU | 1 核 | 2 核以上 |
| 内存 | 512 MB(Docker daemon 自身约占 100MB) | 2 GB 以上 |
| 磁盘空间 | 5 GB(Docker 镜像 + 容器 + 日志) | 20 GB 以上 |
| 网络 | 能访问公网(拉取镜像) | 稳定网络,或搭建内网镜像仓库 |
| 权限 | root 或 sudo 权限,或加入 docker 用户组 | root |
1.3 查看当前系统信息
# 查看操作系统版本
cat /etc/os-release
期待返回(Ubuntu 22.04 示例):
NAME="Ubuntu"
VERSION="22.04.3 LTS (Jammy Jellyfish)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 22.04.3 LTS"
VERSION_ID="22.04"
# 查看内核版本,确认满足 Docker 的最低内核要求(≥ 3.10)
uname -r
期待返回:
5.15.0-91-generic
# 查看系统架构
uname -m
期待返回:
x86_64
x86_64是 64 位 Intel/AMD 架构,aarch64是 ARM 架构(比如部分云服务器的 ARM 型号)。Docker 官方镜像两种架构都支持,不用担心。
# 查看可用内存和磁盘空间
free -h && df -h /
期待返回:
total used free shared buff/cache available
Mem: 3.8Gi 512Mi 2.8Gi 12Mi 512Mi 3.1Gi
Swap: 2.0Gi 0B 2.0Gi
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 40G 8.5G 30G 23% /
1.4 检查 Docker 是否已安装
# 检查 docker 命令是否存在,同时查看版本号
docker --version
已安装时返回:
Docker version 26.1.4, build 5650f9b
未安装时返回:
bash: docker: command not found
# 如果 Docker 已安装,检查 daemon 是否在运行
sudo systemctl status docker
正常运行时返回(节选):
● docker.service - Docker Application Container Engine
Active: active (running) since Wed 2026-04-01 09:00:00 CST; 1h ago
如果 Docker 已安装且正常运行,可以直接跳到第三章,省略安装 Docker 的步骤。
# 检查 80 和 443 端口是否被占用(容器映射端口时会用到)
ss -tlnp | grep -E ':80|:443'
端口空闲时:无任何输出(正常)
端口被占用时返回:
LISTEN 0 128 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1234,fd=6))
如果宿主机 80/443 端口已被占用,后面做端口映射时需要换其他端口,或者先停掉占用的服务。
二、安装 Docker
如果你的机器还没有 Docker,参考下面docker安装教程。已有 Docker 的直接跳到第三章。
史上最全 Linux 系统 Docker 安装保姆级教程(三种安装方式/centos/Ubuntu全适配)
三、拉取 Nginx 镜像
Docker 环境准备好之后,接下来拉取 Nginx 官方镜像。
3.1 了解 Nginx 镜像的版本标签
官方镜像在 Docker Hub 上有很多 tag,搞清楚选哪个很重要:
| 镜像 Tag | 说明 | 推荐场景 |
|---|---|---|
nginx:latest |
最新稳定版(跟随官方 stable 分支) | 开发测试 |
nginx:1.26 |
1.26 大版本的最新小版本 | 生产推荐,版本可控 |
nginx:1.26.2 |
精确锁定到某个小版本 | 生产强烈推荐,版本完全固定 |
nginx:stable |
官方标注的当前稳定版 | 生产推荐 |
nginx:alpine |
基于 Alpine Linux 的精简版 | 镜像体积极小(约 40MB),推荐 |
nginx:1.26-alpine |
1.26 版本的 Alpine 精简版 | 生产最优选,体积小+版本固定 |
nginx:mainline |
主线版(包含最新特性) | 需要新特性时使用 |
生产环境首选 nginx:1.26-alpine,理由:
- Alpine 版本体积只有约 40MB,标准版约 180MB,拉取更快,存储占用更小
- 攻击面更小(Alpine 系统极简,预装软件少)
- 版本号精确,不会因为
latest自动升级引入意外变更
3.2 搜索可用版本
# 在 Docker Hub 搜索 nginx 镜像(显示前 10 个结果)
docker search nginx --limit 10
期待返回:
NAME DESCRIPTION STARS OFFICIAL
nginx Official build of Nginx. 19876 [OK]
unit Official build of NGINX Unit: Universal Web … 70 [OK]
nginx/nginx-ingress NGINX and NGINX Plus Ingress Controllers fo… 92
nginxinc/nginx-unprivileged Unprivileged NGINX Dockerfiles 137
...
看到
[OK]标识的nginx就是官方镜像,放心用。
3.3 拉取镜像
# 拉取指定版本的 Nginx 镜像(推荐 alpine 版本)
# docker pull:从镜像仓库下载镜像到本地
# nginx:1.26-alpine:镜像名:标签,不写标签默认是 latest
docker pull nginx:1.26-alpine
期待返回:
1.26-alpine: Pulling from library/nginx
c926b61bad3b: Pull complete
4b5cacb9d7e4: Pull complete
1e7f2e3b5f2a: Pull complete
e7ac574a7f1c: Pull complete
Digest: sha256:a5127daff3d6f4606be3100a252419bfa84fd6ee5cd74d0feaca1a5068f97dcf
Status: Downloaded newer image for nginx:1.26-alpine
docker.io/library/nginx:1.26-alpine
每一行
Pull complete代表一个镜像层下载完成。Nginx alpine 镜像层少、体积小,通常几十秒就能下好。
# 查看本地已有的镜像
# 确认镜像已成功拉取到本地
docker images | grep nginx
期待返回:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.26-alpine a3c4b89a3a2f 2 weeks ago 41.4MB
SIZE列显示约 41MB,这就是 Alpine 版本的优势,标准版同等版本约 180MB。
四、运行 Nginx 容器
镜像有了,接下来把它跑起来。本章从最简单的单行命令开始,一步步讲到生产级的完整配置。
4.1 快速启动(验证镜像能跑)
# 最简单的启动命令,先验证镜像可以正常运行
# docker run:创建并启动一个容器
# -d:后台运行(detached 模式),不加这个会占用当前终端
# -p 80:80:端口映射,格式是"宿主机端口:容器内端口",把容器 80 映射到宿主机 80
# --name nginx-test:给容器起个名字,方便后续管理
# nginx:1.26-alpine:使用的镜像
docker run -d -p 80:80 --name nginx-test nginx:1.26-alpine
期待返回(容器 ID):
a3f8c2d1e4b57890123456789abcdef0123456789abcdef0123456789abcdef01
返回一长串十六进制字符串就是容器 ID,说明容器已成功创建并在后台运行。
# 验证容器正在运行
# docker ps:列出所有正在运行的容器(加 -a 显示包含已停止的所有容器)
docker ps
期待返回:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a3f8c2d1e4b5 nginx:1.26-alpine "/docker-entrypoint.…" 5 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx-test
关键看
STATUS列,显示Up就是正在运行。PORTS列的0.0.0.0:80->80/tcp说明端口映射生效了。
# 用 curl 验证 Nginx 正在响应请求
curl -I http://localhost
期待返回:
HTTP/1.1 200 OK
Server: nginx/1.26.2
Date: Wed, 01 Apr 2026 02:10:00 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 14 Jun 2022 01:01:09 GMT
Connection: keep-alive
ETag: "62a797ad-267"
Accept-Ranges: bytes
200 OK且Server: nginx/1.26.2,验证通过!
# 先把测试容器删掉,后面用正式配置重新创建
# docker stop:优雅停止容器(发 SIGTERM,等待进程退出)
# docker rm:删除已停止的容器
docker stop nginx-test && docker rm nginx-test
期待返回:
nginx-test
nginx-test
4.2 生产级启动配置
快速验证通过后,接下来搭建规范的目录结构,做好配置挂载、日志持久化等关键设置。
Step 1:规划目录结构
# 在宿主机上创建统一的 Nginx 工作目录
# 把配置文件、网站文件、日志都放在固定位置,方便管理和备份
# 主工作目录
sudo mkdir -p /data/nginx
# 配置目录:存放 nginx.conf 和各站点配置
sudo mkdir -p /data/nginx/conf/conf.d
# 网站根目录:存放你的 HTML、CSS、JS 等静态文件
sudo mkdir -p /data/nginx/html
# 日志目录:access.log 和 error.log 持久化到这里
sudo mkdir -p /data/nginx/logs
# SSL 证书目录:HTTPS 证书文件放这里
sudo mkdir -p /data/nginx/ssl
# 查看目录结构
tree /data/nginx
期待返回:
/data/nginx
├── conf
│ └── conf.d
├── html
├── logs
└── ssl
5 directories, 0 files
如果没有
tree命令,用find /data/nginx -type d代替查看。
Step 2:从容器里复制默认配置文件出来
# 先临时启动一个容器,把里面的默认配置文件复制到宿主机
# 这样我们能在官方默认配置基础上修改,不用从头写
docker run --rm -d --name nginx-temp nginx:1.26-alpine
# docker cp:在容器和宿主机之间复制文件
# nginx-temp:/etc/nginx/nginx.conf:容器内的主配置文件路径
# /data/nginx/conf/nginx.conf:复制到宿主机的目标路径
docker cp nginx-temp:/etc/nginx/nginx.conf /data/nginx/conf/nginx.conf
# 同样复制 mime.types(MIME 类型映射文件,nginx.conf 里会 include 它)
docker cp nginx-temp:/etc/nginx/mime.types /data/nginx/conf/mime.types
# 复制默认的欢迎页 HTML
docker cp nginx-temp:/usr/share/nginx/html/index.html /data/nginx/html/index.html
docker cp nginx-temp:/usr/share/nginx/html/50x.html /data/nginx/html/50x.html
# 把临时容器停掉删掉
docker stop nginx-temp
期待返回:
nginx-temp
# 确认文件已经复制出来
ls -la /data/nginx/conf/ && ls -la /data/nginx/html/
期待返回:
/data/nginx/conf/:
total 24
drwxr-xr-x 3 root root 4096 Apr 1 10:15 .
drwxr-xr-x 6 root root 4096 Apr 1 10:15 ..
drwxr-xr-x 2 root root 4096 Apr 1 10:15 conf.d
-rw-r--r-- 1 root root 1077 Apr 1 10:15 mime.types
-rw-r--r-- 1 root root 648 Apr 1 10:15 nginx.conf
/data/nginx/html/:
total 16
drwxr-xr-x 2 root root 4096 Apr 1 10:15 .
drwxr-xr-x 6 root root 4096 Apr 1 10:15 ..
-rw-r--r-- 1 root root 615 Apr 1 10:15 index.html
-rw-r--r-- 1 root root 494 Apr 1 10:15 50x.html
Step 3:修改主配置文件
# 编辑主配置文件,做一些规范化调整
sudo tee /data/nginx/conf/nginx.conf << 'EOF'
user nginx;
# worker_processes auto:自动根据 CPU 核心数设置 worker 进程数
# 生产环境设置 auto 即可,Docker 环境会感知容器的 CPU 配额
worker_processes auto;
# 错误日志路径和级别
# 级别从低到高:debug < info < notice < warn < error < crit < alert < emerg
# 生产环境推荐 warn,开发/排查问题时可临时改成 info 或 debug
error_log /var/log/nginx/error.log warn;
# PID 文件路径
pid /var/run/nginx.pid;
events {
# 每个 worker 进程的最大并发连接数
# 通常设置为 ulimit -n 的值(系统最大文件描述符数)
worker_connections 1024;
# epoll:Linux 下最高效的 I/O 多路复用模型,生产必开
use epoll;
# multi_accept on:允许 worker 一次性接受多个新连接
multi_accept on;
}
http {
# 引入 MIME 类型映射表,让浏览器正确识别文件类型
include /etc/nginx/mime.types;
# 找不到匹配 MIME 类型时的默认类型
default_type application/octet-stream;
# 日志格式定义(main 是名称,后面 access_log 会引用这个名字)
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 访问日志路径,使用上面定义的 main 格式
access_log /var/log/nginx/access.log main;
# sendfile on:让内核直接在文件描述符间传输数据,避免数据在内核/用户空间来回拷贝
# 静态文件服务性能提升明显
sendfile on;
# tcp_nopush:和 sendfile 配合使用,批量发送 HTTP 响应头
tcp_nopush on;
# tcp_nodelay:禁用 Nagle 算法,减少小数据包的延迟
tcp_nodelay on;
# keepalive_timeout:HTTP 长连接超时时间(秒)
keepalive_timeout 65;
# gzip 压缩,减少传输数据量,提升页面加载速度
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json
application/javascript application/rss+xml
application/atom+xml image/svg+xml;
# 隐藏 Nginx 版本号,减少信息泄露
server_tokens off;
# 引入 conf.d 目录下所有 .conf 文件(每个站点单独一个文件)
include /etc/nginx/conf.d/*.conf;
}
EOF
Step 4:创建默认站点配置
# 在 conf.d 目录下创建默认站点配置文件
sudo tee /data/nginx/conf/conf.d/default.conf << 'EOF'
server {
# 监听 80 端口,接受所有 IPv4 请求
listen 80;
# 同时监听 IPv6
listen [::]:80;
# server_name:匹配请求的域名
# _ 是通配符,表示匹配所有域名(兜底规则)
server_name _;
# 网站根目录(容器内路径)
root /usr/share/nginx/html;
# 默认首页文件
index index.html index.htm;
# 访问日志(容器内路径,会被挂载到宿主机 /data/nginx/logs/)
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
# 处理所有 URI 请求
location / {
# 依次尝试:找对应文件 → 找对应目录 → 返回 404
try_files $uri $uri/ =404;
}
# 自定义错误页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# 状态监控接口(内网访问用,生产环境限制访问 IP)
location /nginx_status {
stub_status on;
# 只允许本机访问,防止信息泄露
allow 127.0.0.1;
allow 172.0.0.0/8; # Docker 默认网段
deny all;
}
}
EOF
Step 5:正式启动 Nginx 容器
# 使用完整的生产级参数启动容器
docker run -d \
--name nginx \
--restart always \
-p 80:80 \
-p 443:443 \
-v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /data/nginx/conf/conf.d:/etc/nginx/conf.d:ro \
-v /data/nginx/conf/mime.types:/etc/nginx/mime.types:ro \
-v /data/nginx/html:/usr/share/nginx/html:ro \
-v /data/nginx/logs:/var/log/nginx \
-v /data/nginx/ssl:/etc/nginx/ssl:ro \
nginx:1.26-alpine
参数逐行说明:
| 参数 | 说明 |
|---|---|
-d |
后台运行,不占用终端 |
--name nginx |
给容器命名为 nginx,方便后续 docker exec、docker logs 等操作 |
--restart always |
容器退出时自动重启;宿主机重启后也会自动拉起容器 |
-p 80:80 |
宿主机 80 端口 → 容器 80 端口(HTTP) |
-p 443:443 |
宿主机 443 端口 → 容器 443 端口(HTTPS) |
-v .../nginx.conf:/etc/nginx/nginx.conf:ro |
挂载主配置文件,:ro 表示容器内只读(防止容器内误修改) |
-v .../conf.d:/etc/nginx/conf.d:ro |
挂载站点配置目录,只读 |
-v .../html:/usr/share/nginx/html:ro |
挂载网站文件目录,只读 |
-v .../logs:/var/log/nginx |
挂载日志目录(可写,日志需要持久化),不加 :ro |
-v .../ssl:/etc/nginx/ssl:ro |
挂载 SSL 证书目录,只读 |
期待返回(容器 ID):
7f3a1b2c4d5e6f7890abcdef1234567890abcdef1234567890abcdef12345678
# 确认容器正常运行
docker ps
期待返回:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7f3a1b2c4d5e nginx:1.26-alpine "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp nginx
五、安装完成后的验证与基础配置
5.1 验证 Nginx 正常响应
# 本地 curl 测试
curl -I http://localhost
期待返回:
HTTP/1.1 200 OK
Server: nginx/1.26.2
Date: Wed, 01 Apr 2026 02:20:00 GMT
Content-Type: text/html
Content-Length: 615
Connection: keep-alive
ETag: "62a797ad-267"
注意:因为我们在主配置里设置了
server_tokens off,实际上Server头只会显示nginx,不带版本号——这是安全最佳实践。上面的示例是为了说明验证成功。
# 查看容器内 Nginx 的实际版本
docker exec nginx nginx -v
期待返回:
nginx version: nginx/1.26.2
5.2 查看容器日志
# docker logs:查看容器的标准输出/错误输出日志
# -f:持续跟踪(follow),有新日志实时显示,Ctrl+C 退出
# --tail 50:只显示最后 50 行
docker logs -f --tail 50 nginx
期待返回(正常启动日志):
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
# 查看持久化到宿主机的日志文件
# 访问日志:记录每一个 HTTP 请求
sudo tail -f /data/nginx/logs/access.log
# 错误日志:记录所有 warn 级别及以上的事件(启动失败、配置错误等)
sudo tail -f /data/nginx/logs/error.log
5.3 进入容器内部排查问题
# docker exec:在运行中的容器内执行命令
# -it:-i 保持标准输入打开,-t 分配一个伪终端(两个合用就是交互式 shell)
# nginx:容器名
# sh:Alpine 镜像没有 bash,用 sh(标准版镜像可以用 bash)
docker exec -it nginx sh
进入容器后的提示符:
/ #
# 在容器内可以执行任何 nginx 相关命令
nginx -v # 查看版本
nginx -t # 检查配置语法
cat /etc/nginx/nginx.conf # 查看配置文件(这里看到的是挂载进来的)
ls /var/log/nginx/ # 查看日志文件
exit # 退出容器,回到宿主机
5.4 检查并放行防火墙
# CentOS/RHEL:放行 80 和 443 端口
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload
# Ubuntu:放行端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
5.5 常用 Docker 管理命令速查
# 查看所有运行中的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
# 启动已停止的容器
docker start nginx
# 停止容器(优雅停止)
docker stop nginx
# 强制删除容器(容器必须先停止,或加 -f 强制删除运行中的容器)
docker rm nginx
# 重启容器
docker restart nginx
# 查看容器实时日志
docker logs -f nginx
# 进入容器交互终端
docker exec -it nginx sh
# 查看容器详细信息(包含挂载、网络、环境变量等完整配置)
docker inspect nginx
# 查看容器资源占用(CPU、内存、网络 I/O)
docker stats nginx
# 查看本地所有镜像
docker images
5.6 修改配置后如何生效
Docker 部署的 Nginx,修改配置文件的流程和直接安装略有不同:
# 第一步:在宿主机修改对应的配置文件
# 比如修改默认站点配置
sudo vim /data/nginx/conf/conf.d/default.conf
# 第二步:检查配置语法(在容器内执行 nginx -t)
docker exec nginx nginx -t
期待返回(语法正确):
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# 第三步:平滑重载配置(不停容器,不中断连接)
docker exec nginx nginx -s reload
没有任何输出 = 重载成功
# 或者直接发信号重启容器(会有短暂中断,非必要别用)
docker restart nginx
经典流程:改配置 →
docker exec nginx nginx -t检查语法 →docker exec nginx nginx -s reload重载,三步走,安全稳妥。
5.7 添加新站点
# 在 conf.d 目录下新建站点配置文件
sudo tee /data/nginx/conf/conf.d/mysite.conf << 'EOF'
server {
listen 80;
server_name mysite.example.com;
root /usr/share/nginx/html/mysite;
index index.html index.htm;
access_log /var/log/nginx/mysite_access.log main;
error_log /var/log/nginx/mysite_error.log warn;
location / {
try_files $uri $uri/ =404;
}
}
EOF
# 在宿主机创建站点目录和测试页
sudo mkdir -p /data/nginx/html/mysite
sudo tee /data/nginx/html/mysite/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Docker Nginx 新站点</title></head>
<body><h1>新站点部署成功!</h1></body>
</html>
EOF
# 检查语法
docker exec nginx nginx -t
# 重载配置
docker exec nginx nginx -s reload
六、Nginx 镜像升级
Docker 升级 Nginx 版本比编译安装简单很多,整个过程几分钟搞定。
6.1 使用 docker run 方式升级
# 第一步:拉取新版本镜像
docker pull nginx:1.27-alpine
# 第二步:停止并删除旧容器(数据卷不受影响)
docker stop nginx && docker rm nginx
# 第三步:用新镜像启动容器(参数和之前完全一样,只改镜像 tag)
docker run -d \
--name nginx \
--restart always \
-p 80:80 \
-p 443:443 \
-v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /data/nginx/conf/conf.d:/etc/nginx/conf.d:ro \
-v /data/nginx/conf/mime.types:/etc/nginx/mime.types:ro \
-v /data/nginx/html:/usr/share/nginx/html:ro \
-v /data/nginx/logs:/var/log/nginx \
-v /data/nginx/ssl:/etc/nginx/ssl:ro \
nginx:1.27-alpine
# 第四步:确认新版本
docker exec nginx nginx -v
6.2 使用 Docker Compose 升级(更优雅)
# 第一步:修改 docker-compose.yml 中的镜像版本
sudo sed -i 's/nginx:1.26-alpine/nginx:1.27-alpine/' /data/nginx/docker-compose.yml
# 第二步:拉取新镜像
docker compose pull
# 第三步:重新创建容器(旧容器停止,新容器启动)
# --no-deps:只更新 nginx 服务,不影响其他服务
docker compose up -d --no-deps nginx
# 第四步:验证版本
docker exec nginx nginx -v
# 清理不再使用的旧镜像,释放磁盘空间
docker image prune -f
七、卸载 Nginx(Docker 方式)
Docker 方式卸载是最干净的——删容器、删镜像、删挂载目录,完全不留痕迹。
7.1 停止并删除容器
# 如果是 docker run 方式启动的
docker stop nginx
docker rm nginx
# 如果是 docker compose 方式启动的
cd /data/nginx
docker compose down
期待返回:
[+] Running 2/2
✔ Container nginx Removed 0.3s
✔ Network nginx_default Removed 0.1s
7.2 删除 Nginx 镜像
# 查看本地所有 nginx 相关镜像
docker images | grep nginx
期待返回:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.26-alpine a3c4b89a3a2f 2 weeks ago 41.4MB
nginx 1.27-alpine b4d5e90f3b1c 3 days ago 42.1MB
# 删除指定镜像(通过 IMAGE ID 或 REPOSITORY:TAG 指定)
docker rmi nginx:1.26-alpine
docker rmi nginx:1.27-alpine
# 或者一次性删除所有 nginx 镜像
docker images | grep nginx | awk '{print $1":"$2}' | xargs docker rmi
# 清理所有未被使用的镜像(悬空镜像 + 未使用的镜像,慎用)
docker image prune -a -f
期待返回:
Untagged: nginx:1.26-alpine
Untagged: nginx:1.26-alpine@sha256:a5127daff3d6f4606...
Deleted: sha256:a3c4b89a3a2f...
Deleted: sha256:7f8e9d1c2b3a...
7.3 删除宿主机上的挂载目录(可选)
# 如果这台机器以后不再运行 nginx,清理挂载目录
# ⚠️ 重要:这个目录里包含配置文件、日志、网站文件
# 如果有价值的内容请提前备份!
# 备份(可选,建议做)
sudo tar -czf /tmp/nginx-backup-$(date +%Y%m%d).tar.gz /data/nginx
# 确认备份完成
ls -lh /tmp/nginx-backup-*.tar.gz
# 删除挂载目录
sudo rm -rf /data/nginx
7.4 如果要连 Docker 一起卸载
# Ubuntu/Debian
sudo apt purge -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo apt autoremove -y
# 删除 Docker 数据目录(镜像、容器、网络、数据卷全部清除)
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
sudo rm -f /etc/docker/daemon.json
# CentOS/RHEL
sudo yum remove -y docker-ce docker-ce-cli containerd.io \
docker-compose-plugin
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
7.5 验证卸载干净
# 确认容器已删除
docker ps -a | grep nginx
# 期待:无任何输出
# 确认镜像已删除
docker images | grep nginx
# 期待:无任何输出
# 如果也卸载了 Docker,确认命令不再存在
docker --version
# 期待:bash: docker: command not found
八、常见问题 Q&A
Q1:`docker pull` 拉取镜像超时或失败
报错信息:
Error response from daemon: Get "https://registry-1.docker.io/v2/":
dial tcp: lookup registry-1.docker.io: no such host
或者:
error pulling image configuration: download failed after attempts=6:
dial tcp 54.210.192.21:443: i/o timeout
原因分析: 国内访问 Docker Hub 网络不稳定,DNS 解析失败或连接超时。
解决方案:
# 确认已配置国内镜像加速(参考 2.6 节)
cat /etc/docker/daemon.json
# 如果没配,现在加上
sudo tee /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors": [
"https://docker.rainbond.cc",
"https://docker.1ms.run",
"https://docker.m.daocloud.io",
"https://dockerhub.icu",
"https://docker.chenby.cn"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
# 重新拉取
docker pull nginx:1.26-alpine
Q2:容器启动失败,`docker ps` 看不到,`docker ps -a` 显示 `Exited`
排查步骤:
# 第一步:查看容器退出原因
docker logs nginx
# 常见错误信息示例:
# 配置文件挂载路径不对
# nginx: [emerg] open() "/etc/nginx/nginx.conf" failed (2: No such file or directory)
# 第二步:检查挂载路径是否存在
ls -la /data/nginx/conf/nginx.conf
ls -la /data/nginx/conf/conf.d/
# 第三步:检查配置文件语法(临时运行一个容器来测试)
docker run --rm \
-v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /data/nginx/conf/conf.d:/etc/nginx/conf.d:ro \
nginx:1.26-alpine nginx -t
nginx -t 期待返回(语法正确):
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Q3:端口映射了 80,但宿主机浏览器访问 IP 连接被拒绝
排查步骤:
# 第一步:确认容器在运行
docker ps | grep nginx
# STATUS 列必须是 Up,不是 Exited 或 Restarting
# 第二步:确认端口映射正确
docker port nginx
# 期待返回:
# 443/tcp -> 0.0.0.0:443
# 80/tcp -> 0.0.0.0:80
# 第三步:确认宿主机 80 端口有监听
ss -tlnp | grep :80
# 期待返回:
# LISTEN 0 4096 0.0.0.0:80 0.0.0.0:* users:(("docker-proxy",pid=...))
# 第四步:检查防火墙(参考 5.4 节放行端口)
sudo firewall-cmd --list-ports # CentOS
sudo ufw status # Ubuntu
Q4:修改了宿主机的配置文件,`docker exec nginx nginx -s reload` 后报错说文件不存在
报错信息:
nginx: [error] open() "/var/run/nginx.pid" failed (2: No such file or directory)
nginx: configuration file /etc/nginx/nginx.conf test failed
原因分析: nginx -s reload 需要读取 PID 文件来找到 master 进程,容器里的 /var/run/nginx.pid 路径和宿主机不同,偶尔会因为 PID 文件异常导致这个问题。
解决方案:
# 直接重启容器(会有极短暂中断,但最干净)
docker restart nginx
# 或者通过 compose
docker compose restart nginx
# 根治方案:确保配置文件里的 pid 路径正确,且容器内可写
# nginx.conf 里的 pid /var/run/nginx.pid; 不要改成宿主机路径
Q5:日志文件权限问题,`/data/nginx/logs/` 目录下的日志文件属主是 `101` 而不是 `nginx`
现象:
ls -la /data/nginx/logs/
# -rw-r--r-- 1 101 101 12345 Apr 1 10:30 access.log
原因分析: Alpine 版 Nginx 镜像内 nginx 用户的 UID 是 101,而宿主机上没有 UID 101 对应的用户名,所以显示的是数字 UID。这是完全正常的,不影响功能。
如果需要在宿主机上用 nginx 用户名访问日志:
# 方案一:在宿主机创建 UID 为 101 的 nginx 用户
sudo useradd -u 101 -s /sbin/nologin -M nginx
# 之后 ls 就能正常显示 nginx 用户名了
ls -la /data/nginx/logs/
# -rw-r--r-- 1 nginx nginx 12345 Apr 1 10:30 access.log
# 方案二:给当前用户读取日志的权限(不修改文件所有者)
sudo chmod o+r /data/nginx/logs/*.log
Q6:容器里 Nginx 进程正常,但访问返回 403 Forbidden
报错页面:
403 Forbidden
nginx/1.26.2
原因分析: 最常见的原因是网站根目录为空(没有 index.html),或者挂载的 html 目录权限有问题,容器内 nginx 用户(UID 101)无法读取文件。
解决方案:
# 检查挂载的 html 目录是否有文件
ls -la /data/nginx/html/
# 如果有文件但还是 403,检查文件权限
# 容器内 nginx 用户(UID 101)需要有读取权限
chmod -R 755 /data/nginx/html/
find /data/nginx/html/ -type f -exec chmod 644 {} \;
# 重新进行验证
curl -v http://localhost 2>&1 | head -20
Q7:如何在不停容器的情况下,查看当前生效的 Nginx 配置?
# 方法一:直接在容器内查看配置文件(挂载进去的文件和宿主机同步)
docker exec nginx cat /etc/nginx/nginx.conf
# 方法二:查看 nginx -T 的输出(-T 大写,会展开所有 include,输出完整合并后的配置)
# 非常适合排查"配置文件改了但不知道哪里生效了"的问题
docker exec nginx nginx -T
# 方法三:在容器内查看所有已加载的站点配置
docker exec nginx ls /etc/nginx/conf.d/
docker exec nginx cat /etc/nginx/conf.d/default.conf
十、小总结
至此,Docker 安装 Nginx 的全流程走完了。几条实操经验送给你:
- 配置文件要纳入版本控制:把
/data/nginx/目录用 Git 管起来,每次改配置提交一个 commit,出问题一键回滚,这是 Docker 部署最大的优势之一,别浪费了 - 精确锁定镜像版本:生产环境永远不要用
latest,用nginx:1.26.2-alpine这种精确到小版本的写法,防止某天镜像更新带进来 Breaking Change - 日志目录单独挂载:
/var/log/nginx必须挂载到宿主机,容器删了重建,日志不能丢 - 改配置先 `-t` 再 `reload`:
docker exec nginx nginx -t是救命命令,语法有错提前发现,不要冒险直接 restart - 定期清理旧镜像:
docker image prune -f定期跑一下,防止旧镜像把磁盘悄悄吃满
更多《软件安装&避坑&实践》系列,公众号有图文详解
关注公众号:IT安装手册
博客:https://itinstall.dev
更多推荐

所有评论(0)