Nginx Docker 容器 403 错误排查与解决方案

4 阅读3分钟

Nginx Docker 容器 403 错误排查与解决方案

问题描述

在飞牛 NAS 上使用 Docker 部署 Nginx 静态网站时,访问 http://IP:8080 出现 403 Forbidden 错误。

环境信息

  • NAS 系统:飞牛 NAS
  • 容器镜像:nginx:alpine
  • 端口映射:8080:80
  • 目录结构
/vol1/1001/workspace/subcatcher/
├── dist/
│   ├── index.html
│   └── assets/
├── docker-compose.yml
└── nginx.conf

问题排查过程

1. 查看容器日志

# 查看 Nginx 错误日志
sudo docker exec subcatcher-aesthetic cat /var/log/nginx/error.log

关键错误信息

[error] 22#22: *1 open() "/usr/share/nginx/html/index.html" failed (13: Permission denied)

2. 检查容器内文件权限

sudo docker exec subcatcher-aesthetic ls -la /usr/share/nginx/html/

发现问题

-rw-rwx---  1 1001  root  1385 Jan 23 11:57 index.html
drwxrwx---  1 1001  root    70 Jan 23 11:58 assets
  • 文件所有者是 1001:root
  • 文件权限是 670(只有所有者和组有读写权限)
  • Nginx worker 进程无法读取文件

根本原因

文件权限不足:宿主机上 dist 目录的文件权限不正确,导致容器内 Nginx 进程(即使以 root 运行)无法读取挂载的文件。


解决方案

✅ 方案一:修复文件权限(推荐)

这是最直接、最彻底的解决方法。

# 1. 修改文件权限为 755(所有用户可读可执行)
sudo chmod -R 755 /vol1/1001/workspace/subcatcher/dist

# 2. 重启容器使权限生效
sudo docker restart subcatcher-aesthetic

# 3. 验证是否解决
sudo docker logs subcatcher-aesthetic --tail 20

权限说明

  • 755 = rwxr-xr-x
  • 所有者:读写执行
  • 组用户:读执行
  • 其他用户:读执行

方案二:修改容器运行用户

如果不想改变文件权限,可以让容器以文件所有者身份运行。

修改 docker-compose.yml

services:
  subcatcher:
    image: nginx:alpine
    container_name: subcatcher-aesthetic
    user: "1001:1001"  # 匹配文件所有者 UID:GID
    restart: always
    ports:
      - "8080:80"
    volumes:
      - ./dist:/usr/share/nginx/html:ro
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    environment:
      - TZ=Asia/Shanghai
    networks:
      - subcatcher-net

重启:

sudo docker-compose down
sudo docker-compose up -d

方案三:去掉只读挂载

将卷挂载从只读改为读写(不推荐用于生产环境)。

volumes:
  - ./dist:/usr/share/nginx/html  # 去掉 :ro
  - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro

常用排查命令

Docker 权限问题

# 如果遇到 "permission denied while trying to connect to docker API"
sudo docker <command>

# 或将用户添加到 docker 组
sudo usermod -aG docker $USER
newgrp docker

查看容器日志

# 查看完整日志
sudo docker logs subcatcher-aesthetic

# 只看最后 20 行
sudo docker logs subcatcher-aesthetic --tail 20

# 实时查看日志
sudo docker logs -f subcatcher-aesthetic

进入容器调试

# 进入容器 Shell
sudo docker exec -it subcatcher-aesthetic sh

# 在容器内检查文件
ls -la /usr/share/nginx/html/
cat /usr/share/nginx/html/index.html

# 查看 Nginx 配置是否正确
nginx -t

# 查看错误日志
cat /var/log/nginx/error.log

检查宿主机权限

# 查看目录权限
ls -la /vol1/1001/workspace/subcatcher/
ls -la /vol1/1001/workspace/subcatcher/dist/

# 修复权限
sudo chmod -R 755 /vol1/1001/workspace/subcatcher/dist/
sudo chown -R root:root /vol1/1001/workspace/subcatcher/dist/

预防措施

1. 构建镜像时设置正确权限

如果使用自定义 Dockerfile:

FROM nginx:alpine

COPY --chown=nginx:nginx dist/ /usr/share/nginx/html/
RUN chmod -R 755 /usr/share/nginx/html/

EXPOSE 80

2. 部署前检查清单

# ✓ 检查文件是否存在
ls -la ./dist/index.html

# ✓ 检查文件权限(应为 644 或 755)
stat -c "%a %n" ./dist/index.html

# ✓ 测试 Nginx 配置语法
sudo docker exec subcatcher-aesthetic nginx -t

# ✓ 查看容器是否正常运行
sudo docker ps | grep subcatcher

3. 标准化部署流程

#!/bin/bash
# deploy.sh - 标准化部署脚本

# 1. 确保权限正确
chmod -R 755 ./dist/

# 2. 停止旧容器
docker-compose down

# 3. 启动新容器
docker-compose up -d

# 4. 检查运行状态
docker-compose ps
docker-compose logs --tail 20

# 5. 测试访问
curl -I http://localhost:8080

完整配置文件参考

docker-compose.yml

services:
  subcatcher:
    image: nginx:alpine
    container_name: subcatcher-aesthetic
    user: root  # 或使用具体 UID,如 "1001:1001"
    restart: always
    ports:
      - "8080:80"
    volumes:
      - ./dist:/usr/share/nginx/html:ro
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    environment:
      - TZ=Asia/Shanghai
    networks:
      - subcatcher-net

networks:
  subcatcher-net:
    driver: bridge

nginx.conf

server {
    listen 80;
    server_name localhost;

    root /usr/share/nginx/html;
    index index.html;

    # Gzip 压缩
    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml+rss text/javascript;
    gzip_vary on;

    # SPA 路由支持
    location / {
        try_files $uri $uri/ /index.html;
        add_header Cache-Control "no-cache";
    }

    # 静态资源缓存
    location ~* .(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    # 错误页面
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }

    # 安全响应头
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";
}

总结

Nginx 403 错误的核心原因:文件权限问题

最佳解决方案

  1. 使用 chmod -R 755 确保文件可读
  2. 重启容器使挂载生效
  3. 建立标准化部署流程避免重复问题

关键命令

sudo chmod -R 755 /path/to/dist
sudo docker restart container-name
sudo docker logs container-name

参考资料