用 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 OKServer: 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 execdocker 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 的全流程走完了。几条实操经验送给你:

  1. 配置文件要纳入版本控制:把 /data/nginx/ 目录用 Git 管起来,每次改配置提交一个 commit,出问题一键回滚,这是 Docker 部署最大的优势之一,别浪费了
  2. 精确锁定镜像版本:生产环境永远不要用 latest,用 nginx:1.26.2-alpine 这种精确到小版本的写法,防止某天镜像更新带进来 Breaking Change
  3. 日志目录单独挂载/var/log/nginx 必须挂载到宿主机,容器删了重建,日志不能丢
  4. 改配置先 `-t` 再 `reload`docker exec nginx nginx -t 是救命命令,语法有错提前发现,不要冒险直接 restart
  5. 定期清理旧镜像docker image prune -f 定期跑一下,防止旧镜像把磁盘悄悄吃满

更多《软件安装&避坑&实践》系列,公众号有图文详解

关注公众号:IT安装手册
博客:https://itinstall.dev

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐