# 基本配置结构
# main 全局块
# events 块
events {
}
# http 块
http {
# http 全局块
# server 块
server {
# server全局块
# location 块
location [PATTERN] {
}
location [PATTERN] {
}
}
server {
# server全局块
# location 块
location [PATTERN] {
}
location [PATTERN] {
}
}
# http 全局块
}
- main 全局块:配置影响 nginx 全局的指令。一般有运行 nginx 服务器的用户组,nginx 进程 pid 存放路径,日志存放路径,配置文件引入,允许生成 worker process 数等。
- events 块:配置影响 nginx 服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。
- http 块:可以嵌套多个 server,配置代理、缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type 定义,日志自定义,是否使用 sendfile 传输文件,连接超时时间,单连接请求数等。
- server 块:配置虚拟主机的相关参数,一个 http 中可以有多个 server。
- location 块:配置请求的路由,以及各种页面的处理情况。
不同模块指令关系:server 继承 main;location 继承 server;upstream 既不会继承指令也不会被继承,它有自己的特殊指令,不需要在其他地方的应用。
# Rewrite
Nginx Rewrite 是利用 nginx 提供的全局变量或自己设置的变量,结合正则表达式和标志位实现 url 重写以及重定向。rewrite 只能放在 server{}, location{}, if{} 中,并且只能对域名后边的除去传递的参数外的字符串起作用,例如 http://seanlook.com/a/we/index.php?id=1&u=str
只对 /a/we/index.php 重写。语法 rewrite regex replacement [flag]
;
如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用 proxy_pass 反向代理。
表面看 rewrite 和 location 功能有点像,都能实现跳转,主要区别在于 rewrite 是在同一域名内更改获取资源的路径,而 location 是对一类路径做控制访问或反向代理,可以 proxy_pass 到其他机器。很多情况下 rewrite 也会写在 location 里,它们的执行顺序是:
- 执行 server 块的 rewrite 指令
- 执行 location 匹配
- 执行选定的 location 中的 rewrite 指令
如果其中某步 URI 被重写,则重新循环执行 1-3,直到找到真实存在的文件;循环超过 10 次,则返回 500 Internal Server Error 错误。
# Flag 标志位
last
: 相当于 Apache的[L] 标记,表示完成 rewritebreak
: 停止执行当前虚拟主机的后续 rewrite 指令集redirect
: 返回 302 临时重定向,地址栏会显示跳转后的地址permanent
: 返回 301 永久重定向,地址栏会显示跳转后的地址
因为 301 和 302 不能简单的只返回状态码,还必须有重定向的 URL,这就是 return 指令无法返回 301, 302 的原因了。这里 last 和 break 区别有点难以理解:
- last 一般写在 server 和 if 中,而 break 一般使用在 location 中
- last 不终止重写后的 url 匹配,即新的 url 会再从 server 走一遍匹配流程,而 break 终止重写后的匹配
- break 和 last 都能组织继续执行后面的 rewrite 指令
# if 指令与全局变量
if判断指令
语法为 if(condition) {...}
,对给定的条件 condition 进行判断。如果为真,大括号内的 rewrite 指令将被执行,if 条件(conditon)可以是如下任何内容:
当表达式只是一个变量时,如果值为空或任何以 0 开头的字符串都会当做 false
直接比较变量和内容时,使用
=
或!=
~
正则表达式匹配,~*
不区分大小写的匹配,!~
区分大小写的不匹配-f
和!-f
用来判断是否存在文件-d
和!-d
用来判断是否存在目录-e
和!-e
用来判断是否存在文件或目录-x
和!-x
用来判断文件是否可执行
栗子:
# 如果UA包含"MSIE",rewrite 请求到 /msid/ 目录下
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
# 如果 cookie 匹配正则,设置变量 $id 等于正则引用部分
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
}
# 如果提交方法为 POST,则返回状态 405(Method not allowed)。return 不能返回 301, 302
if ($request_method = POST) {
return 405;
}
# 限速,$slow 可以通过 set 指令设置
if ($slow) {
limit_rate 10k;
}
# 如果请求的文件名不存在,则反向代理到 localhost。这里的 break 也是停止 rewrite 检查
if (!-f $request_filename){
break;
proxy_pass http://127.0.0.1;
}
# 如果 query string 中包含"post=140",永久重定向到 example.com
if ($args ~ post=140){
rewrite ^ http://example.com/ permanent;
}
# 防盗链
location ~* \.(gif|jpg|png|swf|flv)$ {
valid_referers none blocked www.jefflei.com www.leizhenfang.com;
if ($invalid_referer) {
return 404;
}
}
全局变量
下面是可以用作if判断的全局变量:
$args
: #这个变量等于请求行中的参数,同$query_string$content_length
: 请求头中的Content-length字段。$content_type
: 请求头中的Content-Type字段。$document_root
: 当前请求在root指令中指定的值。$host
: 请求主机头字段,否则为服务器名称。$http_user_agent
: 客户端agent信息$http_cookie
: 客户端cookie信息$limit_rate
: 这个变量可以限制连接速率。$request_method
: 客户端请求的动作,通常为GET或POST。$remote_addr
: 客户端的IP地址。$remote_port
: 客户端的端口。$remote_user
: 已经经过Auth Basic Module验证的用户名。$request_filename
: 当前请求的文件路径,由root或alias指令与URI请求生成。$scheme
: HTTP方法(如http,https)。$server_protocol
: 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。$server_addr
: 服务器地址,在完成一次系统调用后可以确定这个值。$server_name
: 服务器名称。$server_port
: 请求到达服务器的端口号。$request_uri
: 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。$uri
: 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。$document_uri
: 与$uri相同。
栗子:
# http://localhost:88/test1/test2/test.php
$host = localhost
$server_port = 88
$request_uri = http://localhost:88/test1/test2/test.php
$document_uri = /test1/test2/test.php
$document_root = /var/www/html
$request_filename = /var/www/html/test1/test2/test.php
# 常用正则
.
: 匹配除换行符以外的任意字符?
: 重复0次或1次+
: 重复1次或更多次*
: 重复0次或更多次\d
: 匹配数字^
: 匹配字符串的开始$
: 匹配字符串的介绍{n}
: 重复n次{n,}
: 重复n次或更多次[c]
: 匹配单个字符c[a-z]
: 匹配a-z小写字母的任意一个
小括号 ()
之间匹配的内容,可以在后面通过 $1
来引用,$2
表示的是前面第二个 ()
里的内容。正则里面容易让人困惑的是 \
转义特殊字符。
# Rewrite 实例
WordPress 伪静态
if (-f $request_filename/index.html) { rewrite (.*) $1/index.html break; } if (-f $request_filename/index.php) { rewrite (.*) $1/index.php; } if (!-f $request_filename) { rewrite (.*) /index.php; }
PHPCMS 伪静态
rewrite ^/caipu-([0-9]+)-([0-9]+)-([0-9]+).html /index.php?m=content&c=index&a=show&catid=$1&id=$2&page=$3 last; rewrite ^/content-([0-9]+)-([0-9]+)-([0-9]+).html /index.php?m=content&c=index&a=show&catid=$1&id=$2&page=$3 last; rewrite ^/list-([0-9]+)-([0-9]+).html /index.php?m=content&c=index&a=lists&catid=$1&page=$2 last; rewrite ^/tag-([^\.]*)-([0-9]+)-([0-9]+).html /index.php?m=content&c=tag&catid=$2&tag=$1&page=$3 last; rewrite ^/comment-([0-9]+)-([0-9]+)-([0-9]+).html /index.php?m=comment&c=index&a=init&commentid=content_$1-$2-$3 last; rewrite ^/([^\.]*).html /index.php?m=member&c=index&a=$1 last;
DEDECMS 伪静态
rewrite "^/index.html$" /index.php last; rewrite "^/list-([0-9]+)\.html$" /plus/list.php?tid=$1 last; rewrite "^/list-([0-9]+)-([0-9]+)-([0-9]+)\.html$" /plus/list.php?tid=$1&totalresult=$2&PageNo=$3 last; rewrite "^/view-([0-9]+)-1\.html$" /plus/view.php?arcID=$1 last; rewrite "^/view-([0-9]+)-([0-9]+)\.html$" /plus/view.php?aid=$1&pageno=$2 last; rewrite "^/tags.html$" /tags.php last; rewrite "^/tag-([0-9]+)-([0-9]+)\.html$" /tags.php?/$1/$2/ last;
Discuz7 伪静态
rewrite ^/archiver/((fid|tid)-[\w\-]+\.html)$ /archiver/index.php?$1 last; rewrite ^/forum-([0-9]+)-([0-9]+)\.html$ /forumdisplay.php?fid=$1&page=$2 last; rewrite ^/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /viewthread.php?tid=$1&extra=page\%3D$3&page=$2 last; rewrite ^/space-(username|uid)-(.+)\.html$ /space.php?$1=$2 last; rewrite ^/tag-(.+)\.html$ /tag.php?name=$1 last;
DiscuzX 伪静态
rewrite ^([^\.]*)/topic-(.+)\.html$ $1/portal.php?mod=topic&topic=$2 last; rewrite ^([^\.]*)/article-([0-9]+)-([0-9]+)\.html$ $1/portal.php?mod=view&aid=$2&page=$3 last; rewrite ^([^\.]*)/forum-(\w+)-([0-9]+)\.html$ $1/forum.php?mod=forumdisplay&fid=$2&page=$3 last; rewrite ^([^\.]*)/thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=viewthread&tid=$2&extra=page%3D$4&page=$3 last; rewrite ^([^\.]*)/group-([0-9]+)-([0-9]+)\.html$ $1/forum.php?mod=group&fid=$2&page=$3 last; rewrite ^([^\.]*)/space-(username|uid)-(.+)\.html$ $1/home.php?mod=space&$2=$3 last; rewrite ^([^\.]*)/([a-z]+)-(.+)\.html$ $1/$2.php?rewrite=$3 last; if (!-e $request_filename) { return 404; }
PHPWind 伪静态
rewrite ^(.*)-htm-(.*)$ $1.php?$2 last; rewrite ^(.*)/simple/([a-z0-9\_]+\.html)$ $1/simple/index.php?$2 last;
SHOPEX 伪静态
if (!-e $request_filename) { rewrite ^/(.+\.(html|xml|json|htm|php|jsp|asp|shtml))$ /index.php?$1 last; }
Typecho 伪静态
if (-f $request_filename/index.html) { rewrite (.*) $1/index.html break; } if (-f $request_filename/index.php) { rewrite (.*) $1/index.php; } if (!-f $request_filename) { rewrite (.*) /index.php; }
Emlog 伪静态
if (!-f $request_filename) { set $rule_0 1$rule_0; } if (!-d $request_filename) { set $rule_0 2$rule_0; } if ($rule_0 = "21") { rewrite ^/(post|record|sort|author|page)-([0-9]+)\.html(.*)$ /index.php?$1=$2$3; rewrite ^/(post|record|sort|author|page)/([0-9]+)(.*)$ /index.php?$1=$2$3; rewrite ^/tag-(.+)\.html$ /index.php?tag=$1; rewrite ^/tag/(.+)$ /index.php?tag=$1; rewrite ^/t/page/([0-9]+)$ /t/index.php?page=$1; }
# 基本配置模板
########### 每个指令必须以分号结束 #################
# 配置用户或者组,默认为nobody nobody。
# user administrator administrators;
# 允许生成的进程数,默认为1
# worker_processes 2;
# 指定 nginx 进程运行文件存放地址
# pid /nginx/pid/nginx.pid;
# 制定错误日志路径,级别。这个设置可以放入全局块,http块,server块,级别依次为:debug|info|notice|warn|error|crit|alert|emerg
error_log log/error.log debug;
# 工作模式及连接数上限
events {
# 设置网路连接序列化,防止惊群现象发生,默认为on
accept_mutex on;
# 设置一个进程是否同时接受多个网络连接,默认为off
multi_accept on;
# 事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
# use epoll;
# 单个work进程允许的最大连接数,默认为512
worker_connections 1024;
}
# http服务器
http {
# 文件扩展名与文件类型映射表。设定mime类型(邮件支持类型),类型由mime.types文件定义
# include /usr/local/etc/nginx/conf/mime.types;
include mime.types;
# 默认文件类型,默认为text/plain
default_type application/octet-stream;
# 取消服务访问日志
# access_log off;
# 自定义日志格式
log_format myFormat '$remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for';
# 设置访问日志路径和格式。"log/"该路径为nginx日志的相对路径,mac下是/usr/local/var/log/。combined为日志格式的默认值
access_log log/access.log myFormat;
rewrite_log on;
# 允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。(sendfile系统调用不需要将数据拷贝或者映射到应用程序地址空间中去)
sendfile on;
# 每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
sendfile_max_chunk 100k;
# 连接超时时间,默认为75s,可以在http,server,location块。
keepalive_timeout 65;
# gzip压缩开关
# gzip on;
tcp_nodelay on;
# 设定实际的服务器列表
upstream mysvr1 {
server 127.0.0.1:7878;
server 192.168.10.121:3333 backup; #热备(其它所有的非backup机器down或者忙的时候,请求backup机器))
}
upstream mysvr2 {
# weigth参数表示权值,权值越高被分配到的几率越大
server 192.168.1.11:80 weight=5;
server 192.168.1.12:80 weight=1;
server 192.168.1.13:80 weight=6;
}
upstream https-svr {
# 每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题
ip_hash;
server 192.168.1.11:90;
server 192.168.1.12:90;
}
# error_page 404 https://www.baidu.com; #错误页
# HTTP服务器
# 静态资源一般放在nginx所在主机
server {
listen 80; #监听HTTP端口
server_name 127.0.0.1; #监听地址
keepalive_requests 120; #单连接请求上限次数
set $doc_root_dir "/Users/doing/IdeaProjects/edu-front-2.0"; #设置server里全局变量
#index index.html; #定义首页索引文件的名称
location ~*^.+$ { #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
root $doc_root_dir; #静态资源根目录
proxy_pass http://mysvr1; #请求转向“mysvr1”定义的服务器列表
#deny 127.0.0.1; #拒绝的ip
#allow 172.18.5.54; #允许的ip
}
}
# http
server {
listen 80;
server_name www.helloworld.com; # 监听基于域名的虚拟主机。可有多个,可以使用正则表达式和通配符
charset utf-8; # 编码格式
set $static_root_dir "/Users/doing/static";
location /app1 { #反向代理的路径(和upstream绑定),location后面设置映射的路径
proxy_pass http://zp_server1;
}
location /app2 {
proxy_pass http://zp_server2;
}
location ~ ^/(images|javascript|js|css|flash|media|static)/ { #静态文件,nginx自己处理
root $static_root_dir;
expires 30d; # 静态资源过时间30天
}
# 禁止访问 .htxxx 文件
location ~ /\.ht {
deny all;
}
# 直接简单粗暴的返回状态码及内容文本
location = /do_not_delete.html {
return 200 "hello.";
}
# 指定某些路径使用https访问(使用正则表达式匹配路径+重写uri路径)
location ~* /http* { #路径匹配规则:如localhost/http、localhost/httpsss等等
# rewrite只能对域名后边的除去传递的参数外的字符串起作用,
# 例如www.c.com/proxy/html/api/msg?method=1¶=2只能对/proxy/html/api/msg重写。
# rewrite 规则 定向路径 重写类型;
# rewrite后面的参数是一个简单的正则。$1代表正则中的第一个()。
# $host是nginx内置全局变量,代表请求的主机名
# 重写规则permanent表示返回301永久重定向
rewrite ^/(.*)$ https://$host/$1 permanent;
}
# 错误处理页面(可选择性配置)
# error_page 404 /404.html;
# error_page 500 502 503 504 /50x.html;
# 以下是一些反向代理的配置(可选择性配置)
# proxy_redirect off;
# proxy_set_header Host $host; # proxy_set_header用于设置发送到后端服务器的request的请求头
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $remote_addr; #后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
# proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
# proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
# proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
# proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
# proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
# proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
# proxy_temp_file_write_size 64k; #设定缓存文件夹大小,大于这个值,将从upstream服务器传
# client_max_body_size 10m; #允许客户端请求的最大单文件字节数
# client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数
}
# https
# - HTTPS的固定端口号是443,不同于HTTP的80端口;
# - SSL标准需要引入安全证书,所以在 nginx.conf 中你需要指定证书和它对应的 key
server {
listen 443;
server_name www.hellohttps1.com www.hellohttps2.com;
set $geek_web_root "/Users/doing/IdeaProjects/backend-geek-web";
# ssl 证书文件位置(常见证书文件格式为:crt/pem)
ssl_certificate /usr/local/etc/nginx/ssl-key/ssl.crt;
# ssl 证书 key 位置
ssl_certificate_key /usr/local/etc/nginx/ssl-key/ssl.key;
location /passport {
send_timeout 90;
proxy_connect_timeout 50;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_pass http://https-svr;
}
location ~ ^/(res|lib)/ {
root $geek_web_root;
expires 7d;
# add_header用于为后端服务器返回的response添加请求头,这里通过add_header实现CROS跨域请求服务器
add_header Access-Control-Allow-Origin *;
}
# ssl配置参数(选择性配置)
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
}
# 配置访问控制:每个IP一秒钟只处理一个请求,超出的请求会被delayed
# 语法:limit_req_zone $session_variable zone=name:size rate=rate
# (为session会话状态分配一个大小为size的内存存储区,限制了每秒(分、小时)只接受rate个IP的频率)
limit_req_zone $binary_remote_addr zone=req_one:10m rate=1r/s nodelay;
location /pay {
proxy_set_header Host $http_host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 访问控制:limit_req zone=name [burst=number] [nodelay];
# burst=5表示超出的请求(被delayed)如果超过5个,那些请求会被终止(默认返回503)
limit_req zone=req_one burst=5;
proxy_pass http://mysvr1;
}
# 可以把子配置文件放到/usr/local/etc/nginx/servers/路径下,通过include引入
include /usr/local/etc/nginx/servers/*.conf;
}