IO:模型
nginx: web服务器 反向代理:代理web,mail tengine:淘宝的nginx varnish,squid:缓存服务器 nginx:缓存在磁盘上和memcached httpd:缓存在磁盘和内存上。
nginx热部署:平滑升级
安装nginx:
yum groupinstall "Development Tools" "Server Platform Development"
yum install pcre-devel openssl-devel
groupadd -r -g 108 nginx user -r -g 108 -u 108 nginx
tar -zxvf nginx-1.41.tar.gz cd nginx-1.41 ./configure --prefix=/usr --sbin-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx/nginx.pid --lock-path=/var/log/nginx.lock --user=nginx --group=nginx --with-http_ssl_module --with-http_flv_module --with-http_stub_status_module --with-http_gizp_static_module --http-client-temp-path=/var/tmp/nginx/client --http-proxy-temp-path=/var/tmp/nginx/proxy/ --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi --http-scgi-temp-path=/var/tmp/nginx/scgi --http-scgi-temp-path=/var/tmp/nginx/scgi --with-pcre=/usr --with-file-aio
make && make install
采用源码rpm包安装:
rpm -ivh nginx-1.4.1-1.el5.ngx.src.rpm cd /usr/src/redhat/SPECS/ vim nginx.spec
rpmbuild -ba nginx.spec
nginx: server{}:虚拟主机 location{}:
location /URI/ {
root "/web/htdocs";
}
httpd: <DocumentRoot "">
</DocumentRoot>
<location "/bbs">
</location>
URI路径:
nagle算法:主要解决网络拥塞
每一个server{}:定义一个虚拟主机 location{}:
location /uri/ { root “/web/htdocs”; }
httpd: 基于本地文件系统的路径:<documentroot "">
</documentroot>
定义uri路径:<location "/bbs"> </location> uri路径:http://www.baidu.com/(从这里开始后面就称uri路径)
location [ =| ~| ~*| ^~ ] uri{...}
location uri{}:对当前路径及子路径下的所有对象都生效
location = uri {}:精确匹配指定的路径,不包括子路径,因此,只对当前资源生效
location ~ uri {}: location ~* uri {}: 模式匹配uri,此处的uri可使用正则表达式,~区分字符大小写,~*不区分字符大小写:
location ^~ uri {}:不使用正则表达式
location / { root /web/htdocs; }
location /bbs/ { root /web; }
访问控制: 基于IP模式的访问控制 location / { root /web/htdocs; deny 192.168.1.25; }
location / { root /web/htdocs; allow 192.168.1.25; deny all; }
基于用户模式的访问控制 location / { root /web/htdocs; auth_basic "Restricted Area..."; auth_basic_user_file /etc/nginx/.users; autoindex on; }
httppasswd -cm /etc/nginx/.users tom
location /status { stub_status on; }
http://192.168.1.28/status
其status各项表示的意思:已经接受的连接的个数,已经处理的连接的个数,已经连接的请求的个数 reading:nginx正在读取其首部请求的个数; writing:nginx正在读取其主体的请求的个数,或正处理着其请求响应的内容的请求的个数或者正在向其客户端发送响应的个数; waiting:长连接模式的保持的连接个数
建立证书颁发签署机构: 1.制作私钥 vim /etc/pki/openssl.cnf [CA_default] dir = /etc/pki/CA
cd /etc/pki/CA mkdir certs crl newcerts private
(umask 077;openssl genrsa 2048 > private/cakey.pem)
2.生成自签名证书: openssl req -new -x509 -key private/cakey.pem -out cacert.pem
touch serial echo 01 > serial touch index.txt
用户向证书颁发机构申请签署证书: cd /etc/nginx mkdir ssl cd ssl
1.制作私钥 (umask 077;openssl genrsa 1024 > nginx.key)
2.生成向证书颁发机构的证书签署请求 openssl -req -new -key nginx.key -out nginx.csr
3.证书机构签署证书签署请求 openssl ca -in nginx.csr -out nginx.crt -days 3650
server { listen 443; server_name localhost; ssl on; ssl_cerificate /etc/nginx/ssl/nginx.crt; ssl_session_key /etc/nginx/ssl/nginx.key; ssl_protocols SSLv2 SSLv3 TLSv1;
location / {
root /web/htdocs;
index index.html index.htm;
} }
虚拟主机: server { listen 80; server_name sina.uplook.com; location / { root /sina; index index.html; }
LEMP: php-fpm: 127.0.0.1:9000
nginx+PHP+MySQL vim /etc/php.ini vim /etc/php-fpm.conf vim /etc/init.d.php-fpm
tar -zxvf mysql-5.6.10-linux-glibc2.5-i686.tar.gz -C /usr/local
mkdir /mydata/data useradd -r mysql chown -R mysql.msyql /mydata/data cd /usr/local ln -sv mysql-5.6.10 mysql chown -R root.mysql ./* scripts/mysql_install_db --user=mysql --datadir=/mydata/data/ vim /etc/my.cnf datadir = /mydata/data innodb_file_per_table = on log-bin = master-bin socket = /tmp/mysql.sock
cp support-files/mysql.server /etc/init.d/mysqld
service mysqld start
vim /etc/ld.so.conf.d/mysql.conf /usr/local/mysql/lib
ldconf -v
ln -sv /usr/local/mysql/include /usr/include/mysql
tar -jxvf php-5.4.13.tar.bz2 cd php-5.4.13 ./configure --prefix=/usr/local/php --with-mysql=/usr/local/mysql --with-openssl --enable-fpm --enable-sockets --enable-sysvshm --with-mysqli=/usr/local/mysql/_config --enable-mbstring --with-freetype-dir --with-png-dir --with-zlib-dir --with-libxml-dir=/usr --enable-xml --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d --with-bz2 --with-curl
make && make install
cp php.ini-production /etc/php.ini cd /usr/local/php/etc/ cp php-fpm.conf.default php-fpm.conf
cd /root/php-5.4.13/ cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
service php-fpm start
整合nginx和php vim /etc/nginx/nginx.conf location ~ .php$ { root /web/htdocs; index index.php index.html fastcgi_pass 127.0.0.1:9000;(用来定义代理的) fastcgi_index index.php; fastcgi_param script_filename ..; include fastcgi_params; }
vim /etc/nginx/fastcgi_params fastcgi_param ... fastcgi_param ... fastcgi_param ... fastcgi_param ... fastcgi_param ... fastcgi_param ... fastcgi_param ...
vim /web/htdocs/index.php <?php phpinfo(); ?>
IO模型: 阻塞:等待 非阻塞:一直轮询 同步:把数据获取到以后在离开 异步:获取数据的时候,可以不用等到获取后在离开
同步阻塞:
异步阻塞:IO复用
同步非阻塞:event-driven
异步非阻塞:AIO
nginx: mmap event-driven 一个进程响应多个请求;单线程进程
memcached:万金油,存储可序列化数据string,object,key:value hash bucket,O(1)
redis:databases,nosql
lvs nginx haproxy
LEMP: enginx web:nginx,lnmp,memcached,haproxy,tomcat,varnish
location ~* .php$ { fastcgi_pass 127.0.0.1:9000; }
fastcgi
nginx配置文件 main, worker_process error_log user group
events {
} 事件驱动
httpd {
} 关于http相关的配置
server {
} 虚拟主机
location uri { directive <parameters>; } uri访问属性
上下文
server { listen 80; server_name www.maoshou.com location / { 后端服务器; } }
反向代理: proxy_pass
location [op] URI { http://172.16.100.11/; }
~ ~* ^~
location @name
location /forum/ { proxy_pass http://172.16.100.11:8080/bbs/; }
http://www.magedu.com/forum/ --->http://172.16.100.11:8080/bbs/
location ~* ^/forum { proxy_pass http://172.16.100.11:8080; }
http://www.magedu.com/forum/ ---> http://172.16.100.11:8080/forum
vim /etc/nginx.conf location /forum/ { proxy_pass http://172.16.100.6/bbs/; } 在172.16.100.6上mkdir /var/www/html/bbs
vim /etc/nginx.conf location ~* /forum { proxy_pass http://172.16.100.6; proxy_set_header X-Real-IP $remote_addr; } 在 172.16.100.6上mkdir /var/www/html/forum
vim /etc/http.conf LogFormat "%{X-Real-IP}i" ...
proxy_set_header X-real-IP $remote_addr
get,post,head,put,trace,options,connection,delete
nginx: round-robin ip_hash least_conn
vim /etc/nginx.conf upstream websrvs { ip_hash(请注释掉backup这行); server 172.16.100.6 weight=1 max_fails=2 fail_timeout=2; server 172.16.100.7 weight=1 max_fails=2 fail_timeout=2; #server 127.0.0.1:8080 backup; }
proxy_cache_path /nginx/cache/first levels=1:2:1 keys_zone=first:20m max_size=1g;
location / { proxy_pass http://websrvs/; proxy_set_header X-Real-IP $remote_addr; proxy_cache first; proxy_cache_valid 200 10m; }
server { listen 8080; server_name 127.0.0.1; location / { root /web/error; index index.html index.htm } }
mkdir /web/error vim html
mkdir /nginx/cache/first
nginx作为缓存代理服务器 cache:共享内存:存储健和缓存对象元数据 磁盘空间:存储数据
proxy_cache_path:用来定义缓存的目录,不能定义在server{}上下文
缓存对象命名 缓存目录:子目录级别
proxy_cache_path /nginx/cache/first levels=1:2:1 keys_zone=first(这是要被location配置中引用的名称):20m max_size=1g; 表示有三个子级目录,1:表示第一子级目录有一个字符 2:表示第二子级目录有2个字符 1:表示第三子级目录有1个字符 cache_manager:LRU
location / { proxy_pass http://192.168.1.100:8080/webservs/; proxy_cache first; proxy_cache_valie 200 10m; }
另外常用的三种缓存: open_log_cache:日志缓存 open_file_cache: fastcgi_cache:
nginx的limit限制也基于共享内存实现
nginx:gzip
upstream phpsrvs { server .... server .... }
upstream imgsrvs { server .... server .... }
ustream staticfilesrvs { server .... server .... }
location / { root /web/htdocs; index index.php index.html }
location ~* .php$ { fastcgi_pass http://phpsrvs; }
location ~* .(jpg|jpeg|gif|png)$ { proxy_pass http://imgsrvs; }
rewirte:URL重写模块 if (condition) { }
测试: 双目测试: ~,!~ ,! ~,!~ if ($request_method="POST") {
}
if ($request_uri ~* "/forum") {
}
单目测试:
referer:
location / { root /web; rewrite "/images/" http://172.16.100.19/images/ }
支持正则表达式:
locstion / { root html; index index.html; rewrite "^/bbs/(.*)$" http://www.magedu.com/forum/$1 last; }
http://www.magedu.com/bbs/index.html --> http://www.magedu.com/forum/index.html
locstion / { root html; index index.html; rewrite "^/bbs/(.)/images/(.).jpg$" http://www.magedu.com/bbs/$2/images/$1.jpg last; }
http://www.magedu.com/bbs/a/images/b.jpg --> http://www.magedu.com/bbs/b/images/a.jpg --> http://www.magedu.com/bbs/a/images/b.jpg
last:本次重写完成之后,重启下一轮检查; break:本次重写完成之后,直接执行后续操作;
如果rewrite在location外部break和last作用一样,其后续的rewrite/return语句不再执行。但后续有location{}的话,还会近一步执行location{}里面的语句,当然前提是请求必须要匹配该location。 server{ listen 80; server_name test.com; root /tmp/123.com;
rewrite /1.html /2.html break;
rewrite /2.html /3.html;
} 当我们请求1.html时,最终访问到的是2.html 说明break在此示例中,作用是不再执行break以下的rewrite规则。但,当配置文件中有location时,它还会去执行location{}段的配置(请求要匹配该location)。 (break后面还有location段): server{ listen 80; server_name test.com; root /tmp/123.com;
rewrite /1.html /2.html break;
rewrite /2.html /3.html;
location /2.html {
return 403;
}
} 当请求1.html时,最终会返回403状态码,说明它去匹配了break后面的location{}配置。
如果rewrite在location内部,遇到break后,本location{}与其他location{}的所有rewrite/return规则都不再执行。 server{ listen 80; server_name test.com; root /tmp/123.com;
location / {
rewrite /1.html /2.html break;
rewrite /2.html /3.html;
}
location /2.html
{
rewrite /2.html /a.html;
}
location /3.html
{
rewrite /3.html /b.html;
}
} 当请求/1.html,最终会访问/2.html,也就是去访问/tmp/123.com/2.html文件而不会再去匹配location /2.html这个也不会执行rewrite /2.html /3.html这个,如果文件不存在就报404
如果rewrite在location内部,遇到last后,本location{}内后续指令不再执行,而重写后的url再次从头开始,从头到尾匹配一遍规则。 server{ listen 80; server_name test.com; root /tmp/123.com;
location / {
rewrite /1.html /2.html last;
rewrite /2.html /3.html;
}
location /2.html
{
rewrite /2.html /a.html;
}
location /3.html
{
rewrite /3.html /b.html;
}
} 当请求/1.html,最终会访问/a.html,并且会忽略执行rewrite /2.html /3.html这行
(什么都不加): server{ listen 80; server_name test.com; root /tmp/123.com;
location / {
rewrite /1.html /2.html;
rewrite /2.html /3.html;
}
location /2.html
{
rewrite /2.html /a.html;
}
} 当请求/1.html,最终将会访问/b.html,连续执行location /下的两次rewrite,跳转到了/3.html(注意location /2.html不会执行),然后又匹配location /3.html,此时两种情况1.没有localtion /3.html 则到此结束去找/tmp/123.com/3.html 2.有localtion /3.html继续执行该匹配直到最终
总结: 当rewrite规则在location{}外,break和last作用一样,遇到break或last后,其后续的rewrite/return语句不再执行。但后续有location{}的话,还会近一步执行location{}里面的语句,当然前提是请求必须要匹配该location。 当rewrite规则在location{}里,遇到break后,本location{}与其他location{}的所有rewrite/return规则都不再执行。 当rewrite规则在location{}里,遇到last后,本location{}里后续rewrite/return规则不执行,但重写后的url再次从头开始执行所有规则,哪个匹配执行哪个。
locstion / { root html; index index.html; rewrite "^/bbs/(.*)$" /forum/$1; }
zeromq:连接池 mmap:内存映射 Facebook:日志收集器
nginx: IO模型: 阻塞: 非阻塞:一遍一遍的轮询 同步:对方完完整整收到数据后,才响应说收到了 异步:数据发送出去就不管了,不管对方收到没有
同步阻塞 异步阻塞:IO复用 异步阻塞:event-driven 异步非阻塞:aio
nginx: mmap event-driven 一个进程响应多个请求:单线程进程 aio PHP和nginx结合要通过fastcgi
redis:能够实现持久存储 nosql:是一种技术,有很多不同的类别
location [op] uri { proxy_pass http://172.16.100.11/; }
~ ~* ^~
location @name(可以调用另外一个location):
location / { error 404 @fallback(即调用下面的fallback) }
location @fallback { proxy_pass http://1 92.168.1.20; }
location /forum/ { proxy_pass http://192.168.1.100:8080/bbs/; } 此/forum/和/bbs/要事先建立,且这两个目录在两台服务器上不用相同 当在浏览器中输入http://www.psmov.com/forum/则被代理到http://192.168.1.100:8080/bbs/后端http服务器中
如果采用正则表达式(即采用模式匹配)则只能写地址,后面不能接路径,且两个目录要相同 location ~* ^/forum { proxy_pass http://192.168.1.100:8080; } http://www.psmov.com/forum/则被代理到http://192.168.1.100:8080/forum/后端http服务器中
proxy_set_header x-real-IP $remote_addr(当客户端访问时都是代理服务器去获得资源然后给客户端,这样就无法得知是哪个客户端访问了,所有就采用proxy_set_header x-real-IP $remote_addr)
客户端请求内容的方法: get、post、head、put、trace、options、connection、delete
location ~* ^/forum { proxy_pass http://192.168.1.100:8080; proxy_set_header x-real-ip $remote_addr; }
nginx的三种算法: round-robin ip_hash:在这种算法下不能使用backup least_com
读写分离 webdav:基于http协议的读写分离
在后端的http服务中配置: <director "/var/www/html"> Dav on
/etc/init.d/httpd restart
setfacl -m u:apache:rwx /var/www/html
在前端的nginx中配置: location / { proxy_pass http://192.168.1.20/; if ($request_method = "PUT") proxy_pass http://192.168.1.21; }
curl -T /etc/fstab http://172.16.100.106 上传文件
nginx配置只允许域名来访问 server { listen 80 default_server; server_name node3.chenjiao.com; root /usr/share/nginx/html; if ($host != 'node3.chenjiao.com') { return 403; }
nginx配置缓存以及查看缓存命中状态 http { include mime.types; default_type application/octet-stream;
缓存配置,指定缓存路径、每个目录有2个层级,每个层级有两个目录、定义缓存键的共享内存区域名为cache_zone 为30m,最大值为32m,60min后缓存未被使用则会被删除,并关闭临时文件存储
proxy_cache_path /usr/local/nginx/cache_temp levels=2:2 keys_zone=cache_zone:30m max_size=32m inactive=60m use_temp_path=off;
upstream cache_server { server 192.168.12.128:1010; server 192.168.12.128:1011; } sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
# 引用上文的缓存配置
proxy_cache cache_zone;
# 仅对响应200的有效,保存5min
proxy_cache_valid 200 5m;
http请求头记录缓存状态
add_header Nginx-Cache-Status "$upstream_cache_status";
proxy_pass http://cache_server;
}
}
首次请求为MISS [root@localhost ~]# curl -I nginx的ip HTTP/1.1 200 OK Server: nginx/1.20.1 Date: Sat, 16 Dec 2023 12:51:59 GMT Content-Type: text/html;charset=ISO-8859-1 Connection: keep-alive Nginx-Cache-Status: MISS
二次请求为HIT [root@localhost ~]# curl -I nginx的ip HTTP/1.1 200 OK Server: nginx/1.20.1 Date: Sat, 16 Dec 2023 12:52:00 GMT Content-Type: text/html;charset=ISO-8859-1 Connection: keep-alive Nginx-Cache-Status: HIT
nginx使用split_clients实现代理分流:backendv2承担20%的流量,backendv1承担80%的流量 http { log_format main '$remote_addr $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '$http_user_agent $http_x_forwarded_for $request_time $upstream_response_time $upstream_addr $upstream_status'; access_log /var/log/nginx/access.log main;
proxy_cache_path /var/nginx/cache keys_zone=CACHE:60m levels=1:2 inactive=3h max_size=10g; map $request_method $purge_method { PURGE 1; default 0; } sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
upstream backendv1 {
server 192.168.131.141:8080;
} upstream backendv2 { server 192.168.131.142:8080; }
split_clients "${remote_addr}AAA" $variant {
20.0% "backendv2";
* "backendv1";
}
server {
listen 80 default_server;
server_name node3.chenjiao.com;
location / {
proxy_pass http://$variant;
proxy_cache CACHE;
proxy_cache_valid 168h;
proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie;
proxy_cache_lock on;
proxy_cache_lock_age 10s;
proxy_cache_lock_timeout 3s;
add_header Nginx-Cache-Status "$upstream_cache_status";
proxy_cache_key $host$uri$is_args$args$slice_range;
}
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
nginx使用split_clients实现本地网站目录分流:/usr/share/nginx/html承担80%的流量,/usr/share/nginx/html2承担80%的流量 http { #定义连接池和请求池 limit_conn_zone $binary_remote_addr zone=limitbyaddr:10m; limit_conn_status 429; limit_req_zone $binary_remote_addr zone=limitbyaddrr:10m rate=3r/s; limit_req_status 429;
split_clients "${remote_addr}" $site_root_folder { 80% "/usr/share/nginx/html"; * "/usr/share/nginx/html2"; }
server {
listen 82 ;
limit_conn limitbyaddr 40;
limit_req zone=limitbyaddrr burst=12 delay=9;
location / {
root $site_root_folder;
index index.html;
}
}
nginx限制下载速度达到10m后,降速为1m,以及配置加密后的密码认证 http { server { listen 82 ; location /download/ { auth_basic "private site"; auth_basic_user_file conf.d/passwd; alias /usr/share/nginx/iso/; autoindex on; limit_rate_after 10m; limit_rate 1m; }
} #假如密码为admin,对admin密码进行加密 root@node3 ~]# openssl passwd admin M3dsiHVCah1po #编辑用户名和密码文件(写成用户名:加密后的密码格式) [root@node3 html]# cat /etc/nginx/conf.d/passwd admin:4brt6EbPuri.6
使用第三方接口进行认证使用auth_request模块,该模块只需要接收到响应码为200即可认证通过 http { server { listen 80 ; location / { root /usr/share/nginx/html; index index.html; auth_request /auth; auth_request_set $auth_status $upstream_status; }
location ~* /auth {
internal;
proxy_pass http://192.168.131.130:81;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
}
使用nginx简单模拟第三方认证接口,返回200状态码即可 http { server { listen 192.168.131.130:81; location / { return 200; } } }
nginx代理https协议 第一种情况直接代理不验证上游服务器的证书: http { server { listen 80 default_server; server_name node3.chenjiao.com; location / { proxy_pass https://www.baidu.com; }
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
} }
第二种情况代理后端https服务器时验证对方服务器证书 http { server { listen 80 default_server; server_name node3.chenjiao.com; location / { proxy_pass https://www.baidu.com; proxy_ssl_verify on; #验证上游服务上的证书和证书链是否有效 proxy_ssl_verify_depth 2; #验证深度最多为两个证书 proxy_ssl_protocols TLSv1.2; #指定 NGINX 只使用 TLS 版本 1.2 proxy_ssl_trusted_certificate /etc/nginx/conf.d/cacert.pem;#我们只信任这个 CA 签发的所有证书 }
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
} }
下载公共CA文件 curl https://curl.se/ca/cacert.pem -o /etc/nginx/conf.d/cacert.pem
第三种情况代理https时采用upstream模块 1.upstream中的server 为ip:port形式,直接代理即可不用特殊处理 http { upstream backendv1 { server ip:443; }
server { listen 80 default_server; server_name node3.chenjiao.com; location / { proxy_pass https://backendv1; }
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
} }
2.upstream中的server 为域名:port形式,要进行特殊处理(可以关注一下日志中$proxy_host的值) 要在配置文件中设置请求头: proxy_ssl_server_name on。 proxy_ssl_name 域名。 proxy_set_header Host 域名。
http { log_format main '$remote_addr $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '$http_user_agent $http_x_forwarded_for $request_time $upstream_response_time $upstream_addr $upstream_status' ' $Host' ' $host' ' $proxy_host' ' $http_host' ' $server_name'; upstream backendv1 { server www.baidu.com:443; }
server { listen 80 default_server; server_name node3.chenjiao.com; location / { proxy_pass https://backendv1; proxy_ssl_verify on; #验证上游服务上的证书和证书链是否有效 proxy_ssl_verify_depth 2; #验证深度最多为两个证书 proxy_ssl_protocols TLSv1.2; #指定 NGINX 只使用 TLS 版本 1.2 proxy_ssl_trusted_certificate /etc/nginx/conf.d/cacert.pem;#我们只信任这个 CA 签发的所有证书 proxy_ssl_server_name on; proxy_ssl_name www.baidu.com; proxy_set_header Host www.baidu.com; }
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
} }
nginx配置HTTPS 重定向 1.使用 rewrite 指令将所有 HTTP 流量发送到 HTTPS: server { listen 80 default_server; listen [::]:80 default_server; server_name _; return 301 https://$host$request_uri; } 2.在 NGINX 之前终止 SSL/TLS 后重定向到HTTPS(第一种方法是nginx接收到http请求后在跳转到https,而这种方法是通过解析请求头为http协议后直接转发到https协议,不用在http接受请求后在响应跳转到https) 使用常见的 X-Forwarded-Proto 请求头确定是否需要重定向: server { listen 80 default_server; listen [::]:80 default_server; server_name _; if ($http_x_forwarded_proto = 'http') { return 301 https://$host$request_uri; } }
nginx提供多种安全方法(意思就是配置nginx支持一种或者多种的安全访问方法) server{ listen 80; root html;
location / {
satisfy any;
allow 192.168.131.0/24;
deny all;
auth_basic "closed site";
auth_basic_user_file conf.d/passwd;
}
} 此配置告知 NGINX 请求 location/ 的用户需要满足其中一种安全方法:请求需要来自192.168.131.0/24 CIDR 代码块,或者必须能够提供可以在 conf/htpasswd 文件中找到的用户名和密码。 satisfy 指令带两个选项: any(代表用户必须满足其中一个安全要求) 或 all(代表用户必须满足所有安全要求)
使用 secret 保护 location 代码块 通过 secure link 模块和 secure_link_secret 指令,仅允许拥有安全链接的用户访问资源: http {
server { listen 192.168.131.130; location /resources { secure_link_secret mySecret; if ($secure_link = "") { return 403; } rewrite ^ /secured/$secure_link; }
location /secured/ {
internal;
root html;
}
} }
将网页代码放入此目录下面 mkdir /usr/share/nginx/html/secured 需要使用 secret 从应用中生成安全链接。假如我们的网页代码为index.html [root@localhost ~]# echo -n 'index.htmlmySecret' | openssl md5 -hex (stdin)= a53bee08a4bf0bbea978ddf736363a12 此处展示了我们要保护的 URI index.html,它与我们的 secret mySecret 拼接在一起。该字符串被传递到 openssl 命令,输出 md5 十六进制摘要。 浏览器访问:192.168.131.130/resources/a53bee08a4bf0bbea978ddf736363a12/index.html
在 NGINX 服务器上启用 HTTP/2: server { listen 443 ssl http2 default_server; ssl_certificate server.crt; ssl_certificate_key server.key;
...
}
使用 NGINX 代理 gRPC 连接: server { listen 80 http2; location / { grpc_pass grpc://backend.local:50051; } } 在这个配置中, NGINX 侦听端口 80 上未加密的 HTTP/2 流量,并将这些流量代理到端口 50051 上名为 backend.local 的机器。 grpc_pass 指令指示 NGINX 将该通信视为gRPC 调用。后端服务器前面的 grpc:// 不是必需的,但它可以直接显示后端通信是未加密的。 要在客户端和 NGINX 之间利用 TLS 加密,并在将调用传递给应用服务器之前终止加密,需像在第一节中那样启用 SSL 和 HTTP/2: server { listen 443 ssl http2 default_server; ssl_certificate server.crt; ssl_certificate_key server.key; location / { grpc_pass grpc://backend.local:50051; } } 该配置在 NGINX 上终止了 TLS,并通过未加密的 HTTP/2 将 gRPC 通信传递到应用。要配置 NGINX 加密与应用服务器的 gRPC 通信,提供端到端加密流量,只需修改grpc_pass 指令,在服务器信息之前指定 grpcs://(注意增加的 s 表示安全通信): grpc_pass grpcs://backend.local:50051;
需要配置访问日志格式,以将内置变量添加到请求日志中: http { log_format geoproxy '[$time_local] $remote_addr ' '$realip_remote_addr $remote_user ' '$proxy_protocol_server_addr $proxy_protocol_server_port ' '$request_method $server_protocol ' '$scheme $server_name $uri $status ' '$request_time $body_bytes_sent ' '$geoip_city_country_code3 $geoip_region ' '"$geoip_city" $http_x_forwarded_for ' '$upstream_status $upstream_response_time ' '"$http_referer" "$http_user_agent"';
...
server { access_log /var/log/nginx/access.log geoproxy;
...
} }
需要配置错误日志,以更深入地了解 NGINX 服务器问题: 使用 error_log 指令定义日志路径和日志级别: error_log /var/log/nginx/error.log warn;
转发日志到 Syslog 使用 error_log 和 access_log 指令将日志发送到 Syslog 侦听器: error_log syslog:server=10.0.1.42 debug; access_log syslog:server=10.0.1.42,tag=nginx,severity=info geoproxy;
error_log 和 access_log 指令的 syslog 参数后面紧跟冒号和一些参数选项。这些选项包括必要的日志服务标识,如:需要连接的 IP 地址、 DNS 名称或 Unix socket,以及 facility、 severity、 tag 和 nohostname 等可选标记。 server 选项在指定指 IP 地址或 DNS 名称时设置端口号,默认为 UDP 514。 facility 选项是指日志消息的 facility值,取 Syslog RFC 标准定义的 23 个值之一;默认值为 local7。 tag 选项表示消息的标记,默认值为 nginx。 severity 选项默认为 info,表示所发送消息的日志级别。 nohostname 标记禁止将 hostname 字段添加到 syslog 消息头中,不取值。
请求跟踪 使用 request 的唯一识别变量,并将其传递给应用以进行记录: log_format trace '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '"$http_x_forwarded_for" $request_id'; upstream backend { server 10.0.0.42; } server { listen 80;
将 X-Request-ID 标头添加到对客户端的响应中
add_header X-Request-ID $request_id; location / { proxy_pass http://backend;
将 X-Request-ID 标头发送到应用端
proxy_set_header X-Request-ID $request_id; access_log /var/log/nginx/access_trace.log trace; } } 在发起上游请求时,通过使用 proxy_set_header 指令将请求 ID 添加到请求头里,将此 $request_id 变量传递给了上游应用。此外,还通过使用 add_header 指令,在响应头中设置请求 ID,将请求 ID 传回客户端。 $request_id 提供了一个随机生成的 32 位十六进制字符串,这些字符可以用来唯一性标识请求。
API 密钥身份验证 API 密钥是客户端和 API 网关的共享密钥。 API 密钥本质上是一个作为长期凭证发给 API 客户端的长而复杂的密码。 map $http_apikey $api_client_name { default ""; "7B5zIqmRGXmrJTFmKa99vcit" "client_one"; "QzVV6y1EmQFbbxOfRCwyJs35" "client_two"; "mGcjH8Fv6U9y3BVF9H3Ypb9T" "client_six"; } server { listen 99; server_name 192.168.131.130; auth_request /_validate_apikey; #也可以放在具体的location下面 location /_validate_apikey { internal; if ($http_apikey = "") { return 401; } if ($api_client_name = "") { return 403; }
return 204;
}
} API 密钥在 map 块中定义。 Map 指令有两个参数。第一个参数定义在何处查找 API 密钥,本例中是在客户端请求的 apikey HTTP 包头中,该包头于 $http_apikey 变量中捕获。第二个参数创建一个新变量($api_client_name),并将其设置为第一个参数与密钥匹配行的第二个参数的值。例如,当客户端请求中带有 API 密钥 7B5zIqmRGXmrJTFmKa99vcit 时,$api_client_name变量自动设置为 client_one。 internal 指令意味着外部客户端不能直接访问此位置(只能由 auth_request 访问)。客户端应在 apikey HTTP 包头中显示其 API 密钥。如果此标头丢失或为空,我们将发送 401(Unauthorized) 响应,告知客户端需要进行身份验证。API 密钥与 map 块中的任何密钥都不匹配的情况 —— 在这种情况下, default 参数将 $api_client_name 设置为空字符串,我们将发送 403(Forbidden) 响应,告诉客户端身份验证失败。如果这些条件都不匹配,则 API 密钥有效并且该 location 返回204(No Content) 响应 curl -I -H "apikey: 7B5zIqmRGXmrJTFmKa99vcit" http://192.168.131.130:99 HTTP/1.1 200 OK curl -I http://192.168.131.130:99 HTTP/1.1 401 Unauthorized curl -I -H "apikey: 123" http://192.168.131.130:99 HTTP/1.1 403 Forbidden
执行特定的请求方法 请求中只接受 GET 方法 server { listen 99; server_name 192.168.131.130; location / { limit_except GET { deny all; } proxy_pass http://service_1; } } curl -I http://192.168.131.130:99 HTTP/1.1 200 OK curl -I -XPOST http://192.168.131.130:99 HTTP/1.1 403 Forbidden