You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

配置Nginx反向代理后Apache HTTPD访问异常,求解决方案

问题描述

我正尝试为Docker化应用添加Nginx,以下是我的docker-compose.yml文件:

version: "3"
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    # ports:
    #   - 3001:3001
    volumes:
      - ./shared:/app/shared
    depends_on:
      - db
    restart: always
    environment:
      - MONGO_URL=mongodb://db:27017/db_name
      - PORT=3001
      - FE_ADDRESS=http://192.168.1.152:3000
      - SHARE=/app/shared

  db:
    image: mongo
    restart: always
    volumes:
      - ./data:/data/db

  shared:
    image: httpd:2.4
    ports:
      - 2020:80
    volumes:
      - ./shared:/usr/local/apache2/htdocs/
    restart: always

  nginx:
    depends_on:
      - app
      - shared
    restart: always
    build:
      dockerfile: Dockerfile
      context: ./nginx
    ports:
      - 3050:90

我保留了shared服务的端口映射,确认该服务可通过localhost:2020正常访问。以下是我的Nginx配置文件:

upstream app {
    server app:3001;
}

upstream shared {
    server shared:80;
}

server {
    listen 90;

    location / {
        proxy_pass http://app;
    }

    location /shared {
        proxy_pass http://shared;
    }
}

我将app和shared配置为上游块,以便在指定路径部署。目前app服务正常,访问localhost:3050/可查看Node.js应用,但访问localhost:3050/shared时会自动重定向到localhost:90/shared,且无法显示内容。

更新:进入Nginx容器执行curl http://shared,得到如下结果,说明容器内部可正常访问shared服务:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
 <head>
  <title>Index of /</title>
 </head>
 <body>
<h1>Index of /</h1>
<ul><li><a href=".gitkeep"> .gitkeep</a></li>
<li><a href="answers/"> answers/</a></li>
<li><a href="avatars/"> avatars/</a></li>
<li><a href="cases/"> cases/</a></li>
<li><a href="comments/"> comments/</a></li>
</ul>
</body></html>
解决方案

问题原因

访问localhost:3050/shared时,Apache(shared服务)会返回重定向响应——因为当访问路径不带末尾斜杠时,Apache默认会重定向到带斜杠的路径,并且重定向的目标端口会使用Apache自身监听的80端口,但Nginx代理时没有修改这个响应头,导致浏览器收到的重定向地址是localhost:90/shared/,而这个端口在外部是未暴露的,所以无法访问。

另外,当前Nginx的proxy_pass配置在处理/shared路径时,会把完整路径传递给Apache,即Apache收到的请求是/shared,但它的根目录是/usr/local/apache2/htdocs/,这个路径下并没有shared目录,所以即使解决了重定向,也会出现404。


方案一:修改Nginx配置解决重定向与路径问题

调整Nginx的location /shared配置,解决路径传递和重定向头修改的问题:

upstream app {
    server app:3001;
}

upstream shared {
    server shared:80;
}

server {
    listen 90;

    location / {
        proxy_pass http://app;
        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;
    }

    location /shared/ {
        proxy_pass http://shared/; # 末尾加斜杠,将路径转为/而非/shared
        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_redirect http://$host:80/ /shared/; # 修改Apache返回的重定向地址
    }

    # 处理不带末尾斜杠的请求,自动跳转带斜杠的路径
    location = /shared {
        return 302 /shared/;
    }
}

配置说明:

  • location /shared/末尾加斜杠,确保Nginx将请求路径的/shared/xxx转为/xxx传递给Apache,匹配Apache的根目录结构
  • proxy_redirect指令将Apache返回的http://xxx:80/开头的重定向地址替换为/shared/,避免端口错误
  • location = /shared处理不带斜杠的请求,主动跳转带斜杠的路径,减少Apache的重定向操作

方案二:直接用Nginx提供静态文件服务(更简单)

既然shared目录已经通过挂载卷被app服务访问,完全可以去掉Apache服务,让Nginx直接提供静态文件服务,减少服务依赖:

  1. 修改docker-compose.yml,删除shared服务,并给nginx服务添加目录挂载:
version: "3"
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./shared:/app/shared
    depends_on:
      - db
    restart: always
    environment:
      - MONGO_URL=mongodb://db:27017/db_name
      - PORT=3001
      - FE_ADDRESS=http://192.168.1.152:3000
      - SHARE=/app/shared

  db:
    image: mongo
    restart: always
    volumes:
      - ./data:/data/db

  nginx:
    depends_on:
      - app
    restart: always
    build:
      dockerfile: Dockerfile
      context: ./nginx
    ports:
      - 3050:90
    volumes:
      - ./shared:/usr/share/nginx/html/shared # 挂载shared目录到Nginx的静态文件目录
  1. 修改Nginx配置,去掉shared上游块,直接用location提供静态文件:
upstream app {
    server app:3001;
}

server {
    listen 90;

    location / {
        proxy_pass http://app;
        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;
    }

    location /shared/ {
        root /usr/share/nginx/html;
        autoindex on; # 开启目录索引,和之前Apache的效果一致
    }
}

这种方案更简洁,减少了一个服务容器,而且Nginx处理静态文件的效率比Apache更高,同时避免了代理带来的重定向问题。

内容的提问来源于stack exchange,提问作者Borislav Stefanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 13:52:15