文章

Nginx Cookbook

本文记录 Nginx 常见需求的配置实现,用作备忘录。没有什么技术含量。

AND / OR

Nginx 不支持常见的逻辑运算符 &&, || 等,这种需求只能通过添加一个变量来实现。

AND

set $flag "";
if (<condition1>) {
    set $flag "${flag}1";
}
if (<condition2>) {
    set $flag "${flag}1";
}
if ($flag = "11") {
    # condition1 && conditon2
}

OR

set $flag "";
if (<condition1>) {
    set $flag "1";
}
if (<condition2>) {
    set $flag "1";
}
if ($flag = "1") {
    # condition1 || conditon2
}

更复杂的判断类似,通过添加标记字符串后进行判断。

请求域名判断

一个 vhost 绑定多个域名,根据访问域名的不同执行不同的操作。典型需求是其他域名 301 跳转主域名。

server
{
    listen 80;
    listen 443 ssl http2;
    server_name weargallery.app wg.chenhe.me wg.chenhe.cc;
    root /www/wwwroot/weargallery;

    if ($host != 'weargallery.app') {
      rewrite ^/(.*)$ https://weargallery.app/$1 permanent;
    }
}

SNI 动态选择证书

一个 vhost 绑定多个域名,且都开启 https。虽然 SAN 证书可以包含多个主机名,但如果域名本身就不同就没办法了。

利用 SNI,可以指示 Nginx 根据客户端请求的域名来使用对应的证书。

注意,在 ssl_certificatessl_certificate_key 属性中使用变量,需要存放密钥的文件夹有遍历权限 (x),只有读写的话会报 Permission Denied.

约定版

我们约定证书的名称为域名。

server
{
    listen 443 ssl http2;
    server_name weargallery.app wg.chenhe.me wg.chenhe.cc;

    ssl_certificate /www/cert/$ssl_server_name.cert;
    ssl_certificate_key /www/cert/$ssl_server_name.key;
}

$ssl_server_name 是 Nginx 内置变量,实际值就是客户端请求的域名。例如 'weargallery.app', 'wg.chenhe.cc'.

配置版

也可以手动指定每个域名对应哪个证书。

map $ssl_server_name $ssl_cert {
    default /www/cert/weargallery.app.cert; # 默认证书
    wg.chenhe.cc /www/cert/cc.cert;
  	wg.chenhe.me /www/cert/me.cert;
}
map $ssl_server_name $ssl_key {  } # 同理

ssl_certificate $ssl_cert;
ssl_certificate_key $ssl_key;

robots.txt

有时不方便以文件形式添加 robots.txt,例如一个反向代理服务。那么就可以用 Nginx 直接实现:

location = /robots.txt {
  default_type text/html;
  add_header Content-Type "text/plain; charset=UTF-8";
  return 200 "User-Agent: *\nDisallow: /";
}

常用内置变量

变量 注释 Example
http_* 任意请求头字段 $http_accept_language -> Accept-Language
scheme 协议 'http' / 'https'
request_method 请求方法 GET
request_uri [只读] 原始请求 URI,不包括主机名,包括参数 /admin/login?username=abc
is_args 请求是否有查询参数 有 - '?';没有 - ''
args 查询参数,不包括 '?' name=bob&age=33
arg_* 任意查询参数的值,参数名自动转小写
uri 不包括主机名与参数 /admin/login
remote_addr 客户端地址
remote_port 客户端端口