Day27-好用的网页服务器-nginx(三)

前言

昨天的文章讲完前端 Nginx 的写法後,今天就要来进入後端的写法啦!在昨天的小结提到後端的写法会用到 Nginx 其他的功能例如:负载平衡、反向代理等等,今天的文章就会一一介绍这些功能的写法,就让我们开始今天的文章吧!

後端 Nginx 写法

首先我们先来看个范例:

upstream backend {
  server 0.0.0.0:3000;
}

server {
  listen 3000;

  listen 443 default ssl;
  
  server_name xxx.com.tw;

  ssl_certificate /etc/nginx/ssl/tls.crt;
  ssl_certificate_key /etc/nginx/ssl/tls.key;

  root /app
  client_max_body_size 100m;
  charset utf-8;
 
  location /api {
    try_files $uri @proxy_to_backend;
  }
 
  access_log /var/log/nginx/django-access.log;
  error_log /var/log/nginx/django-error.log;

  sendfile on;
 
  server_tokens off;

  location @proxy_to_backend {
    proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto  $scheme;
    proxy_set_Header X-Real-IP $remote_addr;
    proxy_set_header Host   $http_host;
    proxy_redirect off;
    proxy_read_timeout 300;
    proxy_buffer_size 16k;
    proxy_buffers 4 16k;
    proxy_pass  http://backend;
  }
 
  location ~ /\.ht {
    deny all;
  }
}

可以看到後端的 Nginx 设定虽然跟前端的设定很像,但多出了几个没有看过的设定,接下来笔者会好好解释这几个不一样的设定,至於其他的设定有兴趣的读者可以看昨天的文章,笔者都有一一说明。

  • upstream

    upstream 简单来说就是设定分流,对於 server 而言所有网页打的 request 最终都会进到同一台 server 内,所以 server 对於 request 的分流可以说是相当重要,透过 Nginx 我们可以很轻松地做到负载平衡(Load Balancer)的功能,而这个写法就是 upstream

    upstream 的写法也很简单,首先要定义一个 server 让这个 Nginx 知道要分流时要导到哪个地方,由於笔者都是在 local 端进行设定所以这边就简单写成 0.0.0.0:8080 了,假如读者本身有多台机器并且有多个 domain,这时候就可以写多个 server 後面接不同的 domain 了,例如以下这样:

    upstream backend {
      server host1.com.tw;
      server host2.com.tw;
    }
    
  • server_name

    这边可以看到 server_name 加了一些限制进去了,不再是之前的 _ 对全部人开放,毕竟 api 的操作会直接对应到 server 端,所以加一些限制多少都有一些保护的作用在,通常这边都会设定是跟网址有关,必须要是该网址发的 request 才能被接收。

  • location

    可以发现这边的 location 设定又不太一样了,竟然没有像前端那样是根据 path 来决定显示内容,跑出了一段 location @proxy_to_backend,这究竟是什麽意思呢?

    首先可以看到这段:

    location /api {
      try_files $uri @proxy_to_backend;
    }
    

    可以发现上面这段跟前端的设定档有点像但是又有些地方不一样,跑出了 @proxy_to_backend,在 Nginx 中 @ 这个关键字代表着一个 named location,通常会使用 @ 这个关键字就是因为不是一个正常的 path 或者用 regular expression 定义的 path,所以当我们要使用 Nginx 提供的 reverse-proxy 功能就必须要用到这种方式。

    为了不跟前端的路由打架,因此这边通常都会定义一个後端专属的 path 并且把所有的 request 都经由 reverse-proxy 进行处理。

    接下来就要来定义 reverse-proxy 要做的内容了,前面提到 @ 这个关键字代表着一个 named location,所以可想而知前面会用一个 location 的关键字来处理这个 reverse-proxy 的内容,写法就像下面这样。

    location @proxy_to_backend {
      # 以下略
    }
    

    最後这边又多了一个 location 的定义:

    location ~ /\.ht {
      deny all;
    }
    

    看到 deny 这个字就很清楚是要拒绝某些东西了,所以上面这个 location 的写法简单来说就是当这个 request 我无法解析时,Nginx 就自动帮我全部拒绝吧,笔者觉得这段在後端的设定中是一定要加的,这样就可以减少很多 server 被误打的流量。

  • proxy 相关设定

    • proxy_set_header

      proxy_set_header 就是要设定一些 HTTP headers,基本上要设定的 Headers 方向很简单,就是要记录使用者是在从哪个 IP 来的,而这个设定的方法就可以藉由 X-Forwarded-For 以及 X-Real-IP 达成这项功能,而 X-Forwarded-Proto 最主要的功能就是把 header 的内容继续往下传递,最後由於我们有用了 upstream 进行分流设定,假如今天有两台 server 同时都跑一样的内容,因为 server 的 IP 都不一样会导致 request 的 host 看起来也不一样,这时候为了方便控管就可以利用 HOST $http_host 的方式进行设定。

    • proxy_redirect

      由於 reverse proxy server 会进行 url 的重新导向,为了不让重新导向的过程中发生错误,这时候我们可以设定 proxy_redirect,将这项功能关闭就不会进行任何的 url redirect。

    • proxy_read_timeout

      proxy_read_timeout 简单来说就是设定一个 timeout 当我的 response 回传时间过久的时候就把 connection 关闭不要再继续等了,这边的 timeout 时间是以 秒数(s) 为单位,读者这边在设定的时候要特别注意喔!

    • proxy_buffers

      我们都知道 server 很常会因为要处理多个 request 导致 response 回传结果变慢,这时候通常都会利用 cache 的方式来加速回传时间,而 Nginx 也有类似的作法那就是 buffering,透过 buffering 的大小设定就可以让同一个 request 的回传结果先暂存起来,这样就不用频繁的跟 server 拿资料了。

    • proxy_buffer_size

      proxy_buffer_size 就是用来设定 buffering 的大小。

    • proxy_pass

      proxy_pass 简单来说就是要把 request 导到 server 的 URL,但还记得上面写了一个 upstream 吗?由於我们在正上方已经先定义好分流的位置了,所以这时候的 proxy_pass 就可以写上 upstream 的名称,并且在前方加上 http:// 即可,就像下面这样:

      upstream backend {
        # 以下略
      }
      
      location @proxy_to_backend {
        proxy_pass: http://backend;
      }
      
  • access_log

    access_log 简单来说就是用来查看 access 到此 server 的 log,当 Nginx 启动时会预设开启这个 access_log 并且将档案摆放在 /etc/nginx 底下,透过 access_log 的设定可以很轻松的将这个 server 的 log 设定到指定的位置以及指定的档案名称非常方便。

  • error_log

    只要有 access 就一定会有机率会失败,想当然大家都不希望会失败这样就会显得这个 server 相当不稳定,这时候 Nginx 也有提供 error_log 的设定,就可以让工程师很轻松地知道自己的系统哪些环节有问题了,设定的方式也跟 access_log 一模一样。

  • sendfile

    sendfile 主要是用了 Linux 系统中的 sendfile 系统,透过 sendfile 我们可以加速档案的读取,让档案不会花很多时间在经过任何多余核心和使用者层级间的资料复制,可以直接从指定的装置输出,不过 nginx 预设是 off 所以这边如果要使用 sendfile 的话要记得设定成 on

  • server_tokens

    由於 server 都会有被攻击的可能性,既然我们都利用 Nginx 当作 reverse-proxy server 了,想当然我们也要关闭一些设定来降低 server 被攻击的可能性,而 server_tokens 就是个很好的例子,透过将 server_tokens 关闭的方式我们就可以隐藏 server 版本藉此拉高攻击者要攻击的成本。

小结

花了这麽多的时间终於把本系列文会用到的观念全部都说明一遍了,不晓得 Nginx 的观念会不会太难吸收呢?但目前如果都单纯只是介绍观念的话真的不太有感觉,毕竟还是要亲眼看到画面才比较有真实感,而且也可以确认自己终於会一些 DevOps 的技巧了,所以接下来剩下的几个篇幅笔者要来实作整个网站的前後端,并且利用前面所学的 Docker、K8s、Nginx 建立出一个网站出来。

如果对於文章有任何问题都欢迎留言给我,那我们就明天的文章见喽~


<<:  学习Python纪录Day27 - Regular Expression正规表达式

>>:  Day 27:如何写出一篇还不错的技术文章?

Day 10:快速排序(quicksort)

看完了分治法与递回,再来看这样的方法如何解决排序问题。 快速排序是一种利用分治法的演算法,比前面提到...

伫列 - DAY 9

伫列定义 具有线性串列结构,资料遵循着先进先出,後进後出的存取顺序 实际使用 一、手枪的子弹 二、电...

Day 30 - 下一段的旅途与系列文章总结

就这样写着写着来到了系列赛的最後一天,很开心能够坚持到最後撰写最後一天的文章,今日的分享会补充一下後...

利用大数据分析预测MLB胜负(中)

在上一篇文章中,我们介绍作者如何分析MLB赛事,并找出影响比赛胜负较为重要的因子,而今天我们就来看看...

[DAY-05] 开始减少控制 删除休假规定

当初看到这篇的时候 内心很激动! 因为 目前所属单位 部分模式是如此这般 :) 当然 团队成员都非...