[Nginx配置文件的编写方法(适合初学者)]
简述
由于在Web应用开发中,很多项目都使用Nginx作为Web服务器,所以这次我们决定使用Nginx作为我们的Web服务器。
-
- ローカル環境
- 本番環境
请勿离开
-
- NginxのDockerfileおよびnginx.confファイルの作成方法
- フロントエンドとバックエンドの連携方法
我希望解释关于等的问题。
前提
-
- 今回は例としてフレームワークはDjango、WSGIサーバはGunicornを使用します
- インフラはAWSを使用する前提でお話しします
代理服务器和反向代理服务器的区别
代理服务器是在客户端与互联网通信时,客户端不直接连接到Web服务器,而是通过另一台服务器来中转的服务器。通过经由代理可以访问无法直接访问的Web服务器等,具有优点。而反向代理服务器是承担客户端请求中继至后端服务器的角色的服务器。总结起来,代理服务器是代理互联网(客户端),而反向代理则相反,它充当后端服务器的代理。而本次介绍的Nginx的作用是代理服务器,它将客户端的通信通过代理,并发送到后端的API服务器。
本地环境
在本地环境中,使用Dockerfile和docker-compose.yml一起使用。
-
- docker-compose.yml
-
- Dockerfile
- nginx.conf
我将按照以下顺序逐一解释。
docker-compose.yml文件
以下是
-
- Django
-
- MySQL
-
- Nginx
- Node.js
这是用于Docker Compose的文件。
在本地环境中,我们使用Nginx来连接前端和后端,并使用Docker的网络。这次我们将创建一个名为testnet的网络。
version: '3.9'
services:
app:
container_name: app
build:
context: .
dockerfile: containers/django/Dockerfile
volumes:
- ./application:/code
- ./static:/static
ports:
- '8000:8000'
# デバッグ用ポート
- '8080:8080'
command: sh -c "/usr/local/bin/entrypoint.sh"
stdin_open: true
tty: true
env_file:
- .env
nginx:
container_name: web
build:
context: .
dockerfile: containers/nginx/Dockerfile
volumes:
- ./static:/static
ports:
- 80:80
depends_on:
- app
front:
container_name: front
build:
context: .
dockerfile: containers/front/Dockerfile
volumes:
- ./frontend:/code
- node_modules_volume:/frontend/node_modules
command: sh -c "npm run dev"
ports:
- '3000:3000'
environment:
- CHOKIDAR_USEPOLLING=true
- RESTAPI_URL=http://localhost/back
volumes:
static:
networks:
default:
name: testnet
Dockerfile的中文释义是:易容文件。
将下文中的nginx.conf文件进行复制的设置。
FROM nginx:1.21
RUN rm -f /etc/nginx/conf.d/*
COPY ./containers/nginx/nginx.conf /etc/nginx/conf.d/
nginx配置文件
这是在本地环境使用的Nginx配置文件。
upstream front {
server host.docker.internal:3000;
}
upstream back {
server host.docker.internal:8000;
}
server {
listen 80;
server_name localhost;
client_max_body_size 20M;
location / {
proxy_pass http://front/;
}
location /back/ {
# X-Forwarded-Hostヘッダにバックエンドのホスト名とポートを指定
proxy_set_header X-Forwarded-Host $host:$server_port;
# X-Forwarded-Serverヘッダにバックエンドのホスト名を指定
proxy_set_header X-Forwarded-Server $host;
# X-Forwarded-Forヘッダにリクエストを送ったクライアントまたはプロキシのIPアドレスの履歴(リスト)を設定
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 上記の情報のヘッダが今回だとMacの8000番ポートに最終的に転送される
proxy_pass http://back/;
}
location /_next/webpack-hmr {
proxy_pass http://front/_next/webpack-hmr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
逐一解释。
上游
使用upstream指令进行配置
-
- バックエンドサーバ
- フロントエンドサーバ
正在定义
在这种情况下,在”server”之后写上服务器名称
这次将在Docker容器和Docker主机(Mac)之间进行通信
host.docker.internal
利用Docker的一个功能,可以使容器无需指定IP地址即可轻松访问宿主机(Mac)。我们将前端设置为3000端口,后端设置为8000端口,因此在docker-compose.yml文件中也需要相应地调整端口号。
upstream front {
server host.docker.internal:3000;
}
upstream back {
server host.docker.internal:8000;
}
服务器
通过80号端口进行代理设置。
由于使用本地环境,因此服务器名称为localhost。
server {
listen 80;
server_name localhost;
我将说明如何在Nginx中配置代理以向前端发送请求。
由于在upstream中命名为”front”,因此需要与之保持一致。
location / {
proxy_pass http://front/;
}
我将在Nginx的配置中添加一个代理到后端的设置。由于在upstream中使用了”back”,因此请保持名称一致。
location /back/ {
# X-Forwarded-Hostヘッダにバックエンドのホスト名とポートを指定
proxy_set_header X-Forwarded-Host $host:$server_port;
# X-Forwarded-Serverヘッダにバックエンドのホスト名を指定
proxy_set_header X-Forwarded-Server $host;
# X-Forwarded-Forヘッダにリクエストを送ったクライアントまたはプロキシのIPアドレスの履歴(リスト)を設定
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 上記の情報のヘッダが今回だとMacの8000番ポートに最終的に転送される
proxy_pass http://back/;
}
Webpacker 的配置
这是将Nginx中的请求反向代理到Next.js的Webpacker的配置。
根据官方文档,为了启用热模块重载(HMR),需要明确传递以下标头,要求Nginx版本必须为1.3.13或更高。
location /_next/webpack-hmr {
proxy_pass http://front/_next/webpack-hmr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
为将客户端和服务器之间的连接从HTTP/1.1转换为WebSocket,需要使用HTTP/1.1中可用的协议切换机制。
然而,有一个微妙之处:由于“Upgrade”是逐跳的头部,它不会从客户端传递到代理服务器。对于正向代理,客户端可以使用CONNECT方法来绕过这个问题。然而,对于反向代理来说,这种方法不起作用,因为客户端不知道任何代理服务器的存在,需要在代理服务器上进行特殊处理。
从版本1.3.13开始,nginx实现了一种特殊的操作模式,允许在代理服务器返回代码为101(协议切换)的响应,并且客户端通过请求中的“Upgrade”头部请求进行协议切换时,建立客户端和代理服务器之间的隧道。
正如前面所述,包括“Upgrade”和“Connection”在内的逐跳头部不会从客户端传递到代理服务器,因此为了让代理服务器知道客户端要切换到WebSocket的意图,这些头部必须明确传递。
实际环境
由于在生产环境中使用ECS Fargate,不需要使用docker-compose.yml。
-
- NginxのDockerfile
- nginx.conf
我会逐个解释它们的顺序。
Dockerfile 文件
FROM --platform=linux/x86_64 nginx:stable-alpine
RUN rm -f /etc/nginx/conf.d/*
COPY ./containers/nginx/nginx.conf /etc/nginx/conf.d/
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
使用Apple Silicon Mac在AWS上使用Nginx的Dockerfile。
--platform=linux/x86_64
需要指定的是M1 Mac采用的是ARM架构,而ECS上采用的是Linux/x86_64架构,
在构建ECS时会发生平台错误,
因此我们在Dockerfile中添加上述命令,以使平台与ECS相同。
此外,默认情况下,Nginx会在后台(守护进程已启用的状态)运行。
为了能在Cloud Watch上查看日志,我们将守护进程关闭,以便能够以前台方式运行。
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
nginx配置文件
这是Nginx的生产环境设置文件。
upstream gunicorn {
# gunicornとdjangoがunixソケットを通じて通信する
server unix:///code/tmp/gunicorn_socket;
}
server {
listen 80;
server_name example.com api.example.com;
# Nginxのバージョン情報を非表示にする
# サーバ情報を隠すことでセキュリティ上のリスクを軽減させる
server_tokens off;
# ファイルサイズの変更、デフォルト値は1M
client_max_body_size 5M;
# HTTP レスポンスヘッダの Content_Type に付与する文字コード
charset utf-8;
# ログ設定
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# API 通信
# プロキシ先のGunicornに対して、元のクライアントIPアドレスやヘッダ情報を転送
location /api {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_read_timeout 3600;
proxy_pass http://gunicorn;
}
# ヘルスチェック用のレスポンスを転送
location /api/health {
empty_gif;
access_log off;
break;
}
# HTTP 通信をタイムアウトせずに待つ秒数
keepalive_timeout 60;
}
我会逐一解释
上游
upstream gunicorn {
# gunicornとdjangoがunixソケットを通じて通信する
server unix:///code/tmp/gunicorn_socket;
}
進行Gunicorn和Django之間的設定,使它們可以進行套接字通信。通過套接字通信,可以直接在數據之間進行交流,而無需通過互聯網傳輸,這將提升安全性和性能。
与API的通信配置
将本地设置几乎与之前相同。
只需通过proxy_pass指定在上游定义的Gunicorn进行设置。
# API 通信
# プロキシ先のGunicornに対して、元のクライアントIPアドレスやヘッダ情報を転送
location /api {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_read_timeout 3600;
proxy_pass http://gunicorn;
}
健康检查
我将介绍健康检查的设置。关于健康检查,我将把access_log的设置设为关闭。
# ヘルスチェック用のレスポンスを転送
location /api/health {
empty_gif;
access_log off;
break;
}
总结
我写Nginx的配置文件和Dockerfile时只是随便写了一下,所以我整理了一下。
这是在本地和AWS上使用时必备的知识,记住它不会有任何损失,我想。
请参考