Nginx用起来比Apache方便简介,也有很多超过Apache的地方。Nginx不仅可以作为http服务器来用,更重要的,它还可以用来做负载均衡和反向代理。Nginx官方文档
- 正向代理:类似fq,服务器代替我们去访问其他的服务
- 反向代理:外部访问内部服务,例如外部用户访问公司内部的各个服务,通过一个nginx进行代理
安装nginx
安装方法见: nginx安装方法
如果要安装最新稳定版nginx,可以添加这个源:
1 | [nginx] |
Web项目目录的常用权限
1 | find /A -type d -exec chmod 0755 {} \; |
配置文件详解
fastcgi
和http
的区别是,前者是一个二进制协议,并且是长连接,http不是长连接。
nginx配置文件地址在/etc/nginx/nginx.conf
,nginx的配置文件里,最重要的section是http区块,里面包含了全局设置、主机设置(server)、上游服务器设置(upstream)、URL设置
1 | user www-data; # nginx所属用户 |
负载均衡配置
1 | # 在http里定义upstream |
端口转发配置/获取真实IP
proxy_set_header
几个配置可以让程序获取到真实的用户IP,而不是多级代理时候的nginx
内网地址
1 | 在server里: |
单独的虚拟目录配置
最好将单独的域名放到单独的配置文件中/etc/nginx/conf.d/test.conf
1 | server{ |
自定义日志格式
- 日志的一些变量:
$host
访问的域名$remote_addr/$http_x_forwarded_for
客户端IP地址$time_local
访问时间$status
访问状态码$upstream_response_time
应用返回到Nginx的时间$request_time
请求时间$http_referer
请求来源$http_user_agent
访问客户端$body_bytes_sent
返回给客户端的大小
nginx
的默认日志格式为
1 | log_format '$remote_addr - $remote_user [$time_local] ' |
将真实IP记录在日志中,而不是代理的日志(需要设置proxy_set_header
等信息,参考代理配置):
1 | # my_format即是自己定义的日志格式别名 |
Rewrite规则
是一种以正则方式重写url的语法
关于uri的变量
1
2
3
4
5
6
7
8
9
10
11
12
13request_uri # 包含请求参数的原始uri,例如/nginx.php?id=123
uri # 不带请求参数的原始uri,例如/nginx.php
document_uri # 同上
args # 请求参数
query_string # 同上
content_length
content_type
host
http_cookie
request_method
scheme # http或https
server_name
server_PORT有如下几种重写类型:
- last: 表示完成rewrite,浏览器地址栏URL不变。一般用在server和if中。不会终止匹配,新的url会重新从server匹配一遍。
- break: 本条规则匹配完成后终止匹配,不再匹配后面的规则,浏览器地址栏URL不变。一般用在location中,会终止匹配,只会往下走,不会整个server重新匹配。
- redirect: 返回302临时重定向,浏览器地址栏URL变成转换后的地址
- permanent: 返回301永久重定向,浏览器地址栏URL变成转换后的地址
1 | # 如果用户访问/test/abc,直接重定向到/abc并且使用test这个upstream |
如果怎么
rewrite
程序都获取不到正确的请求地址,例如CI框架,那么可能是应用程序读取的是REQUEST_URI
而不是proxy_pass
过去的地址,可以这样传递以改变$request_uri
的值: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
26set $request_url $request_uri;
if ($request_uri ~ ^/admin/(.*)$ ) {
set $request_url /$1;
}
location /v2 {
set $request_url $uri; # 如果要给所有请求加一个前缀,可以这样做
rewrite ^/v2/(.*)$ /$1 last;
}
location /admin {
set $request_url $uri;
rewrite ^/admin/(.*)$ /$1 last;
}
location / {
try_files $uri $uri/ /index.php; # try_files指令回按顺序检查文件是否存在,返回第一个找到的文件或文件夹
}
location ~* \.php$ {
rewrite ^/admin/(.*)$ /$1 break;
include test/fastcgi-php.conf;
fastcgi_param REQUEST_URI $request_url;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
去掉uri中的一段
- 例如用户访问
/abc/def.html
,我们将其重定向到/def.html
1 | # 方法一 |
重定向指定文件的访问
例如,重定向favicon.ico文件
1 | location /favicon.ico { |
配置nginx IP黑白名单
新建配置文件/etc/nginx/blockips.conf
,内容格式如下
1 | deny 1.1.1.1; # 屏蔽单个IP |
然后在nginx主配置文件/etc/nginx/nginx.conf
的http
中导入该文件include blockips.conf;
HTTPS证书配置
1 | server { |
本地localhost开启https/ssl
配置流程主要参考的是local-cert-generator
生成根证书
1
2openssl genrsa -des3 -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 7300 -out rootCA.pem打开MacOS的
Keychain Access
然后点击左下角Category->Certificates
,然后点击顶部菜单File->Import Items
选择刚才生成的rootCA.pem
,然后双击,选择始终信任该证书:签发证书
1
2openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key -config server.csr.cnf # server.csr.cnf见https://github.com/dakshshah96/local-cert-generator/blob/master/server.csr.cnf
openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 825 -sha256 -extfile v3.ext # v3.ext见https://github.com/dakshshah96/local-cert-generator/blob/master/v3.ext把上一步生成的证书配置到
nginx
中即可1
2
3
4
5
6
7
8
9
10
11server {
listen 443 ssl;
charset utf-8;
server_name localhost;
ssl_certificate /etc/nginx/conf.d/server.crt;
ssl_certificate_key /etc/nginx/conf.d/server.key;
location / {
proxy_pass http://127.0.0.1:8000; # 这里是服务的地址
}
}
Nginx直接返回文本/Json
1 | location ~ ^/json { |
Nginx根据日期转发/Nginx获取日期
1 | location = / { |
Nginx编写.htaccess
- 其实不算是
.htaccess
就是一个配置文件而已 - 需要在项目目录下新建
.htaccess
,语法需要是nginx
的语法,而不是apache
的 - 然后在
nginx
该server
配置中include
该文件即可
返回stream响应
1 | location / { |
查看负载均衡状态
nginx提供了默认的模块可以查看负载均衡的统计信息等,只需要在某个server里面添加:
1 | location /nginx { |
其中htpasswd是保存用户名和密码的文件,可以自定义位置,每一行一个用户username:password
这样子保存的,使用crypt3(BASE64)加密,可以用一个PHP文件来生成
$password = 'hehe';
$password = crypt($password, base64_encode($password));
echo $password;
最后访问 http://...../nginx 即可看到如下的负载均衡信息:
Active connections: 1
server accepts handled requests
2 2 37
Reading: 0 Writing: 1 Waiting: 0
常用模块
nginx-http-concat: 合并前端资源
前端可以直接访问/js/??jquery.js,index.js,second.js
同时获取三个js文件,而不用发送三个请求了
TroubleShooting
CentOS下出现负载均衡出现错误:(13: Permission denied) while connecting to upstream:[nginx],直接执行如下命令:
1
2sudo cat /var/log/audit/audit.log | grep nginx | grep denied | audit2allow -M mynginx
sudo semodule -i mynginx.pp # 貌似在SELinux下,auditallowk可以讲禁止的规则加入到信任php-fpm
没有打印错误日志,仅仅有访问日志,原因是php-fpm默认是关闭workder进程的错误输出,重定向到了/dev/null
,所以在errlog里面看不到我们想看的日志,需要做以下更改:1
2
3
4
5
6
7
8vim /etc/php-fpm.conf
[www]
catch_workers_output = yes # 更改为yes
vim /etc/php.ini
log_errors = On
error_log = /var/log/error_log
error_reporting=E_ALLHTTP Header中后端服务无法获取有下划线的header: 没错,无论是
Nginx
还是Apache
,都是不允许的(在HTTP标准中倒是允许的),因为Nginx
的配置文件中的变量都是下划线的,容易引起混淆,当然也可以用underscores_in_headers on
参数进行开启,不过不建议。client intended to send too large body: 客户端发送的数据量太大,可以通过更改
http
模块中的client_max_body_size 1m;
参数,默认为1m
,看实际需要调整**upstream sent too big header while reading response header from upstream: **原因是
upstream
那边响应头过大,可以在server/location
配置里面适当加大响应缓存大小:1
2fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;Nginx报错504 gateway timeout: 首先当然是看业务是否需要那么长的时间,如果实在需要,可以在nginx配置中修改如下参数:
1
2
3
4
5
6
7
8
9fastcgi模式
fastcgi_connect_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_read_timeout 300s;
proxy模式
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;上述timeout都不起作用: 看看会不会是aws的负载均衡器设置了超时时间的。MMP,ClashX可能也会导致刚好1分钟60秒超时的问题
Nginx报错502 Bad Gateway:
方法一:检查upstream是否正常
方法二:修改了timeout参数
方法三:可以尝试在nginx配置中提高这两个fastcgi参数:1
2fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;方法四:如果是docker里面的nginx,查看网页上是否访问到代理的IP上面去了
wordpress无限重定向: 可能是在aws的elb中只发了http请求到后端,但是url访问的却是https,导致wordpress搞不清楚了,可以在nginx这边加上一个fastcgi配置:
1
fastcgi_param HTTPS on;
改了各种配置都还是499错误 发现关了代理就好了,mmp