Nginx 实操-常用配置

适配 PC 与 移动环境

现在很多网站都同时存在 PC 站和 H5 站,因此根据用户的浏览环境自动切换站点是很常见的需求。Nginx 可以通过内置变量 $http_user_agent,获取到请求客户端的 userAgent,从而知道用户处于移动端还是 PC 端,进而控制重定向到 PC 站 还是 H5 站,例如 PC 端站点为 example.com,H5 端站点为 h5.example.com,就可以在 PC 端配置 Nginx :

server {
  listen 80;
  server_name example.com;
  location / {
    root /usr/local/app/pc; #pc 的 html 路径
    #获取 userAgent
    if ($http_user_agent ~* '(Android|webOS|iPhone|iPad|BlackBerry)') {
      rewrite ^.+ http://h5.example.com;
    }
    index index.html;
  }
}

图片处理

在前端开发中,经常需要不同尺寸的图片。现在的云存储基本对图片都提供有处理服务(一般是通过在图片链接上加参数)。用 Nginx 可以通过几十行配置,搭建出一个属于自己的本地图片处理服务,完全能够满足日常对图片的裁剪、缩放、旋转、图片品质等处理需求。需要用到 ngx_http_image_filter_modulearrow-up-right 模块,这个模块是非基本模块,需要安装。此外还可以通过 proxy_cache 配置 Nginx 缓存,避免每次请求都重新处理图片,减少 Nginx 服务器处理压力,还可以通过和 nginx-upload-modulearrow-up-right 一起使用加入图片上传的功能。

图片缩放功能示例:

页面内容修改

Nginx 可以通过向页面底部或者顶部插入额外的 css 和 js 文件,从而实现修改页面内容。这个功能需要额外模块支持,例如 nginx-http-footer-filterarrow-up-right 或者 ngx_http_addition_modulearrow-up-right。工作中,经常需要切换各种测试环境,而通过 switchhosts 等工具切换后,有时还需要清理浏览器 dns 缓存。可以通过页面内容修改 + Nginx 反向代理来实现轻松快捷的环境切换。这里首先在本地编写一段 js 代码(switchhost.js)里面的逻辑是:在页面插入 hosts 切换菜单以及点击具体某个环境时,将该 host 的 ip 和 hostname 存储在 cookie 中,最后刷新页面;接着编写一段 css 代码(switchhost.css)用来设置该 hosts 切换菜单的样式。最后 Nginx 脚本配置:

这个功能其实为 Nginx 在前端开发中的应用提供了无限可能。例如,可以通过区分本地、测试和线上环境,为本地、测试环境页面增加很多开发辅助功能:给本地页面增加一个常驻二维码便于手机端扫码调试;本地调试线上页面时,在 js 文件底部加入 sourceMappingURL,便于本地 debug 等等。

请求限制

对于大流量恶意的访问,会造成带宽的浪费,给服务器增加压力。可以通过 Nginx 对于同一 IP 的连接数以及并发数进行限制。合理的控制还可以用来防止 DDos 和 CC 攻击。

关于请求限制主要使用 Nginx 默认集成的 2 个模块:

  • ngx_http_limit_conn_module 连接频率限制模块

  • ngx_http_limit_req_module 请求频率限制模块

涉及到的配置主要是:

  • limit_req_zone 限制请求数

  • limit_conn_zone 限制并发连接数

图片防盗链

简单有效的防盗链手段:referer 模块

使用场景例如某网站通过 url 引用了你的页面,当用户在浏览器上点击 url 时,http 请求的头部中会通过 referer 头部将该网站当前页面的 url 带上,告诉服务器本次请求是由这个页面发起的。通过 referer 模块,用 invalid_referer 变量根据配置判断 referer 头部是否合法。从而拒绝第三方网站访问我们站点的资源。referer 模块默认编译进 Nginx。

valid_referers 指令

语法 valid_referers none | blocked | server_names | string...

  • none 允许缺失 referer 头部的请求访问

  • block 允许 referer 头部没有对应的值的请求访问

  • server_names 若 referer 中站点域名与 server_name 中本机域名某个匹配,则允许该请求访问。

  • string 域名及 URL 如果是字符串,域名可在前缀或者后缀中含有 * 通配符,若 referer 头部的值匹配字符串后,则允许请求访问;域名如果是正则表达式,若 referer 头部的值匹配正则表达式后,则允许请求访问

valid_referers 指令后面可以同时携带多个参数,表示多个 referer 头部都生效。模块还会提供出一个 $invalid_referer 变量,允许访问时变量值为空,不允许访问时变量值为 1。

通过验证 URL 中哈希值的方式防盗链,该模块默认未编译进 Nginx。

实现的功能过程是由某服务器(也可以是 Nginx)生成加密后的安全链接 url,返回给客户端。客户端使用安全 url 访问 Nginx,由 Nginx 的 $secure_link 变量判断判断是否验证通过。

实现的原理是:

  • 哈希算法是不可逆的

  • 客户端只能拿到执行过哈希算法的 URL

  • 仅生成 URL 的服务器、验证 URL 是否安全的 Nginx 这二者,才保存执行哈希算法前的原始字符串

  • 原始字符串通常由以下部分有序组成:

    • 资源位置,例如 HTTP 中指定资源的 URI,防止攻击者拿到一个安全 URI 后可以访问任意资源

    • 用户信息,例如用户 IP 地址,限制其他用户盗用安全 URI

    • 时间戳,使安全 URI 及时过期

    • 密钥,仅服务器端拥有,增加攻击者猜测出原始字符串的难度

模块提供了两个变量:

  • $secure_link 值为空字符串,表示验证不通过,值为 0,表示 URL 过期,值为 1,表示验证通过

  • $secure_link_expires 时间戳的值

有两个参数,第一个参数是哈希值,第二个参数是时间戳

  • 首先使用命令行生成安全链接

    • 生成 MD5 echo -n '时间戳URL客户端IP密钥' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d = 例如 echo -n '2147483647/test1.txt116.62.160.193 secret' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =

    • 原请求 /test1.txt?md5=md5生成值&expires=时间戳(如 2147483647)

  • Nginx 配置

    • secure_link $arg_md5,$arg_expires;

    • secure_link_md5 "$secure_link_expires$uri$remote_addr secret";

secure_link_secret 指令

采用仅对 URI 进行哈希的简单办法。就是将请求 URL 分为三个部分:/prefix/hash/link,Hash 生成方式是对 "link 密钥" 做 md5 哈希求值,在 Nginx 中使用 secure_link_secret secret; 配置密钥。

  • 命令行生成安全连接

    • 原请求 link

    • 生成的安全请求 /prefix/md5/link

    • 生成 md5 echo -n 'linksecret' | openssl -md5 -hex 例如 echo -n 'test1.txtsecret2' | openssl md5 -hex

  • Nginx 配置

    • secure_link_secret secret2;

单页面项目 history 路由配置

请求过滤

过滤指定 user_agent

Nginx 可以禁止指定的浏览器和爬虫框架访问:

根据请求类型过滤

根据状态码过滤

这样实际上是一个内部跳转,当访问出现 502、503 的时候就能返回 50x.html 中的内容,这里需要注意是否可以找到 50x.html 页面,所以加了个 location 保证找到自定义的 50x 页面。

根据 URL 名称过滤

泛域名路径分离

这是一个非常实用的技能,我们可能需要配置一些二级或者三级域名,希望通过 Nginx 自动指向对应目录,比如:

  1. test1.com 自动指向 /usr/local/html/test1 服务器地址;

  2. test2.com 自动指向 /usr/local/html/test2 服务器地址;

Last updated