繁体   English   中英

Dockerized NGINX 配置 ReactJS App 在 Azure 上运行(容器实例)

[英]Dockerized NGINX Configuration with ReactJS App Running on Azure (Container Instances)

我有一个相当标准的 ReactJS 前端(使用端口 3000)应用程序,它由 NodeJS 后端服务器(使用端口 5000)提供服务。 这两个应用程序都是 Dockerized 的,我已经配置了 NGINX 以便代理从前端到服务器的请求。

Dockerfile 用于前端(带有 NGINX“烘焙”):

FROM node:lts-alpine as build

WORKDIR /app

COPY ./package.json ./
COPY ./package-lock.json ./

RUN npm install
COPY . .
RUN npm run build

FROM nginx

EXPOSE 3000
EXPOSE 443
EXPOSE 80

COPY ./cert/app.crt /etc/nginx/
COPY ./cert/app.key /etc/nginx/

ENV HTTPS=true
ENV SSL_CRT_FILE=/etc/nginx/app.crt
ENV SSL_KEY_FILE=/etc/nginx/app.key

RUN rm /etc/nginx/conf.d/default.conf

COPY ./default.conf /etc/nginx/nginx.conf
COPY --from=build /app/build/ /usr/share/nginx/html

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

服务器 Dockerfile:

FROM node:lts-alpine as build

WORKDIR /app
EXPOSE 5000

ENV NODE_TLS_REJECT_UNAUTHORIZED=0
ENV DANGEROUSLY_DISABLE_HOST_CHECK=true
ENV NODE_CONFIG_DIR=./config/

COPY ./package.json ./
COPY ./package-lock.json ./

RUN npm install

COPY . .
CMD [ "npm", "start" ]

此设置的 docker-compose.yml 是

version: '3.8'
services:
  client:
    container_name: client
    depends_on:
      - server
    stdin_open: true
    environment:
      - CHOKIDAR_USEPOLLING=true
      - HTTPS=true
      - SSL_CRT_FILE=/etc/nginx/app.crt
      - SSL_KEY_FILE=/etc/nginx/app.key
    build:
      dockerfile: Dockerfile
      context: ./client
    expose:
      - "8000"
      - "3000"
    ports:
      - "3000:443"
      - "8000:80"
    volumes:
      - ./client:/app
      - /app/node_modules
      - /etc/nginx
    networks:
      - internal-network

  server:
    container_name: server
    build:
      dockerfile: Dockerfile
      context: "./server"
    expose:
      - "5000"
    ports:
      - "5000:5000"
    volumes:
      - /app/node_modules
      - ./server:/app
    networks:
      - internal-network

networks:
  internal-network:
    driver: bridge
    

至关重要的是,NGINX default.conf 是

worker_processes auto;

events {
  worker_connections 1024;
}

pid /var/run/nginx.pid;

http {

    include mime.types;

    upstream loadbalancer {
        server server:5000 weight=3;
    }

    server {
        listen 80 default_server;
        listen [::]:80 default_server;

        server_name _;

        port_in_redirect off;
        absolute_redirect off;

        return 301 https://$host$request_uri;
    }

    server {
        listen [::]:443 ssl;
        listen 443 ssl;

        server_name example.app* example.co* example.uksouth.azurecontainer.io* localhost*;
        error_page 497 https://$host:$server_port$request_uri;

        error_log /var/log/nginx/client-proxy-error.log;
        access_log /var/log/nginx/client-proxy-access.log;

        ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers                ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
        ssl_prefer_server_ciphers  on;
        ssl_session_cache          shared:SSL:10m;
        ssl_session_timeout        24h;

        keepalive_timeout 300;
        add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';

        ssl_certificate     /etc/nginx/app.crt;
        ssl_certificate_key /etc/nginx/app.key;

        root /usr/share/nginx/html;
        index index.html index.htm index.nginx-debian.html;

         location / {
            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;
            try_files $uri $uri/ /index.html;
        }
        
        location /tours {
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            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_pass http://loadbalancer;
        }
    }
}

使用此配置我有两个问题:

  1. 通过运行docker-compose up -d ,此设置在本地构建和部署两个 Docker 容器。 当我使用 https://localhost:3000/id 时,这有效并且数据被检索并正确显示在浏览器中 - 当我键入 http://localhost:3000/id 时,它被重定向到 http://localhost:443/id这是行不通的。 我试图使用 NGINX 命令port_in_redirect off; absolute_redirect off; port_in_redirect off; absolute_redirect off; 但这没有帮助。 如何确保重定向不会编辑端口号? (这在不使用端口号的生产中可能不会成为问题)。

  2. 更大的问题:部署到 Azure 是使用docker context并运行docker-compose -f./docker-compose-azure.yml up 这将运行并创建两个 Docker 容器和一个 side-car 进程。 docker-compose-azure.yml 文件是

    版本:'3.8' 服务:

     client: image: dev.azurecr.io/example-client depends_on: - server stdin_open: true environment: - CHOKIDAR_USEPOLLING=true - HTTPS=true - SSL_CRT_FILE=/etc/nginx/app.crt - SSL_KEY_FILE=/etc/nginx/app.key restart: unless-stopped domainname: "example-dev" expose: - "3000" ports: - target: 3000 #published: 3000 protocol: tcp mode: host.networks: - internal.network server: image: dev.azurecr.io/example-server restart: unless-stopped ports: - "5000:5000".networks: - internal.network.networks: internal.network: driver: bridge

如果我不使用 HTTPS 和一个简单的反向代理 - 上面概述的两个问题 go 就会消失。 但是使用上面的配置,调用 Azure FQDN/URL 失败; HTTPS 请求超时“ERR_CONNECTION_TIMED_OUT”,对于 HTTP,找不到站点。 我在这里做错了什么?

谢谢你的时间。

我认为您需要正确检查/更新 Nginx 配置文件,并确保 SSL 证书文件可用

# http block would be
server {
        listen 80 default_server;
        return 301 https://$server_name$request_uri;
}

在 https 服务器块中,您需要更新location

location /tours {
        proxy_pass http://server:5000;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
}
        
location / {
        try_files $uri $uri/ /index.html;
}

更新

您的 Nginx 配置文件将是

worker_processes auto;

events {
  worker_connections 1024;
}

pid /var/run/nginx.pid;

http {

    include mime.types;

    server {
        listen [::]:443 ssl;
        listen 443 ssl;

        server_name my-redirected-domain.com my-azure-domain.io localhost;

        access_log /var/log/nginx/client-proxy.log;

        ssl_protocols              TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers                ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
        ssl_prefer_server_ciphers  on;
        ssl_session_cache          shared:SSL:10m;
        ssl_session_timeout        24h;

        keepalive_timeout 300;
        add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';

        ssl_certificate     /etc/nginx/viewform.app.crt;
        ssl_certificate_key /etc/nginx/viewform.app.key;

        root /usr/share/nginx/html;
        index index.html index.htm index.nginx-debian.html;

        location / {
            try_files $uri $uri/ /index.html;
        }
        
        location /tours {
            proxy_pass http://server:5000;
            proxy_set_header Connection "";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
    }

    server {
        listen 80 default_server;
        return 301 https://$server_name$request_uri;
    }
}

在任何地方都使用端口 443 以避免与端口重新映射(可以是高级设置)混淆:

1.) 定义要在端口443上运行的client容器:

version: '3.8'
services:
  client:
...
    ports:
      - port: 443
        protocol: TCP

2.) 将 Nginx 定义为在端口443上运行,并使用正确的 TLS 设置,就像您在更新的 nginx.conf 中所做的那样

部署并打开https://<public IP> (您很可能需要在浏览器中添加 sec.exception)。

顺便说一句:Azure 有关于 Nginx 和 TLS 的相当不错的文章(但使用了更高级的设置): https://learn.microsoft.com/en-us/azure/container-instances/container-instances-container-group-ssl

恕我直言,最好从 http 重定向到 https 是:

server {
    listen         [::]:80;
    return 301 https://$host$request_uri;
}

我认为Jan Garaj的回答已经触及了所有重要的部分。 这是我的看法,试图给出有针对性的答案。

HTTP 到 HTTPS 重定向

目前return 301语句使用的$host变量只包含主机名而不是端口信息。 要捕获两者,您可以改用$http_host变量。 来源

server {
    listen         [::]:80;

    #//307 to preserve POST data
    return 307 https://$http_host$request_uri; 
}

Azure 配置的问题

在 Azure 配置中,你有这个位:

    ports:
      - target: 3000
        #published: 3000
        protocol: tcp 
        mode: host

它将 3000 标识为侦听请求的内部客户端端口。 但是您必须记住,您内部有一个 NGINX 代理,它只侦听端口 80 或 443(Nginx 配置中的server块)。 所以这就是您收到 ERR_CONNECTION_TIMED_OUT 错误的原因,因为请求被发送到没有任何监听的端口 3000。

当您想进行 HTTPS 部署时,您可以将其设置为 443,然后 Nginx 将处理请求。

在 Azure 上启用 HTTP 重定向

最后一点是配置 Azure 部署,这样当向您的 URL 发出 HTTP 请求时,它应该被重定向到对应的 HTTPS。 我们已经有了 80 端口的 NGINX 重定向块。

但是,这无济于事。 由于我们将目标指定为容器内的 443,因此 HTTP 请求将尝试命中 443 并被拒绝。 This article最后也提到了同样的事情

使用浏览器导航到容器组的公共地址 IP。 此示例中显示的 IP 地址为 52.157.22.76,因此 URL 为https://52.157.22.76 由于 Nginx 服务器配置,您必须使用 HTTPS 才能查看正在运行的应用程序。 尝试通过 HTTP 连接失败。

如果可以将另一个端口添加到 Azure 配置,即端口 80,则可以解决此问题。

     ports:
      - port: 443
        protocol: TCP
      - port: 80
        protocol: TCP

我不确定 Azure 是否允许这样做,但如果允许,那就是最终解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM