三年教训的前端或多或少与 nginx 配置打过交道。
nginx 的重要性显而易见。
本篇文章以前端的视角,介绍下 nginx 的常见配置,并通过 docker 的形式学习 nginx,这保障所有示例配置都能失常运行。
我将本文所有对于 docker/nginx 的配置搁置在 simple-deploy,可克隆下来通过 docker compose 疾速运行。
并将所有的接口示例保护在了 Learn Nginx By Docker 文档,并可通过 Apifox 关上并疾速调试。
nginx 的配置文件
咱们通过 nginx
镜像来理解 nginx 的配置文件都有哪些。
$ docker run -it --rm nginx:alpine sh
$ ls -lah /etc/nginx/
total 40K
drwxr-xr-x 3 root root 4.0K Nov 13 2021 .
drwxr-xr-x 1 root root 4.0K Jun 14 07:55 ..
drwxr-xr-x 2 root root 4.0K Nov 13 2021 conf.d
-rw-r--r-- 1 root root 1.1K Nov 2 2021 fastcgi.conf
-rw-r--r-- 1 root root 1007 Nov 2 2021 fastcgi_params
-rw-r--r-- 1 root root 5.2K Nov 2 2021 mime.types
lrwxrwxrwx 1 root root 22 Nov 13 2021 modules -> /usr/lib/nginx/modules
-rw-r--r-- 1 root root 648 Nov 2 2021 nginx.conf
-rw-r--r-- 1 root root 636 Nov 2 2021 scgi_params
-rw-r--r-- 1 root root 664 Nov 2 2021 uwsgi_params
在 nginx
中,其中比拟重要的有以下几个文件,而它们都是有层层关联的:
/etc/nginx/nginx.conf
/etc/nginx/conf.d/default.conf
/etc/nginx/nginx.conf
nginx 主配置文件,援用了 /etc/nginx/conf.d/
目录下的所有配置文件。
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {worker_connections 1024;}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local]"$request"''$status $body_bytes_sent "$http_referer" ''"$http_user_agent""$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
/etc/nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {root /usr/share/nginx/html;}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
/usr/share/nginx/html
默认的动态资源目录,也是 nginx 的欢送页面。
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html {color-scheme: light dark;}
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
通过 docker 高效学习 nginx 配置
举荐一种高效学习 nginx 的办法: 在本地应用 nginx 镜像并挂载 nginx 配置启动容器。
通过以下 docker-compose
可秒级验证 nginx 配置,无疑是学习 nginx 的绝佳利器。
我将所有对于 nginx 的配置搁置在 simple-deploy,并且每一份配置对应 docker-compose
中的一个 service 如以下 nginx、location、order1 就是 service
。
version: "3"
services:
# 对于 nginx 最常见配置的学习
nginx:
image: nginx:alpine
ports:
- 8080:80
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- .:/usr/share/nginx/html
# 对于 location 的学习
location: ...
# 对于 location 匹配程序的学习
order1: ...
每次批改配置时,须要重启容器,可依据服务名学习指定内容。
$ docker-compose up <service>
# 学习 nginx 最根底的配置
$ docker-compose up nginx
# 学习对于 location 的配置
$ docker-compose up location
本篇文章所有的 nginx 配置均能够通过 docker
来进行学习,并附全副代码及配置。
root 与 index
root
: 动态资源的根门路。见文档 https://nginx.org/en/docs/htt…index
: 当申请门路以/
结尾时,则主动寻找该门路下的 index 文件。见文档 https://nginx.org/en/docs/htt…
root
与 index
为前端部署的根底,在默认状况下 root 为 /usr/share/nginx/html
,因而咱们部署前端时,往往将构建后的动态资源目录挂载到该地址。
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
}
location
location 用以匹配路由,配置语法如下。
location [= | ~ | ~* | ^~] uri {...}
其中 uri
前可提供以下修饰符
=
准确匹配,优先级最高。^~
前缀匹配,优先级其次。如果同样是前缀匹配,走最长门路。~
正则匹配,优先级再次 (~* 只是不辨别大小写,不单列)。如果同样是正则匹配,走第一个门路。/
通用匹配,优先级再次。
为了验证所匹配的 location,我会在以下示例中增加一个自定义响应头 X-Config
,可通过浏览器控制台网络面板验证其响应头。
add_header X-Config B;
留神,我所有 配置文件中的链接可间接点击,防止了在 compose 配置文件中寻找映射端口号的不不便。
location 修饰符验证
对于此四种修饰符能够在我的 nginx 下进行验证。
因为此处应用了 proxy_pass
,因而须要 location2
,api
两个服务一起启动,在 location2 服务中,可间接通过 service 名称作为 hostname 即 http://api:3000
拜访 api 服务。
而 api 服务,为我本人写的一个 whoami 服务,用以打印出申请门路等信息,详见 shfshanyue/whoami。
$ docker-compose up location2 api
以下是对于验证 location 的配置文件,详见 shfshanyue/simple-daploy:learn-nginxs
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
# 通用匹配,所有 /xxx 任意门路都会匹配其中的规定
location / {
add_header X-Config A;
try_files $uri $uri.html $uri/index.html /index.html;
}
# http://localhost:8120/test1 ok
# http://localhost:8120/test1/ ok
# http://localhost:8120/test18 ok
# http://localhost:8120/test28 not ok
location /test1 {
# 可通过查看响应头来判断是否胜利返回
add_header X-Config B;
proxy_pass http://api:3000;
}
# http://localhost:8120/test2 ok
# http://localhost:8120/test2/ not ok
# http://localhost:8120/test28 not ok
location = /test2 {
add_header X-Config C;
proxy_pass http://api:3000;
}
# http://localhost:8120/test3 ok
# http://localhost:8120/test3/ ok
# http://localhost:8120/test38 ok
# http://localhost:8120/hellotest3 ok
location ~ .*test3.* {
add_header X-Config D;
proxy_pass http://api:3000;
}
# http://localhost:8120/test4 ok
# http://localhost:8120/test4/ ok
# http://localhost:8120/test48 ok
# http://localhost:8120/test28 not ok
location ^~ /test4 {
# 可通过查看响应头来判断是否胜利返回
add_header X-Config E;
proxy_pass http://api:3000;
}
}
location 优先级验证
在我配置文件中,以 order
打头来命名所有优先级验证的 nginx 配置,总共有四个配置文件,详见 docker-compose。
此处仅仅以 order1
为例进行验证,配置如下:
# 以下配置,拜访以下链接,其 X-Config 为多少
#
# http://localhost:8210/shanyue,为 B,若都是前缀匹配,则找到最长匹配的 location
server {
root /usr/share/nginx/html;
# 次要是为了 shanyue 该门路,因为没有后缀名,无奈确认其 content-type,会主动下载
# 因而这里采纳 text/plain,则不会主动下载
default_type text/plain;
location ^~ /shan {add_header X-Config A;}
location ^~ /shanyue {add_header X-Config B;}
}
启动服务:
$ docker-compose up order1
curl 验证:
当然也能够通过浏览器控制台网络面板验证,因为此处只须要验证响应头,则咱们通过 curl --head
只发送 head
申请即可。
# 查看其 X-Config 为 B
$ curl --head http://localhost:8210/shanyue
HTTP/1.1 200 OK
Server: nginx/1.21.4
Date: Fri, 03 Jun 2022 10:15:11 GMT
Content-Type: text/plain
Content-Length: 15
Last-Modified: Thu, 02 Jun 2022 12:44:23 GMT
Connection: keep-alive
ETag: "6298b0a7-f"
X-Config: B
Accept-Ranges: bytes
proxy_pass
proxy_pass
反向代理,也是 nginx 最重要的内容,这也是罕用的解决跨域的问题。
当应用 proxy_pass
代理门路时,有两种状况
- 代理服务器地址不含 URI,则此时客户端申请门路与代理服务器门路雷同。强烈建议这种形式
- 代理服务器地址含 URI,则此时客户端申请门路匹配 location,并将其 location 后的门路附在代理服务器地址后。
# 不含 URI
proxy_pass http://api:3000;
# 含 URI
proxy_pass http://api:3000/;
proxy_pass http://api:3000/api;
proxy_pass http://api:3000/api/;
再举一个例子:
- 拜访 http://localhost:8300/api3/hello,与以下门路匹配胜利
proxy_pass
附有 URI- 匹配门路后多余的门路为
/hello
,将其附在proxy_pass
之后,得 http://api:3000/hello/hello
location /api3 {
add_header X-Config C;
# http://localhost:8300/api3/hello -> proxy:3000/hello/hello
proxy_pass http://api:3000/hello;
}
有点拗口,在咱们试验环境有多个示例,应用以下代码启动可重复测试:
$ docker-compose up proxy api
因为 proxy_pass 所代理的服务为 whoami,可打印出实在申请门路,可依据此进行测试
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
# 倡议应用此种 proxy_pass 不加 URI 的写法,原样门路即可
# http://localhost:8300/api1/hello -> proxy:3000/api1/hello
location /api1 {
# 可通过查看响应头来判断是否胜利返回
add_header X-Config A;
proxy_pass http://api:3000;
}
# http://localhost:8300/api2/hello -> proxy:3000/hello
location /api2/ {
add_header X-Config B;
proxy_pass http://api:3000/;
}
# http://localhost:8300/api3/hello -> proxy:3000/hello/hello
location /api3 {
add_header X-Config C;
proxy_pass http://api:3000/hello;
}
# http://localhost:8300/api4/hello -> proxy:3000//hello
location /api4 {
add_header X-Config D;
proxy_pass http://api:3000/;
}
}
add_header
管制响应头。
因为很多个性都是通过响应头管制,因而基于此指令可做很多事件,比方:
- Cache
- CORS
- HSTS
- CSP
- …
Cache
location /static {add_header Cache-Control max-age=31536000;}
CORS
location /api {add_header Access-Control-Allow-Origin *;}
HSTS
location / {
listen 443 ssl;
add_header Strict-Transport-Security max-age=7200;
}
CSP
location / {add_header Content-Security-Policy "default-src'self';";}
作业
- 初阶: 基于 docker 学习 nginx 配置,并可配置 index.html 强缓存 60s 工夫
- 中阶: 如何应用 nginx 与 whoami 镜像,模仿 502/504
- 高阶: 基于 docker 学习 nginx 配置,并可配置 gzip/brotli
- 面试: brotli/gzip 有何区别