[英]Dockerized NGINX Configuration with ReactJS App Running on Azure (Container Instances)
I have a fairly standard ReactJS frontend (using port 3000) app which is served by a NodeJS backend server (using port 5000).我有一个相当标准的 ReactJS 前端(使用端口 3000)应用程序,它由 NodeJS 后端服务器(使用端口 5000)提供服务。 Both apps are Dockerized and I have configured NGINX in order to proxy requests from the frontend to and from the server.
这两个应用程序都是 Dockerized 的,我已经配置了 NGINX 以便代理从前端到服务器的请求。
Dockerfile for front end (with NGINX "baked in"): 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 for server:服务器 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" ]
The docker-compose.yml for this setup is此设置的 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
And crucially, the NGINX default.conf is至关重要的是,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;
}
}
}
with this configuration I have two problems:使用此配置我有两个问题:
By running docker-compose up -d
, this setup builds and deploys two Docker containers locally.通过运行
docker-compose up -d
,此设置在本地构建和部署两个 Docker 容器。 When I use https://localhost:3000/id this works and the data is retrieved and shown in browser correctly - when I type http://localhost:3000/id this gets redirected to http://localhost:443/id and this does not work.当我使用 https://localhost:3000/id 时,这有效并且数据被检索并正确显示在浏览器中 - 当我键入 http://localhost:3000/id 时,它被重定向到 http://localhost:443/id这是行不通的。 I have attempted to use NGINX commands
port_in_redirect off; absolute_redirect off;
我试图使用 NGINX 命令
port_in_redirect off; absolute_redirect off;
port_in_redirect off; absolute_redirect off;
but this has not helped.但这没有帮助。 How can I make sure that the redirect does not edit the port number?
如何确保重定向不会编辑端口号? (this is likely not going to be an issue in production where the port numbers are not used).
(这在不使用端口号的生产中可能不会成为问题)。
The bigger problem : the deployment to Azure is done using a docker context
and running docker-compose -f./docker-compose-azure.yml up
.更大的问题:部署到 Azure 是使用
docker context
并运行docker-compose -f./docker-compose-azure.yml up
。 This runs and creates two Docker containers and a side-car process.这将运行并创建两个 Docker 容器和一个 side-car 进程。 The docker-compose-azure.yml file is
docker-compose-azure.yml 文件是
version: '3.8' services:版本:'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
If I don't use HTTPS and a simple reverse proxy - the two issues outline above go away.如果我不使用 HTTPS 和一个简单的反向代理 - 上面概述的两个问题 go 就会消失。 But with the configuration above, calls to the Azure FQDN/URL fail;
但是使用上面的配置,调用 Azure FQDN/URL 失败; HTTPS requests timing out "ERR_CONNECTION_TIMED_OUT", and for HTTP, the site could not be found.
HTTPS 请求超时“ERR_CONNECTION_TIMED_OUT”,对于 HTTP,找不到站点。 What am I doing wrong here?
我在这里做错了什么?
Thanks for your time.谢谢你的时间。
I think you need to check/update Nginx configuration file properly and also make sure SSL certificate files are available我认为您需要正确检查/更新 Nginx 配置文件,并确保 SSL 证书文件可用
# http block would be
server {
listen 80 default_server;
return 301 https://$server_name$request_uri;
}
and in https server block, you need to update location
block在 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;
}
Updated更新
Your Nginx config file would be您的 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;
}
}
Use port 443 everywhere to avoid any confusion with port remapping (that can be an advance setup):在任何地方都使用端口 443 以避免与端口重新映射(可以是高级设置)混淆:
1.) Define client
container to be running on port 443
: 1.) 定义要在端口
443
上运行的client
容器:
version: '3.8'
services:
client:
...
ports:
- port: 443
protocol: TCP
2.) Define Nginx to be running on the port 443
with proper TLS setup as you have in your updated nginx.conf 2.) 将 Nginx 定义为在端口
443
上运行,并使用正确的 TLS 设置,就像您在更新的 nginx.conf 中所做的那样
Deploy and open https://<public IP>
(you will very likely need to add sec. exception in the browser).部署并打开
https://<public IP>
(您很可能需要在浏览器中添加 sec.exception)。
BTW: Azure has quite good article about Nginx with TLS (but more advance setup is used): https://learn.microsoft.com/en-us/azure/container-instances/container-instances-container-group-ssl顺便说一句:Azure 有关于 Nginx 和 TLS 的相当不错的文章(但使用了更高级的设置): https://learn.microsoft.com/en-us/azure/container-instances/container-instances-container-group-ssl
IMHO better redirect from http to https is:恕我直言,最好从 http 重定向到 https 是:
server {
listen [::]:80;
return 301 https://$host$request_uri;
}
I think Jan Garaj 's answer has touched upon all the important bits.我认为Jan Garaj的回答已经触及了所有重要的部分。 Here is my take, trying to give a targeted answer.
这是我的看法,试图给出有针对性的答案。
HTTP to HTTPS redirect HTTP 到 HTTPS 重定向
Currently the return 301
statement is using the $host
variable that only holds the Hostname and not the port information.目前
return 301
语句使用的$host
变量只包含主机名而不是端口信息。 To capture both, you can use the $http_host
variable instead.要捕获两者,您可以改用
$http_host
变量。 source 来源
server {
listen [::]:80;
#//307 to preserve POST data
return 307 https://$http_host$request_uri;
}
Problems with the Azure config Azure 配置的问题
In the Azure config, you have this bit:在 Azure 配置中,你有这个位:
ports:
- target: 3000
#published: 3000
protocol: tcp
mode: host
which identifies 3000 as the internal client port which listens to the requests.它将 3000 标识为侦听请求的内部客户端端口。 But you have to remember that you have a NGINX proxy inside that only listens to ports 80 or 443 (the
server
blocks in Nginx config).但是您必须记住,您内部有一个 NGINX 代理,它只侦听端口 80 或 443(Nginx 配置中的
server
块)。 So this is the reason you get the ERR_CONNECTION_TIMED_OUT error because the requests are sent to port 3000 where nothing is listening.所以这就是您收到 ERR_CONNECTION_TIMED_OUT 错误的原因,因为请求被发送到没有任何监听的端口 3000。
As you want to do a HTTPS deployment, you can set this to 443 and the Nginx will take care of the request.当您想进行 HTTPS 部署时,您可以将其设置为 443,然后 Nginx 将处理请求。
enabling HTTP redirect on Azure在 Azure 上启用 HTTP 重定向
The final bit is to configure the Azure deployment such that when a HTTP request is made to your URL, it should get redirected to the HTTPS counterpart.最后一点是配置 Azure 部署,这样当向您的 URL 发出 HTTP 请求时,它应该被重定向到对应的 HTTPS。 We already have the NGINX redirect block for port 80.
我们已经有了 80 端口的 NGINX 重定向块。
BUT, it will not help.但是,这无济于事。 As we specify the target to be 443 inside the container, the HTTP request will try to hit 443 and get refused.
由于我们将目标指定为容器内的 443,因此 HTTP 请求将尝试命中 443 并被拒绝。 This article also mentions the same towards the end
This article最后也提到了同样的事情
Use your browser to navigate to the public IP address of the container group.
使用浏览器导航到容器组的公共地址 IP。 The IP address shown in this example is 52.157.22.76, so the URL is https://52.157.22.76 .
此示例中显示的 IP 地址为 52.157.22.76,因此 URL 为https://52.157.22.76 。 You must use HTTPS to see the running application, because of the Nginx server configuration.
由于 Nginx 服务器配置,您必须使用 HTTPS 才能查看正在运行的应用程序。 Attempts to connect over HTTP fail.
尝试通过 HTTP 连接失败。
This could be solved if it were possible to add another port to Azure config, the port 80.如果可以将另一个端口添加到 Azure 配置,即端口 80,则可以解决此问题。
ports:
- port: 443
protocol: TCP
- port: 80
protocol: TCP
I am not sure if Azure allows this, but if it does then thats the final solution.我不确定 Azure 是否允许这样做,但如果允许,那就是最终解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.