无法从Nginx反向代理后面的Docker容器提供静态资产

时间:2019-08-25 00:48:58

标签: docker nginx create-react-app

我正在尝试使用Nginx作为反向代理来服务两个容器。这是我的Nginx conf文件的一部分:

upstream dashboard {
    server dashboard:80;
}

upstream editor {
    server editor:80;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass         http://dashboard;
    }

    location /editor/ {
        rewrite ^/editor(.*)$ $1 break;
        proxy_pass         http://editor;
    } 

在浏览器中导航到/editor URL时出现404错误,因为该页面正在提交对驻留在上游容器“编辑器”中的静态资源的请求。

enter image description here

我对Nginx还是很陌生,但我想它会收到带有url的请求: http://example.com/static/css/2.3d394414.chunk.css

Nginx无法知道相应的CSS位于editor容器内部。如何修改配置以解决此问题?我已经看到了一些配置,这些配置提供了通往任何静态资产的通用路径,但是我需要一个可以处理Docker容器内资产的解决方案。

4 个答案:

答案 0 :(得分:1)

如果我正确理解,您在上游的editordashboard上有静态资源,并且在两种情况下,URL都是相同的/static/some.resource 由于无法根据URL进行区分,因此可以配置nginx首先尝试确定文件是否在dashboard上,然后将请求代理到editor(如果找不到)。

 upstream editor {
    server editor:80;
   }

   upstream dashboard {
     server dashboard:80;
   }

   server {
     location /static {
     # Send 404s to editor
     error_page 404 = @editor;
     proxy_intercept_errors on;

     proxy_pass http://dashboard

     }

     location @editor {
       # If dashboard does not have the file try with editor
       proxy_pass http://editor
     }
   }

另请参阅nginx – try files on multiple named location or server

希望有帮助。

答案 1 :(得分:1)

如果其他任何人遇到相同的问题,这是一个附加的答案,以及@ b0gusb发布的答案。当您将Docker容器作为上游应用程序时,这是一个解决方案。 dashboardeditor例如是包含create-react-app个应用程序和nginx服务器的容器。

首先,通过设置package.json中的index.html字段,更改由create-react-app生成的homepage文件搜索静态资产的目录:

{
  "name": "dashboard",
  "homepage": "https://example.com/dashboard",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-scripts": "3.1.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

使用react-scripts(3.1.1)的当前最新版本,这将生成一个index.html文件,其中包含指向您静态资产的链接,这些链接应位于dashboard目录(或任何名称)中您可以在homepage字段中的斜杠之后选择)。

现在,在您的docker文件中,您需要对构建资产进行一些移动,以使index.html中的链接不会中断。以下是我的Dockerfile

FROM node:12.2.0-alpine as builder

WORKDIR /usr/src/app

ENV PATH /usr/src/app/node_modules/.bin:$PATH

COPY package.json .

RUN npm install react-scripts@3.1.1 -g
RUN npm install

COPY . .

RUN npm run build

FROM nginx:1.17.2

COPY --from=builder /usr/src/app/build/ /usr/share/nginx/html/dashboard
COPY --from=builder /usr/src/app/build/*.html /usr/share/nginx/html

EXPOSE 80

CMD [ "nginx", "-g", "daemon off;" ] 

请注意,由create-react-app构建生成的静态资产位于dashboard目录的内部和index.html目录的/usr/share/nginx/html的内部。现在,您的nginx反向代理可以区分对各种容器的不同静态资产的请求:

    # location to handle calls by the editor app for assets
    location /editor/ {
        proxy_pass http://editor/editor/;
    }

    # location to handle calls by the dashboard app for assets
    location /dashboard/ {
        proxy_pass http://dashboard/dashboard/;
    }

    # location to handle navigation to the editor app
    location /editor-path/ {
        access_log /var/logs/nginx/access.log;
        rewrite ^/editor-path(.*)$ $1 break;
        proxy_pass         http://editor/;
    }        

    # location to handle calls to the rest/graphql api
    location /api/ {
        access_log /var/logs/nginx/access.log;
        rewrite ^/api(.*)$ $1 break;
        proxy_pass         http://restserver/;
    }

    # location to handle navigation to the dashboard app
    location / {
        access_log /var/logs/nginx/access.log;
        proxy_pass         http://dashboard/;
    }

答案 2 :(得分:0)

/编辑器配置置于 / 配置上方。

Nginx从上到下执行检查,因此,最上面的根配置( / )会将所有内容路由到错误的服务器。

切换块位置并重新启动/重新加载nginx配置。

答案 3 :(得分:0)

实际上,为便于配置,您可以按照以下步骤操作:

upstream dashboard {
    server dashboard:80;
}

upstream editor {
    server editor:80;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass         http://dashboard;
    }

    location /editor/ {
        proxy_pass         http://editor;
        proxy_set_header Accept-Encoding "";
        sub_filter "/static" "/editor/static;
        sub_filter_once off;
    }

sub_filter函数会将example.com/static/更改为example.com/editor/static,但是为了获得最佳配置,您必须为所有静态文件创建一个路径。喜欢:

/ var / data / build / dashboard / ..(可以是CSS,JS)

/ var / data / build / editor / ..(可以是CSS,JS)

我认为使用sub_filter很好,而该应用程序没有很多URL可以重写,希望对您有所帮助。