包括常用的一些 Nginx 示例和使用技巧,如果你在使用中遇到问题,欢迎去提 Issue 。

Nginx 状态码配置和错误文件

server {
    # 配置访问 /test.js 时报 403 错
    location /test.js {
        return 403;
    }
 
    # 配置访问 /404 时报 404 错
    location /404 {
        return 404;
    }
 
    # 配置访问 /500 时报 500 错
    location /500 {
        return 500;
    }
 
    # 把指定状态码指向这个文件 uri
    error_page 500 502 503 504 /status.html;
    error_page 404 /status.html;
}

如:

server {
    listen 80;
    server_name test.me;
 
    root /Users/xiaowu/work/test.me;
 
    # 用if匹配任何以 403 开头的,会匹配到 /4034444
    if ($request_uri ~* ^/403) {
        return 403;
    }
 
    # 用location匹配 /500/ /500,但不匹配 /500/1
    location ~* "^/500/?$" {
        return 500;
    }
 
    # 用if匹配以 /501/ 开头的,匹配 /501/1,/501/1/2 但不匹配 /501
    if ($request_uri ~* ^/501/) {
        return 501;
    }
 
    # 用location匹配 /502/ /502 /502/1 /502/1/2
    location ~* "^/502(/.*)?$" {
        return 502;
    }
 
    # 用location只匹配 /503
    location = /503 {
        return 503;
    }
}

#error_page配置小提示

注意 error_page 配置时加  =  和不加  =  的区别,加了 =  表示响应为指定的 http status code ,默认为 200,不加  = 为原错误的状态码~

# 这样可以访问错误页面时 http status 为 404 ,并且页面内容是 404.html 的内容
error_page 404 /404.html
error_page 404 500 /404.html;
 
# 这样配置访问错误页面时 http status 为 200 ,但页面内容是 404.html 的内容
error_page 404 500 = /404.html;
 
# 这样配置访问错误页面时 http status 为 404 ,但页面内容是 404.html 的内容
error_page 404 500 =404 /404.html;
 
# 也可以把404请求直接301到某个域上
error_page 404 =301 https://xuexb.com/404;

这样就可以根据自己需求配置错误页为指定的状态码,因为非 200 的状态码可能会被浏览器拦截。

主域301重定向

你的网站可能有多个域名访问,比如:www.xuexb.comxuexb.com 等,设置主域意思是不管用户输入哪个域名,都会 301 重定向到主域上,设置主域可以对 SEO 更友好,比如:

以xuexb.com为主域

www.xuexb.com => xuexb.com
www.xuexb.com/search/xxoo => xuexb.com/search/xxoo
www.xuexb.com/a/b/c/404.html => xuexb.com/a/b/c/404.html

配置文件核心:

server {
    # 设置多个域名
    server_name www.xuexb.com xuexb.com;
 
    # 判断host是不是xuexb.com,如果不是则直接301重定向,permanent表示301
    if ( $host != 'xuexb.com' ){
        rewrite ^/(.*)$ http://xuexb.com/$1 permanent;
    }
 
    # 其他规则
}

Node.js 反向代理

服务端如果使用nodejs运行服务,由于端口不能同时多个服务占用,而服务器中可能又是多个网站,那么可以使用 Nginx 做反向代理,比如有这些网站域名和端口:

域名端口
www.xxoo.com8001
www.xo.com8002
www.xo.cn8003

当然一个服务器上的网站可能还有更多,可以通过配置 Nginx 转发来代理这些端口分发,如:

server {
    server_name www.xxoo.com;
    listen 80;
 
    # 设置这个网站的根目录
    root /wwwroot/www.xxoo.com/;
 
    # 由于下面配置了文件不存在则代码到 Node.js 中,那么直接访问目录(不带默认主页)的话会有问题,这里做下判断
    # 如果访问目录下有 index.html 文件,则直接重写到该文件
    # break 表示重写且停止,但 url 不变,而 permanent 表示301重定向,url 会更新
    if ( -f $request_filename/index.html ){
        rewrite (.*) $1/index.html break;
    }
 
    # 如果请求的文件不存在,则代理到 Node.js
    if ( !-f $request_filename ){
        rewrite (.*) /index.js;
    }
 
    # 代理node服务 8001
    location = /index.js {
        # 设置一些代理的header信息,这些信息将被透传到 Node.js 服务的header信息里
        proxy_set_header Connection "";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
 
        # 代理服务
        proxy_pass http://127.0.0.1:8001$request_uri;
 
        # 忽略其他重写
        proxy_redirect off;
    }
}

配置之后,比如你网站根目录里有 index.html 文件,访问 url 如:

访问链接解析过程备注
www.xxoo.com/index.htmlNginx由于文件存在,直接使用 Nginx 输出
www.xxoo.comNginx由于判断该目录下有 index.html 文件,则自动重写到该文件,但 url 不变
www.xxoo.com/xx.htmlNginx Node.js:8001由于文件不存在,使用 Nginx 代理到 Node.js 的 8001 端口
www.xxoo.com/xxoo/Nginx Node.js:8001首先判断该目录是否存在
如果存在再判断是否有 index.html 文件
一旦不成立,直接代理到 Node.js

配置图片防盗链

防盗链是指当图片不是自己网站打开时返回 403 或者指定图片,是通过请求的来路判断是否是自己的站点来设置响应。

#语法

valid_referers none | blocked | server_names | string

  • none:表示没有来路
  • blocked:表示有来路
  • server_names:来路里包含当前域名
  • string:(忽略端口)

以上参数可以叠加一起使用。

#例子

server {
 
    # 配置所有图片
    location ~* \.(gif|jpg|png|bmp)$ {
        # 验证可以是没有来路、或者有来路时来路匹配xuexb.com、或者匹配当前域名
        valid_referers none blocked *.xuexb.com server_names;
 
        # 如果验证不通过则返回403
        if ($invalid_referer) {
            return 403;
        }
    }
}

配置 HTTPS

首先配置支持 HTTPS 必须让 Nginx 开启 http_ssl_module 模块,点击查看nginx编译安装参数 ,可以使用nginx -V查看是否开启TLS SNI support enabled

购买/生成 SSL 证书,可以使用免费的证书,比如:Let’s Encrypt,免费好用的 HTTPS 证书 。

# 配置 HTTPS
 
# 配置个http的站点,用来做重定向,当然如果你不需要把 HTTP->HTTPS 可以把这个配置删了
server {
    listen       80;
 
    # 配置域名
    server_name www.xxoo.com xxoo.com;
 
    # 添加 STS, 并让所有子域支持, 开启需慎重
    add_header strict-transport-security 'max-age=31536000; includeSubDomains; preload';
 
    # 配置让这些 HTTP 的访问全部 301 重定向到 HTTPS 的
    rewrite ^(.*) https://www.xxoo.com$1 permanent;
}
 
# 配置 HTTPS
server {
    # 配置域名
    server_name www.xxoo.com xxoo.com;
 
    # https默认端口
    listen 443;
 
    # 添加STS, 并让所有子域支持, 开启需慎重
    add_header strict-transport-security 'max-age=31536000; includeSubDomains; preload';
 
    # https配置
    ssl on;
    ssl_certificate /xxoo/www.xxoo.com.crt;
    ssl_certificate_key /xxoo/www.xxoo.com.key;
 
    # 其他按正常配置处理即可...
}

注意,这里证书的格式是 .crt 的。

#配置后的访问规则

#强烈推荐

使用 https://github.com/Neilpang/acme.sh 支持泛域名证书申请了,好赞。

配置泛域名转发

有的时候,我们需要配置一些自定义的子域名,如:

  • xuexb.user.demo.com
  • a01.user.demo.com

这时候就需要域名的 DNS 解析一个泛域名 *.user.demo.com 到服务器,Nginx 可以配置如下:

#子域名转发到子目录

server {
    listen       80;
    server_name ~^([\w-]+)\.user\.demo\.com$;
 
    location / {
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        Host $http_host;
        proxy_set_header        X-NginX-Proxy true;
        proxy_pass              http://127.0.0.1:8080/$1$request_uri;
    }
}

以上配置表示:

  • xuexb.user.demo.com/path?a=1  127.0.0.1:8080/xuexb/path?a=1
  • a01.user.demo.com/path?a=1  127.0.0.1:8080/a01/path?a=1

这样后端就可以根据子目录解析不同的规则,甚至 Nginx 可以再进行链接重写。

#子域名配置不同的目录

server {
    listen       80;
    server_name ~^([\w-]+)\.user\.demo\.com$;
 
    root /home/user/wwwroot/user/$1;
}

以上配置可以把不同的子域名分发到不同的目录中,做到路径分离的功能,如:

  • xuexb.user.demo.com  /home/user/wwwroot/user/xuexb;
  • a01.user.demo.com  /home/user/wwwroot/user/a01;

配置浏览器缓存

使用 expires 参数。

#不缓存

server {
    expires -1;
}

输出Response Headers:

Cache-Control:no-cache

当文件没有变更时会返回 304 ,有变更时会是 200 ,如果强制命中 200 可以再添加: if_modified_since off; 忽略 Request Headers 里的 If-Modified-Since 字段。

#缓存

server {
    expires 1d;
}

1d为1天,单位如下:

ms  milliseconds
s   seconds
m   minutes
h   hours
d   days
w   weeks
M   months,30 days
y   years,365 days

如果希望最大缓存可以:

server {
    expires max;
}

输出Response Headers:

Cache-Control:max-age=315360000

#根据链接设置缓存时间

server {
    # 设置为1月
    set $expires_time           1M;
 
    # 针对后台不缓存
    if ($request_uri ~* ^/admin(\/.*)?$) {
        set $expires_time       -1;
    }
 
    # 针对静态文件缓存最大
    if ($request_uri ~* ^/static(\/.*)?$) {
        set $expires_time       max;
    }
 
    # 设置吧
    expires $expires_time;
}

配置默认主页、目录浏览

设置默认主页

直接可以使用目录形式打开的页面称为默认主页,一般常见的有: index.htmlindex.htmindex.php 这些,要吧通过配置来完成,如:

server {
    root /网站根目录;
 
    # 设置默认主页,支持多个,按优先级来,空格分格
    index index.html index.htm index.php;
}

#设置目录浏览

当一个目录内没有默认主页的文件时,直接访问目录会报 403 Forbidden 错误,而启用目录浏览功能后可以直接列出当前目录下的文件、文件夹,如:

server {
    root /网站根目录;
 
    # 优先使用默认主页
    index index.html index.htm;
 
    # 当默认主页不存在时直接列出目录内文件树
    autoindex on;
}

但多 autoindex 相关可官方文档: http://nginx.org/en/docs/http/ngx_http_autoindex_module.html

注意,线上运行环境最好别开启该配置,因为这将直接暴露你的文件~