三年教训的前端或多或少与 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.typeslrwxrwxrwx    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 andworking. 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...

rootindex 为前端部署的根底,在默认状况下 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,因而须要 location2api 两个服务一起启动,在 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,若都是前缀匹配,则找到最长匹配的 locationserver {    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/shanyueHTTP/1.1 200 OKServer: nginx/1.21.4Date: Fri, 03 Jun 2022 10:15:11 GMTContent-Type: text/plainContent-Length: 15Last-Modified: Thu, 02 Jun 2022 12:44:23 GMTConnection: keep-aliveETag: "6298b0a7-f"X-Config: BAccept-Ranges: bytes

proxy_pass

proxy_pass 反向代理,也是 nginx 最重要的内容,这也是罕用的解决跨域的问题。

当应用 proxy_pass 代理门路时,有两种状况

  1. 代理服务器地址不含 URI,则此时客户端申请门路与代理服务器门路雷同。强烈建议这种形式
  2. 代理服务器地址含 URI,则此时客户端申请门路匹配 location,并将其 location 后的门路附在代理服务器地址后。
# 不含 URIproxy_pass http://api:3000;# 含 URIproxy_pass http://api:3000/;proxy_pass http://api:3000/api;proxy_pass http://api:3000/api/;

再举一个例子:

  1. 拜访 http://localhost:8300/api3/hello,与以下门路匹配胜利
  2. proxy_pass 附有 URI
  3. 匹配门路后多余的门路为 /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

管制响应头。

因为很多个性都是通过响应头管制,因而基于此指令可做很多事件,比方:

  1. Cache
  2. CORS
  3. HSTS
  4. CSP
  5. ...

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 有何区别