用于在 nginx 上运行的 Angular 应用程序的 nginx 反向代理

Posted

技术标签:

【中文标题】用于在 nginx 上运行的 Angular 应用程序的 nginx 反向代理【英文标题】:nginx reverse proxy for angular app running on nginx 【发布时间】:2019-09-19 07:15:18 【问题描述】:

我有一个 Docker 容器,用于在 nginx 上运行的 Angular 应用程序,名为 "website" 。我想从名为“test.nginx”的其他 nginx 反向代理容器访问这个容器。但我不知道如何为反向代理配置 nginx.conf。

首先,我正在为 Angular 应用程序创建 docker 映像。 Dockerfile:

FROM nginx:alpine
COPY default.conf /etc/nginx/conf.d/default.conf
COPY angular /usr/share/nginx/html

这里的 angular 文件夹包括 angular 构建文件(index.html, main.js, runtime.js ...)

default.conf:

server 
    listen       80;
    server_name  localhost;

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

    error_page   500 502 503 504  /50x.html;
    location = /50x.html 
        root   /usr/share/nginx/html;
    

docker-compose.yml

version: '3.4'

services:

  nginx:
    image: nginx:latest
    container_name: test.nginx
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    ports:
      - 2020:80
    environment:
      - NETWORK_ACCESS=internal

  website:
    image: website
    container_name: website
    restart: on-failure       
    ports:
      - 2121:80

和 test.nginx 容器使用这个 nginx.conf

worker_processes 1;
events  worker_connections 1024; 

http 
    server 
        location /client/ 
            proxy_pass         http://website/;
            proxy_redirect     off;
            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-Host $server_name;
            
    


当我尝试使用 http://localhost:2121 访问 Angular 应用程序时,一切都很好。 但是如果我尝试这个http://localhost:2020/client/ 我会得到这些错误

website    | 192.168.208.2 - - [30/Apr/2019:15:11:18 +0000] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36" "192.168.208.1"
test.nginx | 192.168.208.1 - - [30/Apr/2019:15:11:18 +0000] "GET /client/ HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
test.nginx | 2019/04/30 15:11:18 [error] 6#6: *5 open() "/etc/nginx/html/runtime.js" failed (2: No such file or directory), client: 192.168.208.1, server: , request: "GET /runtime.js HTTP/1.1", host: "localhost:2020", referrer: "http://localhost:2020/client/"
test.nginx | 192.168.208.1 - - [30/Apr/2019:15:11:18 +0000] "GET /runtime.js HTTP/1.1" 404 556 "http://localhost:2020/client/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
test.nginx | 2019/04/30 15:11:18 [error] 6#6: *3 open() "/etc/nginx/html/polyfills.js" failed (2: No such file or directory), client: 192.168.208.1, server: , request: "GET /polyfills.js HTTP/1.1", host: "localhost:2020", referrer: "http://localhost:2020/client/"
test.nginx | 192.168.208.1 - - [30/Apr/2019:15:11:18 +0000] "GET /polyfills.js HTTP/1.1" 404 556 "http://localhost:2020/client/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
test.nginx | 2019/04/30 15:11:18 [error] 6#6: *4 open() "/etc/nginx/html/styles.js" failed (2: No such file or directory), client: 192.168.208.1, server: , request: "GET /styles.js HTTP/1.1", host: "localhost:2020", referrer: "http://localhost:2020/client/"
test.nginx | 192.168.208.1 - - [30/Apr/2019:15:11:18 +0000] "GET /styles.js HTTP/1.1" 404 556 "http://localhost:2020/client/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
test.nginx | 2019/04/30 15:11:18 [error] 6#6: *1 open() "/etc/nginx/html/vendor.js" failed (2: No such file or directory), client: 192.168.208.1, server: , request: "GET /vendor.js HTTP/1.1", host: "localhost:2020", referrer: "http://localhost:2020/client/"
test.nginx | 192.168.208.1 - - [30/Apr/2019:15:11:18 +0000] "GET /vendor.js HTTP/1.1" 404 556 "http://localhost:2020/client/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
test.nginx | 192.168.208.1 - - [30/Apr/2019:15:11:18 +0000] "GET /main.js HTTP/1.1" 404 556 "http://localhost:2020/client/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
test.nginx | 2019/04/30 15:11:18 [error] 6#6: *6 open() "/etc/nginx/html/main.js" failed (2: No such file or directory), client: 192.168.208.1, server: , request: "GET /main.js HTTP/1.1", host: "localhost:2020", referrer: "http://localhost:2020/client/"

当我只使用 index.html 文件而不是 angular 构建文件时,我可以从 http://localhost:2020/client/ 和 http://localhost:2121 访问 index.html 文件

请有人帮助我吗? 谢谢:)

***编辑:

我认为我收到此错误是因为 Angular 是一个单页应用程序。 现在的问题是如何为 spa 配置 location 和 proxy_pass?

【问题讨论】:

【参考方案1】:

你不能只用 NGINX 和 Angular 做一个反向代理。

我们必须做的是添加 haproxy (http://www.haproxy.org/) 作为单独的服务并对其进行配置,以便它可以查看 nginx 服务器。

这个 docker 镜像可能是一个好的开始(https://hub.docker.com/_/haproxy)

对于我们的 nginx 配置,它看起来类似于:

        # Api Endpoint
        location /api/
        proxy_pass https://api.company.com:1234/;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        

然后,在我们的 HA 代理中(使用 HTTPS)。我添加了一些评论来帮助指导您完成此操作。

global
    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

    # Default SSL material locations
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private


    server=haproxy
    ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
    ssl-default-bind-options no-sslv3

frontend server1  #Where the user is coming from (anywhere) 
        mode http
        bind 0.0.0.0:443 ssl crt /etc/ssl/certificate.pem

        acl api url_reg ^\/API/.*  # Check the contents of the URL from the user's browser

        use_backend api_server if api  # If the ACL above is true:
                                       # Use the api_server desription below


backend api_server # Define the api_server
        mode http  
        server appsrv-1 10.1.1.3:443/API/ check ssl verify none
                             # appsrv-1 is just a title of the server.
                             # Use the IP to where the Backend is
                             # specify the port and the location.  In your case
                             # you would use /client/

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http

然后,当您完成 HA 代理配置并指向您的 nginx 服务器时,请确保您的用户首先使用其 FQDN 的 IP 地址访问 haproxy。然后,HA 代理将为您处理反向代理。

关于您关于 SPA 的问题,我的理解是您添加的 NGINX 配置内部:

proxy_pass http://api.company.com:1234/; # Where the proxy is
proxy_intercept_errors on;               # IF there is a problem
error_page 404 = /index.html;              # Serve the index.html as the 404 page

【讨论】:

非常感谢。您知道如何为水疗中心配置 location 和 proxy_pass 吗? @ErtuğrulGAMGAM,我更新了我的答案,将您的 SPA 问题包含在底部。我个人没有这样做,但我希望它有所帮助。 @mthola:“你不能只用 NGINX 和 Angular 做一个反向代理。”抱歉,为什么?这应该是有原因的,但我无法从你后续的回答中得到它......

以上是关于用于在 nginx 上运行的 Angular 应用程序的 nginx 反向代理的主要内容,如果未能解决你的问题,请参考以下文章

Angular App 在 nginx 上运行并在附加的 nginx 反向代理后面

如何从 Angular 6 向 node.js 发送 https 请求

使用 SSL 和 Nginx 运行 Puma

如何在节点/角度/nginx应用程序上强制缓存过期

如何在同一端口 4200 上运行 angular 4 app 和 nodejs api 用于生产和开发?

Angular 4路由不适用于实时网络应用