nginx配置进阶(三)
==============================================================================
概述:
本章我们将会继续介绍Nginx中http段的配置,内容主要包括:
ngx_http_fastcgi_module模块详解;
lnmp环境的部署;
定义fastcgi的缓存;
ngx_http_ssl_module模块:
配置nginx支持ssl的安全访问;
ngx_http_referer_module模块:防盗链功能
==============================================================================
ngx_http_fastcgi_module模块:构建lnmp
1.The ngx_http_fastcgi_module module allows passing requests to a FastCGI server.
★作用:
用于构建lnmp时,能够让nginx作为适配到fastcgi协议的客户端,从而能够连接至后端fpm的服务器,从而实现与fpm server进行通信
附图:
lnmp
★fastcgi_pass address;
address为fastcgi server的地址;
适用位置:location, if in location;
示例:
fastcgi_pass localhost:9000;
★fastcgi_index name;
fastcgi默认的主页资源;
★fastcgi_param parameter value [if_not_empty];
Sets a parameter that should be passed to the FastCGI server. The value can contain text, variables, and their combination.(传递给后端某一个服务器的变量的值,可以是字符串,也可以是变量,还可以是他们的组合)
[root@centos7 nginx]# cat fastcgi_params fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200;
⊙配置示例2:通过/pm_status和/ping来获取fpm server状态信息;
部署lnmp环境:
1.首先安装相关的部署程序包
# yum install php-fpm php-mysql mariadb-server php-gd php-mbstring php-mcrypt
2.php-fpm默认系统用户和组为apache,因为这里要使nginx与php-fpm相结合,所以我们需要修改php-fpm的配置文件/etc/php-fpm.d/www.conf 修改用户和组为nginx
[root@localhost ~]# cd /etc/php-fpm.d/ [root@localhost php-fpm.d]# ls www.conf [root@localhost php-fpm.d]# vim www.conf # 修改配置文件 user = nginx group = nginx pm.status_path = /pm-status # 启用状态页 ping.path = /ping # 启用ping和pong接口 ping.response = pong
3.创建/var/lib/php/session,并修改其属主和属组为nginx
[root@localhost ~]# mkdir /var/lib/php/session [root@localhost ~]# chown -R nginx:nginx /var/lib/php/session [root@localhost ~]# ll -d /var/lib/php/session drwxr-xr-x 2 nginx nginx 4096 10月 27 21:56 /var/lib/php/session
4.启动服务,并查看其对应端口,nginx/80,mairadb/3306,php-fpm/9000
[root@localhost ~]# systemctl start nginx [root@localhost ~]# systemctl start php-fpm [root@localhost ~]# systemctl start mariadb [root@localhost ~]# ss -tnl State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 127.0.0.1:9000 *:* LISTEN 0 50 *:3306 *:* LISTEN 0 128 *:80 *:* LISTEN 0 128 *:22 *:* LISTEN 0 128 127.0.0.1:631 *:* LISTEN 0 100 127.0.0.1:25 *:* LISTEN 0 128 127.0.0.1:6010 *:* LISTEN 0 128 :::22 :::* LISTEN 0 128 ::1:631 :::* LISTEN 0 100 ::1:25 :::* LISTEN 0 128 ::1:6010 :::*
5.接下来我们就可以配置nginx使用php-fpm了,配置如下:
1)/etc/nginx/conf.d/default.conf中自带有fastcgi的定义,我们直接启用就可以,然后稍作修改
2)修改如下:
location ~* \.php$ { # 上图匹配所有以.php结尾的文件区分大小写,这里改为不区分大小写 root /usr/share/nginx/html; # 默认为相对路径,这里最好改为绝对路径 fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; # 默认的主页面 # 请求时传递的脚本参数到后端,这里我们要给它一个真正的root路径下的url # 这里的url一定要转换成对应的后端服务器的网页文件的位置 fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/$fastcgi_script_name; include fastcgi_params; # 包含的另外一个配置文件 }
3)修改完成之后,检测语法,并重载nginx服务,然后提供页面文件
[root@localhost conf.d]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@localhost conf.d]# nginx -s reload [root@localhost conf.d]# cat << eof > /usr/share/nginx/html/phpinfo.php # 提供测试页 > <?php > phpinfo(); > ?> > eof [root@localhost conf.d]# cat /usr/share/nginx/html/phpinfo.php <?php phpinfo(); ?>
用浏览器访问如下:
6.接下来我们部署一个php的应用程序phpMyadmin,因为只是测试一下,所以我把之前部署在lamp上的phpMyadmin复制过来,如下:
[root@localhost ~]# ls /vhosts/www/ index.html index.php phpMyAdmin-4.0.5-all-languages pma test.html [root@localhost ~]# cp /vhosts/www/phpMyAdmin-4.0.5-all-languages/ /usr/share/nginx/html/ [root@localhost ~]# cd /usr/share/nginx/html/ [root@localhost html]# ln -sv phpMyAdmin-4.0.5-all-languages/ PMA "PMA" -> "phpMyAdmin-4.0.5-all-languages/" [root@localhost html]# ls 50x.html index.html phpinfo.php phpMyAdmin-4.0.5-all-languages PMA
使用浏览器访问如下:
提示客户端错误,原因为我们这里的默认主页面index.php虽然已经在location中定义,但是没有在server中定义,所以再次修改nginx的配置文件如下:
修改好之后,保存退出,检测语法重载之后,再次刷新页面,可以正常访问,如下图:
后面基于mysql的认证登录等就不在这里做演示了可以参考之前的文档;
7.接下来,我们使用ab命令来对文件中压测,看一下nginx接受并发响应的性能;
[root@localhost ~]# ab -c 100 -n 2000 http://192.168.1.17/PMA/index.php This is ApacheBench, Version 2.3 <$Revision: 1430300 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 192.168.1.17 (be patient) Completed 200 requests Completed 400 requests Completed 600 requests Completed 800 requests Completed 1000 requests Completed 1200 requests Completed 1400 requests Completed 1600 requests Completed 1800 requests Completed 2000 requests Finished 2000 requests Server Software: nginx/1.10.0 Server Hostname: 192.168.1.17 Server Port: 80 Document Path: /PMA/index.php Document Length: 8141 bytes Concurrency Level: 100 Time taken for tests: 121.663 seconds Complete requests: 2000 Failed requests: 0 Write errors: 0 Total transferred: 18691104 bytes HTML transferred: 16282000 bytes Requests per second: 16.44 [#/sec] (mean) Time per request: 6083.133 [ms] (mean) Time per request: 60.831 [ms] (mean, across all concurrent requests) Transfer rate: 150.03 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.6 0 4 Processing: 1020 5982 644.2 6032 9814 Waiting: 79 5896 649.1 5984 9814 Total: 1020 5982 643.8 6032 9815 Percentage of the requests served within a certain time (ms) 50% 6032 66% 6149 75% 6225 80% 6285 90% 6489 95% 6638 98% 6838 99% 7106 100% 9815 (longest request)
8.我们在php-fpm的配置文件中开启了测试功能(ping/pong)和状态页status,之前我们在httpd中是通过添加单独的匹配条件代理至后端的,那在nginx中我们应该怎样设置呢?如下:
如上,就为简单部署成功了一个lnmp环境了。。。
2.fastcgi的缓存
★fastcgi_cache_path path
☉格式和适用位置:
# Syntax: fastcgi_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time]; Default:— Context:http # 只能定义在http中☉作用:
定义fastcgi的缓存;缓存位置为磁盘上的文件系统,由path所指定路径来定义;
☉参数:
◆levels=levels:缓存目录的层级数量,以及每一级的目录数量;
levels=ONE:TWO:THREE 例如:leves=1:2:2(每一级为16进制数)
◆keys_zone=name:size
k/v映射的内存空间的名称及大小
缓存的组织方式:缓存是哈希值,而且对应的缓存文件名通常是文件内容的哈希内容,并且缓存层级是按照定义的多级结构去存放文件的;
◆inactive=time:非活动时长;
◆max_size=size:磁盘上用于缓存数据的缓存空间上限;
★fastcgi_cache zone | off;
作用:调用指定的缓存空间来缓存数据;
适用位置:http, server, location
★fastcgi_cache_key string;
作用:定义用作缓存项的key的字符串,通常为uri当变量;
★fastcgi_cache_methods GET | HEAD | POST ...;
作用:为哪些请求方法使用缓存;
★fastcgi_cache_min_uses number;
作用:缓存空间中的缓存项在inactive定义的非活动时间内至少要被访问到此处所指定的次数方可被认作活动项;
★fastcgi_cache_valid [code ...] time;
作用:不同的响应码各自的缓存时长;
定义使用缓存:
1.首先要创建一个缓存的文件目录,实际生产环境中可以放在固态磁盘上或者Raid0上,这样I/O能力很强;(注意文可能需要修改属主和属组为nginx)
[root@localhost ~]# ls /var/cache/ abrt-di fontconfig httpd krb5rcache libvirt nginx realmd cups gdm ibus ldconfig man PackageKit yum [root@localhost ~]# ls /var/cache/nginx/ client_temp fastcgi_temp proxy_temp scgi_temp uwsgi_temp [root@localhost ~]# mkdir /var/cache/nginx/fastcgi_cache
2.因为缓存只能定义在http配置段,所以编辑主配置文件/etc/nginx/nginx.conf
3.如上,已经定义好了,但是要想调用,要定义在在server或者location中,因为我们这里针对的是fastcgi协议所以定义在php的location中,如下:
4.定义好之后保存退出,检测语法,重载;然后用浏览器访问PMA,查看缓存如下
[root@localhost ~]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@localhost ~]# nginx -s reload [root@localhost ~]# tree /var/cache/nginx/fastcgi_cache/ /var/cache/nginx/fastcgi_cache/ └── 9 └── 0e └── 3 └── 9092aafd46eba60f9dd7f9eee97d30e9 3 directories, 1 file
再访问http://192.168.1.17/phpinfo.php,查看缓存如下:
[root@localhost ~]# tree /var/cache/nginx/fastcgi_cache/ /var/cache/nginx/fastcgi_cache/ ├── 0 │ └── 15 │ └── 4 │ └── 918e9e96dec978b2ec01d531bef84150 ├── 9 │ └── 0e │ └── 3 ├── e │ └── fd │ └── 5 │ └── 98413616be76ca2adb60d2de52405fde └── f └── a6 └── 5 └── f507ec3769c639b6261e1eb529305a6f
3.fastcgi 的保持连接
★fastcgi_keep_conn on | off;
By default, a FastCGI server will close a connection right after sending the response. However, when this directive is set to the value on, nginx will instruct a FastCGI server to keep connections open.
☉作用:
在并发压力较大的时候,向后端php-fpm开启保持连接是很有必要的,可以减轻nginx的压力;
ngx_http_ssl_module模块
1.支持nginx能够运行为https服务
★ssl on | off;
Enables the HTTPS protocol for the given virtual server.(是否在给定的虚拟主机上启用https协议)
★ssl_certificate file;
当前虚拟主机使用PEM格式的证书文件;
★ssl_certificate_key file;
当前虚拟主机上与其证书匹配的私钥文件;
★ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2];
支持ssl协议版本,默认为后三个;建议使用1.1版本
★ssl_session_cache off | none | [builtin[:size]] [shared:name:size];
builtin[:size]:使用OpenSSL内建的缓存,此缓存为每worker进程私有;
[shared:name:size]:在各worker进程之间使用一个共享的缓存;(性能更好一点,但是危险会更大一点)
★ssl_session_timeout time;
客户端一侧的连接可以复用ssl session cache中缓存 的ssl参数的有效时长;
配置示例:
把80端口重定向到443上,然后关闭80服务;
配置使ngins支持https协议:
1.在rpm包安装的nginx的配置文件中没有对ssl的相关配置,所以这里我们在/etc/nginx/conf.d下新定义一个虚拟主机使其支持ssl,配置如下:
[root@localhost conf.d]# pwd /etc/nginx/conf.d [root@localhost conf.d]# vim ssl.conf 1 server { 2 listen 443 ssl; # 指明ssl监听的端口443,和ssl协议 3 server_name # 主机名 4 root /vnhosts/ssl/htdocs; # ssl的路径 5 ssl on # 开启ssl功能 6 ssl_certificate /etc/nginx/ssl/nginx.crt; # 虚拟机使用的证书文件的路径 7 ssl_certificate_key /etc/nginx/ssl/nginx.key; # 与其证书匹配的私钥文件路径 8 ssl_session_cache shared:sslcache:20m; # 定义使用共享缓存,名字为sslcache,大小为20M 9 }
2.为了测试,首先在自己的主机上创建私有CA,但是在互联网上公开使用时,一定要找公共CA去签署
1)生成私钥文件
[root@localhost ~]# cd /etc/pki/CA [root@localhost CA]# ls certs crl newcerts private [root@localhost CA]# ls private/ [root@localhost CA]# (umask 077;openssl genrsa -out private/cakey.pem 4096) Generating RSA private key, 4096 bit long modulus ......++ ........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................++ e is 65537 (0x10001) [root@localhost CA]# ls private/ cakey.pem
2)生成自签证书
[root@localhost CA]# openssl req -new -x509 -key private/cakey.pem -out cacert.pem You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [XX]:CN State or Province Name (full name) []:Beijing Locality Name (eg, city) [Default City]:Beijing Organization Name (eg, company) [Default Company Ltd]:MageEdu Organizational Unit Name (eg, section) []:taotao.com Common Name (eg, your name or your server's hostname) []:ca.taotao.com Email Address []: [root@localhost CA]# ll 总用量 20 -rw-r--r-- 1 root root 2037 10月 28 21:14 cacert.pem drwxr-xr-x. 2 root root 4096 6月 29 2015 certs drwxr-xr-x. 2 root root 4096 6月 29 2015 crl drwxr-xr-x. 2 root root 4096 6月 29 2015 newcerts drwx------. 2 root root 4096 10月 28 21:05 private
3)为CA提供目录和文件
[root@localhost CA]# touch index.txt [root@localhost CA]# echo 01 > serial [root@localhost CA]# ls cacert.pem certs crl index.txt newcerts private serial
3.如上,创建CA完成,接下来要为nginx服务器签署CA请求
1)创建用于httpd通信时的私钥
[root@localhost CA]# cd /etc/nginx/ [root@localhost nginx]# ls conf.d koi-utf mime.types nginx.conf scgi_params win-utf fastcgi_params koi-win modules nginx.conf.bak uwsgi_params [root@localhost nginx]# mkdir ssl [root@localhost nginx]# cd ssl [root@localhost ssl]# (umask 077;openssl genrsa -out nginx,key 2048) Generating RSA private key, 2048 bit long modulus ......................+++ .................................................+++ e is 65537 (0x10001) [root@localhost ssl]# ls nginx,key # 创建成功
2)利用生成的私钥生成证书签署请求:
[root@localhost ssl]# openssl req -new -key nginx.key -out nginx.csr You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [XX]:CN State or Province Name (full name) []:Beijing Locality Name (eg, city) [Default City]:Beijing Organization Name (eg, company) [Default Company Ltd]:MageEdu Organizational Unit Name (eg, section) []:taotao.com Common Name (eg, your name or your server's hostname) []:www.taotao.com Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
4.接下来CA要为nginx签发证书(因为这里都是在本地主机生成的CA和httpd服务,所以不需要传送)
[root@localhost ssl]# openssl ca -in nginx.csr -out nginx.crt Using configuration from /etc/pki/tls/openssl.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 1 (0x1) Validity Not Before: Oct 28 13:29:07 2016 GMT Not After : Oct 28 13:29:07 2017 GMT Subject: countryName = CN stateOrProvinceName = Beijing organizationName = MageEdu organizationalUnitName = taotao.com commonName = www.taotao.com X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 8C:6E:F0:D0:2E:DF:52:22:6D:10:A9:25:74:BC:17:A5:2F:9C:42:DD X509v3 Authority Key Identifier: keyid:79:9F:37:3C:86:41:08:6D:1F:85:09:2B:59:C6:B6:0D:63:CC:5A:57 Certificate is to be certified until Oct 28 13:29:07 2017 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated [root@localhost ssl]# ls nginx.crt # 签署的证书 nginx.csr nginx.key
5.如上,证书签署完成我们只需把生成的证书nginx.crt发送给客户端即可,现在我们检测语法nginx的语法,重载,查看ssl的443端口是否监听;
[root@localhost ssl]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@localhost ssl]# nginx -s reload
[root@localhost ssl]# ss -tnl State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 127.0.0.1:9000 *:* LISTEN 0 50 *:3306 *:* LISTEN 0 128 *:80 *:* LISTEN 0 128 *:22 *:* LISTEN 0 128 127.0.0.1:631 *:* LISTEN 0 100 127.0.0.1:25 *:* LISTEN 0 128 127.0.0.1:6010 *:* LISTEN 0 128 *:443 *:* LISTEN 0 128 127.0.0.1:6011 *:* LISTEN 0 128 :::22 :::* LISTEN 0 128 ::1:631 :::* LISTEN 0 100 ::1:25 :::* LISTEN 0 128 ::1:6010 :::* LISTEN 0 128 ::1:6011 :::*
6.接下来我们为在nginx中定义的虚拟主机创建root的路径,并提供测试页面
[root@localhost ssl]# mkdir /vnhosts/ssl/htdocs -pv mkdir: 已创建目录 "/vnhosts" mkdir: 已创建目录 "/vnhosts/ssl" mkdir: 已创建目录 "/vnhosts/ssl/htdocs" [root@localhost ssl]# vim /vnhosts/ssl/htdocs/index.html <h1>SSL Host</h1>
在浏览器中访问如下:
由上图可知:有两点错误:
ip地址被标记为无效的安全证书,访问的url必须要为www.taotao.com,因为CA机构签署的是www.taotao.com;所以,要保证服务器和客户端都能解析这个地址,所以这里修改本地/etc/hosts文件,(因为我这里这台主机即为客户端又为服务端)使主机名能够解析;
提示证书颁发机构不被信任,因为我们是自建的CA机构,所以需要在浏览器中导入自建CA的证书文件/etc/pki/CA/cacert.pem,让浏览器信任我们自己创建的CA即可;
7.修改本地hosts文件,使其能够解析
[root@localhost ssl]# vim /etc/hosts 1 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 2 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 3 10.1.252.37 # 添加ip的解析
8.导入CA机构的自签证书
再次访问,可以正常访问,如下:
因为我们现在在配置文件中定义了多个server,所以,如果不基于https协议访问,而使用http访问,还是会访问默认的主页面,如下:
8.处于安全考虑,如果我想让用户访问网站都是通过https协议访问(即实现从80端口跳转到443端口)的话,就需要在另一个server添加rewritw重写uri,如下:
现在我们再去访问http://192.168.1.17,如下
这就是,为什么我们在平时访问网站时,明明使用的是http协议,但它会自动跳转使用到https协议,只不过是用到了rewrite重写罢了!!!
ngx_http_referer_module模块
1.用于阻挡来源非法的域名请求(防盗链)
★valid_referers none | blocked | server_names | string ...;
☉作用:
定义referer首部的合法可用值;
☉参数:
◆none:请求报文首部没有referer首部(也就是从浏览器中直接输入的);
◆blocked:请求报文的referer首部没有值;
◆server_names:参数,其可以有值作为主机名或主机名模式;
arbitrary_string:直接字符串,但可使用 * 作通配符;
regular expression:被指定的正则表达式模式匹配到的字符串;要使用 ~ 打头,
例如:~.*\.magedu\.com;
示例:
valid_referers none blocked server_names *.example.com example.* www.example.org/galleries/ ~\.google\.; if ($invalid_referer) { return 403; }
演示:
解析:
以上所有符合none,blocked,taotao.com、tao.com域名和域名中包含mgedu和firefox的站点都可以访问到当前站点的内容,如果来源域名不在这个列表中,那么$invalid_referer等于1,在if语句中返回一个403给用户,这样用户便会看到一个403的页面,如果使用下面的rewrite,那么盗链的内容都会被重写到www.taotao.com的主页面。
测试:
使用curl命令模拟从tao.com magedu.com 和baidu.com跳转而来,结果发现前两个跳转都可以正常访问到内容,而从baidu跳转过来的则不能访问
[root@localhost conf.d]# curl -k -e "http://www.tao.com" "https://www.taotao.com/index.html" <h1>SSL Host</h1> [root@localhost conf.d]# curl -k -e "http://www.magedu.com" "https://www.taotao.com/index.html" <h1>SSL Host</h1> [root@localhost conf.d]# curl -k -e "http://www.baidu.com" "https://www.taotao.com/index.html" <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> # 不能正常访问返回结果为403 Forbidden <hr><center>nginx/1.10.0</center> </body> </html>