常用nginx配置

摘要

nginx常用的配置

常用设置

日志配置

1
2
3
4
5
log_format main '$time_iso8601|$remote_addr|$remote_user|$request_method|$uri|'
'$status|$request_time|$request_length|$body_bytes_sent|$bytes_sent|'
'$connection|$http_x_forwarded_for|$upstream_addr|$upstream_status|'
'$upstream_response_time|$args|$http_referer|$http_user_agent';
access_log logs/access.log main;

反向代理透传客户端IP设置

1
2
3
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;

全局变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$args #这个变量等于请求行中的参数。
$content_length #请求头中的Content-length字段。
$content_type #请求头中的Content-Type字段。
$document_root #当前请求在root指令中指定的值。
$host #请求主机头字段,否则为服务器名称。
$http_user_agent #客户端agent信息
$http_cookie #客户端cookie信息
$limit_rate #这个变量可以限制连接速率。
$request_body_file #客户端请求主体信息的临时文件名。
$request_method #客户端请求的动作,通常为GET或POST。
$remote_addr #客户端的IP地址。
$remote_port #客户端的端口。
$remote_user #已经经过Auth Basic Module验证的用户名。
$request_filename #当前请求的文件路径,由root或alias指令与URI请求生成。
$query_string #与$args相同。
$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相同。

Rewrite规则

rewrite 正则 替换 标志位

flag标记

rewrite指令的最后一项参数

  • last last是终止当前location的rewrite检测,但会继续重试location匹配并处理区块中的rewrite规则。
  • break break是终止当前location的rewrite检测,而且不再进行location匹配。
  • redirect 返回302临时重定向,浏览器地址会显示跳转后的URL地址。
  • permanent 返回301永久重定向,浏览器地址会显示跳转后的URL地址。
1
2
3
4
5
# 正则匹配
location ~ ^/(a|bb|ccc)/ {
rewrite ^/([a-z]+)/(.*)$ http://106.185.48.229/$2?$1;
}
# 注:用括号括起来的参数为后面的 $1 $2 变量

反向代理的路由策略

location 语法

1
location [=|~|~*|^~] /uri/ {…}
  • = 开头表示精确匹配,不支持正则。
  • ^~ 开头表示uri以某个常规字符串开头,不支持正则,理解为匹配url路径即可。
  • ~和~* 开头表示区分大小写的和不区分大小写的正则匹配。
  • !~和!~* 开头表示区分大小写不匹配及不区分大小写不匹配的正则匹配。
  • / 通用匹配,任何请求都会匹配,通常放着配置的最后。

匹配优先级

1
2
= > ^~ > ~, ~* > 空
全匹配 > 路径匹配 > 正则匹配 > 字符串匹配

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 字符串匹配
location /static {
alias /home/www/static;
access_log off;
}
# 路径匹配,此时proxy_pass的结束 / 决定是否带上匹配的路径
location ^~ /333/ {
proxy_pass http://106.185.48.229/;
}
# 正则匹配,此时proxy_pass不能带结束 /
location ~ ^/(xxx|yyy)/ {
proxy_pass http://106.185.48.229;
}
# 字符串匹配,此时proxy_pass的结束 / 决定是否带上匹配得路径
location /zzz/ {
proxy_pass http://106.185.48.229/;
}
# 默认匹配
location / {
proxy_pass http://127.0.0.1:8080;
}

http转https

rewrite

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 80;
server_name domain.com;
rewrite ^(.*)$ https://${server_name}$1 permanent;
#rewrite ^(.*) https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name domain.com;
ssl on;
ssl_certificate /etc/nginx/ssl/domain.com.crt;
ssl_certificate_key /etc/nginx/ssl/domain.com.crt;
# other
}

return

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
server_name domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name domain.com;
ssl on;
ssl_certificate /etc/nginx/ssl/domain.com.crt;
ssl_certificate_key /etc/nginx/ssl/domain.com.crt;
# other
}

error_page

1
2
3
4
5
6
7
8
9
10
server {
listen 80;
listen 443 ssl;
server_name domain.com;
ssl on;
ssl_certificate /etc/nginx/ssl/domain.com.crt;
ssl_certificate_key /etc/nginx/ssl/domain.com.crt;
# other
error_page 497 https://$server_name$request_uri;
}

常用虚拟主机配置

https

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
server {
listen 80;
server_name c.isme.pub;

access_log /data/logs/nginx_log/xxx_access.log moss;
error_log /data/logs/nginx_log/xxx_error.log error;

return 301 https://$server_name/$1;
#location / {
# proxy_pass http://0.0.0.0/;
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#}
}

server {
listen 443 ssl;
server_name c.isme.pub;
access_log /data/logs/nginx_log/xxx_access.log moss;
error_log /data/logs/nginx_log/xxx_error.log error;

ssl on;
ssl_certificate /usr/local/nginx/conf/ssl/wildcard-g7-20170629.crt;
ssl_certificate_key /usr/local/nginx/conf/ssl/wildcard-g7-20170629.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
#ssl_ciphers HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:demo-pay:4m;

location / {
proxy_pass http://0.0.0.0:80/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
#proxy_set_header Host $host;
#proxy_set_header X-Real-IP $remote_addr;
}
}

upstream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
upstream zabbix{
server 172.16.1.4:80;
}
server {
listen 80;

server_name zabbix.xxx.com;

access_log /data/logs/zabbix/zabbix_access.log ksformat;
error_log /data/logs/zabbix/zabbix_error.log;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header remote_addr $remote_addr;
proxy_pass http://zabbix;
}
}

location

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
server {
listen 80;
server_name c.isme.pub;
keepalive_timeout 120;

#access_log /data/logs/nginx_log/xxx_access.log moss;
#error_log /data/logs/nginx_log/xxx_error.log error;

location ~ ^/product/xxx/.+\.php$ {
access_log /data/logs/nginx_log/xxx_access.log moss;
error_log /data/logs/nginx_log/xxx_error.log;
if ($fastcgi_script_name ~ /product/xxx/(.*)) {
root /data/web_data/web/app/xxx/www/;
set $valid_fastcgi_script_name $1;
}
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$valid_fastcgi_script_name;
include fastcgi_params;
}

location /product/xxx/ {
access_log /data/logs/nginx_log/xxx_access.log moss;
error_log /data/logs/nginx_log/xxx_error.log;
alias /data/web_data/web/app/cat_elock/www/;
index index.htm;
}


location ~ ^/xxx/(.*)$ {
alias /data/web_data/web/app/xxx/app/zeus/public/;
try_files $uri $uri/ /index.php?$query_string;
index index.php index.html index.htm;
}

location / {
root /data/web_data/web/app/xxx/www/;
index index.php index.html index.htm;
}

location ~ \.php$ {
root /data/web_data/web/app/xxx/www/;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.html;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
include fastcgi_params;
}

location /php-fpm_status {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
include fastcgi_params;
}

location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Is-EDU 0;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://xxx;
}
}

通过url中不同参数定位到不同项目和不同环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location /www/ {
if ( $query_string ~* ^(.*)p=(.*?)&(.*)e=gt(.*)$ ) {
root /www/html/;
set $location $2;
set $env "gtest";
}
if ( $query_string ~* ^(.*)p=(.*?)&(.*)e=mt(.*)$ ) {
root /www/html/;
set $location $2;
set $env "mtest";
}
rewrite ^/www/(.*) /$location/$env/index.html?$query_string break;
try_files $uri /$location/$env/index.html?$query_string;
index index.html;
}

rewrite

1
2
3
4
5
6
7
8
9
10
11
location /xxx/
{
alias /www/html/xxx/;
try_files $uri /xxx/index.html;
if ( $uri ~ 'users' ){
rewrite ^/xxx/users /xxx/index.html;
}
if ( $uri ~ '' ) {
rewrite ^/xxx/$ https://xxxxxx
}
}

nginx做正向代理(透明代理)

  • 解决自定义端口问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
server {

listen 8088;
server_name isme-proxy;

access_log logs/isme_access.log isme;
error_log logs/isme_error.log;

resolver 8.8.8.8 valid=3600s;

proxy_connect;
proxy_connect_allow 443 563;
proxy_connect_connect_timeout 10s;
proxy_connect_read_timeout 10s;
proxy_connect_send_timeout 10s;


location / {
root html;
index index.html index.htm;
if ( $request ~ .*:.*(:[0-9]+)/.* ) {
set $port $1;
}
#default_type text/html;
#return 502 $port;
#proxy_pass http://$host$port;
proxy_set_header Host $host;
proxy_pass $scheme://$host$port$request_uri;
proxy_buffers 256 4k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
#proxy_next_upstream error timeout invalid_header http_502;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header REQUEST_URI $request_uri;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

nginx常用变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
$args                    #请求中的参数值
$query_string #同 $args
$arg_NAME #GET请求中NAME的值
$is_args #如果请求中有参数,值为"?",否则为空字符串
$uri #请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如"/foo/bar.html"。
$document_uri #同 $uri
$document_root #当前请求的文档根目录或别名
$host #优先级:HTTP请求行的主机名>"HOST"请求头字段>符合请求的服务器名.请求中的主机头字段,如果请求中的主机头不可用,则为服务器处理请求的服务器名称
$hostname #主机名
$https #如果开启了SSL安全模式,值为"on",否则为空字符串。
$binary_remote_addr #客户端地址的二进制形式,固定长度为4个字节
$body_bytes_sent #传输给客户端的字节数,响应头不计算在内;这个变量和Apache的mod_log_config模块中的"%B"参数保持兼容
$bytes_sent #传输给客户端的字节数
$connection #TCP连接的序列号
$connection_requests #TCP连接当前的请求数量
$content_length #"Content-Length" 请求头字段
$content_type #"Content-Type" 请求头字段
$cookie_name #cookie名称
$limit_rate #用于设置响应的速度限制
$msec #当前的Unix时间戳
$nginx_version #nginx版本
$pid #工作进程的PID
$pipe #如果请求来自管道通信,值为"p",否则为"."
$proxy_protocol_addr #获取代理访问服务器的客户端地址,如果是直接访问,该值为空字符串
$realpath_root #当前请求的文档根目录或别名的真实路径,会将所有符号连接转换为真实路径
$remote_addr #客户端地址
$remote_port #客户端端口
$remote_user #用于HTTP基础认证服务的用户名
$request #代表客户端的请求地址
$request_body #客户端的请求主体:此变量可在location中使用,将请求主体通过proxy_pass,fastcgi_pass,uwsgi_pass和scgi_pass传递给下一级的代理服务器
$request_body_file #将客户端请求主体保存在临时文件中。文件处理结束后,此文件需删除。如果需要之一开启此功能,需要设置client_body_in_file_only。如果将次文件传 递给后端的代理服务器,需要禁用request body,即设置proxy_pass_request_body off,fastcgi_pass_request_body off,uwsgi_pass_request_body off,or scgi_pass_request_body off
$request_completion #如果请求成功,值为"OK",如果请求未完成或者请求不是一个范围请求的最后一部分,则为空
$request_filename #当前连接请求的文件路径,由root或alias指令与URI请求生成
$request_length #请求的长度 (包括请求的地址,http请求头和请求主体)
$request_method #HTTP请求方法,通常为"GET"或"POST"
$request_time #处理客户端请求使用的时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
$request_uri #这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI,不包含主机名,例如:"/cnphp/test.php?arg=freemouse"
$scheme #请求使用的Web协议,"http" 或 "https"
$server_addr #服务器端地址,需要注意的是:为了避免访问linux系统内核,应将ip地址提前设置在配置文件中
$server_name #服务器名
$server_port #服务器端口
$server_protocol #服务器的HTTP版本,通常为 "HTTP/1.0" 或 "HTTP/1.1"
$status #HTTP响应代码
$time_iso8601 #服务器时间的ISO 8610格式
$time_local #服务器时间(LOG Format 格式)
$cookie_NAME #客户端请求Header头中的cookie变量,前缀"$cookie_"加上cookie名称的变量,该变量的值即为cookie名称的值
$http_NAME #匹配任意请求头字段;变量名中的后半部分NAME可以替换成任意请求头字段,如在配置文件中需要获取http请求头:"Accept-Language",$http_accept_language即可
$http_cookie
$http_host #请求地址,即浏览器中你输入的地址(IP或域名)
$http_referer #url跳转来源,用来记录从那个页面链接访问过来的
$http_user_agent #用户终端浏览器等信息
$http_x_forwarded_for
$sent_http_NAME #可以设置任意http响应头字段;变量名中的后半部分NAME可以替换成任意响应头字段,如需要设置响应头Content-length,$sent_http_content_length即可
$sent_http_cache_control
$sent_http_connection
$sent_http_content_type
$sent_http_keep_alive
$sent_http_last_modified
$sent_http_location
$sent_http_transfer_encoding

其他

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
log_format有一个默认的、无须设置的combined日志格式设置,相当于Apache的combined日志格式,其具体参数如下:


log_format combined '$remote_addr-$remote_user [$time_local]'

' "$request" $status $body_bytes_sent'

' "$http_referer" "$http_user_agent" ';



我现在使用的日志格式:

log_format access '$http_x_forwarded_for $remote_addr [$time_local] "http://$host" "$request" '
'$status $body_bytes_sent "$http_referer" "$http_user_agent" "$remote_user" ';

当日志文件中记录的值为"-"时,表示为空

access为自定义的日志格式的名称,使用时引用即可:

access_log /data/logs/nginx/ihouse_access.log access;

------------------------------------------------------------------------------------------------------

正确设置nginx中remote_addr和x_forwarded_for参数

什么是remote_addr:

remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,当你的浏览器访问某个网站时,假设中间没有任何代理,那么网站的web服务器(Nginx,Apache等)就会把remote_addr设为你的机器IP,如果你用了某个代理,那么你的浏览器会先访问这个代理,然后再由这个代理转发到网站,这样web服务器就会把remote_addr设为这台代理机器的IP

什么是x_forwarded_for:

正如上面所述,当你使用了代理时,web服务器就不知道你的真实IP了,为了避免这个情况,代理服务器通常会增加一个叫做x_forwarded_for的头信息,把连接它的客户端IP(即你的上网机器IP)加到这个头信息里,这样就能保证网站的web服务器能获取到真实IP

使用HAProxy做反向代理时:

通常网站为了支撑更大的访问量,会增加很多web服务器,并在这些服务器前面增加一个反向代理(如HAProxy),它可以把负载均匀的分布到这些机器上。你的浏览器访问的首先是这台反向代理,它再把你的请求转发到后面的web服务器,这就使得web服务器会把remote_addr设为这台反向代理的IP,为了能让你的程序获取到真实的客户端IP,你需要给HAProxy增加以下配置

option forwardfor

它的作用就像上面说的,增加一个x_forwarded_for的头信息,把客户端的ip添加进去,否则的话经测试为空值

如上面的日志格式所示:$http_x_forwarded_for 是客户端真实的IP地址,$remote_addr是前端Haproxy的IP地址

或者:

当Nginx处在HAProxy后面时,就会把remote_addr设为HAProxy的IP,这个值其实是毫无意义的,你可以通过nginx的realip模块,让它使用x_forwarded_for里的值。使用这个模块需要重新编译Nginx,增加--with-http_realip_module参数

./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module \ --with-http_realip_module --http-log-path=/data/logs/nginx/access.log --error-log-path=/data/logs/nginx/error.log

set_real_ip_from 10.1.10.0/24;

real_ip_header X-Forwarded-For;

上面的两行配置就是把从10.1.10这一网段过来的请求全部使用X-Forwarded-For里的头信息作为remote_addr,这样此时remote_addr就是客户端真实的IP地址

--------------------------------------------------------------

X-Forwarded-For 和 X-Real-IP 获取客户端的ip的区别:

一般来说,X-Forwarded-For是用于记录代理信息的,每经过一级代理(匿名代理除外),代理服务器都会把这次请求的来源IP追加在X-Forwarded-For中 来自4.4.4.4的一个请求,header包含这样一行 X-Forwarded-For: 1.1.1.1, 2.2.2.2, 3.3.3.3 代表 请求由1.1.1.1发出,经过三层代理,第一层是2.2.2.2,第二层是3.3.3.3,而本次请求的来源IP 4.4.4.4是第三层代理 而X-Real-IP,一般只记录真实发出请求的客户端IP,上面的例子,如果配置了X-Read-IP,将会是 X-Real-IP: 1.1.1.1 所以 ,如果只有一层代理,这两个头的值就是一样的