实战Nginx
该书代码:
http://zyan.cc/book/nginx/code/ 360浏览器编码改成GBK
官方文档
grep -Ev "^$|#" conf.d/default.conf
排除空行和注释行
- 安装
yum -y install gcc gcc-c++ autoconf automake
yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel
- DOS 命令
nginx -s stop quit reopen reload
- Nginx 信号控制
- TERM INT 快速关闭
- QUIT 从容关闭
- HUP 平滑启动,重新加载配置文件
- USR1 重新打开日志文件,在日志切割时用
- USR2 平滑升级可执行程序
- WINCH 从容关闭工作线程
kill -TERM `cat nginx.pid` kill -QUIT `cat nginx.pid` kill -USR2 `cat nginx.pid` pkill -9 nginx
- 虚拟主机
- 基于域名
- 基于IP,一个机子几个IP
- 基于端口
-
日志格式可以用变量,但是有几个限制,so..方便起见还是老实一个个写吧
access_log logs/$server_name.log combined;
image.png -
cut_nginx_log.sh
#!/bin/bash
#这个脚本必须每天00:00运行
echo "start..."`date`
#nginx的日志文件存放路径
logs_path="/var/log/nginx"
logs_backup_path=${logs_path}/$(date -d "yesterday" +"%Y")$(date -d "yesterday" +"%m")
mkdir -p ${logs_backup_path}
mv ${logs_path}/access.log ${logs_backup_path}/access_$(date -d "yesterday" +"%Y%m%d").log
kill -USR1 `cat /var/run/nginx.pid`
echo "over..."`date`
- 下载站点
location /zzjdownload {
alias /home/download;
charset utf-8,gbk;
autoindex on ;
autoindex_exact_size on;
autoindex_localtime on;
auth_basic "Byedbl";
auth_basic_user_file conf.d/htpasswd ;
}
#printf "byedbl1:$(openssl passwd -crypt xxxx)\n" >>conf.d/htpasswd
- Nginx站点状态
with-http_stub_status_module
location /ng-status {
allow xxx;
deny all;
stub_status on;
access_log off;
}
- 获取nginx的主进程ID
ps -ef | grep "nginx: master process" | grep -v 'grep' | awk -F ' ' '{print $2}'
- 修改日志格式,改源码...
log_format access '$remote_addr $time_iso8601 "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
- 跨域
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods GET,POST,PUT;
add_header Access-Control-Allow-Headers accept,content-type,x-iamservice-appid,x-iamservice-appkey;
- 本地srm配置
#配置worker进程的用户和用户组
#user nobody;
#worker进程启动数量
#与CPU核心处理器数量相同
worker_processes 2;
#所有错误写入的文件,其他地方也可以单独指定
#第二个参数值有: debug(在编译时配置了with-debug才可以使用) info notice warn error crit alert emerg
#error_log logs/error.log;
#error_log logs/error.log notice;
error_log logs/error.log info;
#记录主进程ID
#pid logs/nginx.pid;
events {
#单个worker_processes的并发连接的最大数
worker_connections 1024;
}
#包含其他的配置
#nginx -t -c ../*.conf 测试配置语法的正确性,包括include 文件
#include /opt/local/etc/nginx/vhost/*.conf;
http {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods GET,POST,PUT;
add_header Access-Control-Allow-Headers accept,content-type,x-iamservice-appid,x-iamservice-appkey;
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
#直接复制数据从一个到另一个文件描述符
sendfile on;
#设置一个sendfile在拷贝中的最大数据大小
#sendfile_max_chunk
#仅依赖sendfile使用,能够使得Nginx在一个数据包中尝试发送响应头,以及在一个数据包中发送一个完整文件
#tcp_nopush on;
#启用或禁用 TCP_NODELAY 选项,用于keep-alive连接
#tcp_nodelay on ;
#指定keep-alive连接连续多久
#keepalive_timeout 0;
keepalive_timeout 65;
#指定server_name 哈希表的最大大小
server_names_hash_max_size 1024;
gzip on;
#这段的作用是丢弃这种缺乏Host头的请求
server {
listen 80;
error_page 444 error/404.html;
return 444;
location / {
#当502或504时,将请求转发到负载均衡中正常server中
#proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_connect_timeout 10;
proxy_send_timeout 3000;
proxy_read_timeout 3000;
proxy_pass http://srm_portal_server;
proxy_redirect off;
#若nginx为最前端时,后端获得X-Real-IP传递的ip即为实际ip,若nginx不是最前端时,实际ip为X-Forwarded-For值。
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host:8096;
proxy_pass_request_headers on;
index index.html;
}
}
upstream srm_portal_server{
server 127.0.0.1:8096;
}
#虚拟服务器部分,根据server_name逻辑分割的资源
server {
listen 8097;
#配置可接受通配符,如:*.example.com .example.com(将匹配*.example.com和example.com本身)
#server_ name ~^ www\. example\. com$; 可用正则表达式
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
#location = / {
# #root html;
# root test;
#
# #index index.html index.htm;
# index index/html/index.html;
#}
error_page 404 error/404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 error/50x.html;
location = /50x.html {
root html;
}
location = /404.html {
root html;
}
#静态文件交给nginx处理
location ~ .*\.(js|css||gif|jpg|jpeg|png|bmp|swf|ioc|flv|woff|woff2|ttf|map)$
#location ~/static/.*
{
proxy_connect_timeout 10;
proxy_send_timeout 3000;
proxy_read_timeout 3000;
proxy_pass http://10.100.21.114:80;
proxy_redirect off;
#若nginx为最前端时,后端获得X-Real-IP传递的ip即为实际ip,若nginx不是最前端时,实际ip为X-Forwarded-For值。
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass_request_headers on;
#root D:\\mytask\\SRM\\res;
#expires 30d;
}
location /static/
{
proxy_connect_timeout 10;
proxy_send_timeout 3000;
proxy_read_timeout 3000;
proxy_pass http://10.100.21.114:80;
proxy_redirect off;
#若nginx为最前端时,后端获得X-Real-IP传递的ip即为实际ip,若nginx不是最前端时,实际ip为X-Forwarded-For值。
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass_request_headers on;
#root D:\\mytask\\SRM\\res;
}
location ~ .*\.html$
{
proxy_connect_timeout 10;
proxy_send_timeout 3000;
proxy_read_timeout 3000;
proxy_pass http://10.100.21.114:80;
proxy_redirect off;
#若nginx为最前端时,后端获得X-Real-IP传递的ip即为实际ip,若nginx不是最前端时,实际ip为X-Forwarded-For值。
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass_request_headers on;
#root D:\\mytask\SRM\\res\\index;
#expires 30d;
}
#location ~ .*\.html$
#{
# root D:\mytask\SRM\res\index;
# expires 30d;
#}
location / {
#当502或504时,将请求转发到负载均衡中正常server中
#proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_connect_timeout 10;
proxy_send_timeout 3000;
proxy_read_timeout 3000;
proxy_pass http://srm_portal_server;
proxy_redirect off;
#若nginx为最前端时,后端获得X-Real-IP传递的ip即为实际ip,若nginx不是最前端时,实际ip为X-Forwarded-For值。
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host:8096;
proxy_pass_request_headers on;
index index.html;
}
}
}
-
反向代理:多个网络用户从Internet访问内网的固定服务器
-
正向代理:内网用户通过代理服务器访问多个Internet站点
-
WEB负载均衡方法
- 下载页提供不同的站点
- DNS轮询,添加二级域名和A记录
C:\Users\zengzhijun.QK>nslookup www.baidu.com
服务器: qkdc1.qk.qiku.com
Address: xxx
非权威应答:
名称: www.a.shifen.com
Addresses: 14.215.177.38
14.215.177.39
Aliases: www.baidu.com
C:\Users\zengzhijun.QK>nslookup www.taobao.com
服务器: qkdc1.qk.qiku.com
Address: xxx
非权威应答:
名称: www.taobao.com.danuoyi.tbcache.com
Address: 220.170.91.114
Aliases: www.taobao.com
Linux用dig命令
yum install -y bind-utils
[root@iZwz9j1m4fpjustyk6ar1iZ nginx]# dig www.baidu.com
; <<>> DiG 9.9.4-RedHat-9.9.4-61.el7 <<>> www.baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47626
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;www.baidu.com. IN A
;; ANSWER SECTION:
www.baidu.com. 672 IN CNAME www.a.shifen.com.
www.a.shifen.com. 41 IN A 220.181.111.188
www.a.shifen.com. 41 IN A 220.181.112.244
;; Query time: 5 msec
;; SERVER: 100.100.2.138#53(100.100.2.138)
;; WHEN: Thu Jun 21 15:57:21 CST 2018
;; MSG SIZE rcvd: 90
百度有两条A记录
该方法不好,负载不均衡,可靠性不高,缓存生效时间不定.
- 四/七层负载均衡设备,F5(硬件) LVS(软件4层) Nginx,HAProxy(软件7层)
物理层->数据链路层->网络层->传输层->会话层->表示层->应用层
2数据链路层: 保证了数据在不可靠的物理线路上进行可靠的传递
3网络层,IP,路由,地址协议解析(ARP)
4传输层:TCP,UDP,该层起到缓冲的作用,为会话层提供可靠保障
5会话层:保持会话同步,决定通信是否中断,中断时决定从何处重传
6表示层:加解密,解码和编码
7应用层:Telnet,FTP,HTTP,为操作系统和网络应用程序提供网络服务的接口
- 配置
upstream php_server_pool {
ip_hash;
server 192.168.1.10:80 weight=4 max_fails=2 fail_timeout=30s;
server 192.168.1.14:3245 down;
server 192.168.1.14:3245 backup;
}
location
proxy_next_upstream http_502 http_504 error timeout invalid_header;
- 日志中可以用的几个配置
$upstream_status upstream 服务器的应答状态;
$upstream_addr 处理请求upstream服务器地址;
$upstream_response_time Upstream服务器响应时间,多个以冒号和逗号分隔;
$upstream_http_$HEADER 任意HTTP协议头,如:$upstream_http_host;
-
Nginx负载均衡服务器的双机高可用
image.png
见实战Nginx摘录-文档 nginx_ha2.sh脚本
-
Nginx rewrite
rewrite ^/b/(.*)\.html /play?v=$1 break;
if (! -f $request_filename)
{
rewrite ^/img/(.*)$ /site/$host/images/$1 last;
}
- break:
使用环境:server location if
作用:完成当前的规则集,不再处理rewrite指令
if ($slow) {
limit_rate 10k;
break;
}
-
if:
使用环境: server location
作用: 用于检查条件是否符合,不支持多个条件 && 和 || 处理
image.png
if($http_user_agent ~ MSIE){
rewrite ^(.*)$ /msie/$1 break;
}
if( $request_method = POST ) {
return 405;
}
if( $http_cookie ~* "id=([^;]+)(?:;|$)" ){
set $id $1;
}
if( !-f $request_filename){
break;
proxy_pass http://127.0.0.1;
}
if ($slow) {
limit_rate 10k;
break;
}
if( $arg ^~ post=140){
rewrite ^ http://127.0.0.1;
}
- rewrite指令 ,根据配置文件的顺序来执行
语法:rewrite regex replacement flag[last,break,redirect 302,permanent 301]
使用环境:server location if
if ( $host ~* www\.(.*)) {
set $host_without_www $1;
rewrite ^(.*)$ http://$host_without_www$1 permanent;
}
alias --> last last注意死循环问题
proxy_pass --> break
image.png
在跟location中和server中推荐用last,在非根的location中推荐用break;
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
/photos/12345 重定向到 /path/to/photos/12/1234/12345.png
rewrite "/photos/([0-9]{2})([0-9]{2})([0-9]{2})" /path/to/photos/$1/$1$2/$1$2$3.png;
-
set指令 赋值
使用环境:server location if
set $varname hello -
rewrite能用的变量
$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相同
image.png
image.png
- 实例
#文件和目录不存在时跳转首页
if ( !-e $request_filename){
rewrite ^/(.*)$ /index.html last;
}
#多目录转成参数
if ($host ~* (.*)\.domain\.com){
set $sub_name $1;
rewrite ^/sort\/(\d+)\/?$ /index.do?act=sort&cid=$sub_name&id=$1 last;
}
#禁止访问多个目录
location ~* ^/(cron|tempalte)/ {
deny all;
break;
}
#禁止访问以/data开头的文件,可以放到location里面,会直接跳首页
location ~* ^/data {
deny all;
}
#设置某些文件的浏览器过期时间
location ~ .*\.(js|css)?$
{
expires 1h;
}
#将多级目录下的文件转换成一个文件 /job-123-456-789.html 指向 /job/123/456/789.html
#注意与跳首页的先后顺序,放外面就直接跳首页了,放里面要放到下面的规则里
location ~ .*\.html$
{
rewrite ^/job-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /$1/$2/jobshow_$3.html last;
if ( !-e $request_filename){
rewrite ^/(.*)$ /index.html last;
}
root /usr/share/nginx/html;
location ~ ^/data {
deny all;
}
}
#允许指定的域名访问本站,其他域名一律跳转 http://www.bbb.com
if ($host ~* ^(.*)?\.aaa\.com$){
set $var '1';
}
if ($host ~* ^192\.168\.1\.(.*?)$){
set $var '1';
}
if ($host ~* ^localhost){
set $var '1';
}
if ($var !~ '1'){
rewrite ^/(.*)$ http://www.bbb.com redirect;
}
#跳转到其他网站,或者没有输入www点的跳有www点的
server
{
listen 80;
server_name www.byedbl2.com;
rewrite ^/(.*)$ http://www.byedbl.com/ permanent;
access_log /var/log/nginx/access_1.log main;
}
#静态文件的代理
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|css|html|shtml)$
{
proxy_cache cache_one;
proxy_cache_valid 200 10m;
proxy_cache_valid 304 1m;
proxy_cache_valid 301 302 1h;
proxy_cache_valid any 1m;
proxy_cache_key $host$uri$is_args$args;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://bbs_server_pool;
}
#限制下载速度
location /
{
#限制下载速度为256kB/秒
limit_rate 256k;
proxy_pass http://xx.xx.xx.19;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
#播放视频
server
{
listen 80;
server_name flv.byedbl.com ;
index index.html index.htm;
root /usr/share/nginx/html/flv;
#30M之后开始限速
limit_rate_after 30m;
limit_rate 512k;
location ~ \.flv
{
flv;
}
}
- html 播放视频 html中嵌入flv格式文件的代码 Yamdi1.9 和flvtool2 开源软件
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" height="120" width="190">
<param name="movie"
value="http://www.byedbl.com/static/vcastr22.swf?vcastr_file=http://flv.byedbl.com/1.flv">
<param name="quality" value="high">
<param name="allowFullScreen" value="true" />
<embed
src="http://www.byedbl.com/static/vcastr22.swf?vcastr_file=http://flv.byedbl.com/1.flv"
quality="high"
pluginspage="http://www.macromedia.com/go/getflashplayer"
type="application/x-shockwave-flash" width="820" height="840">
</embed>
</object>
- 正向代理服务器
server
{
listen 80;
location / {
#DNS解析服务器的IP地址
resolver 8.8.8.8;
proxy_pass http://$host$request_uri;
}
access_log /var/log/access_log.log
}
- 关闭日志
location = /robots.txt {
log_not_found off;
}
location = /favicon.ico{
log_not_found off;
}
- try_files 用法
# try_files 用法,按照顺序一路找存在的,必须要有个存在,不然会报错
location / {
try_files /system/maintenance.html $uri $uri/index.html $uri.html @byedbl_proxy
}
location @byedbl_proxy {
proxy_pass http://www.byedbl.com;
}
location /api/ {
try_files /system/maintenance.html $uri $uri/index.html $uri.html @byedbl_proxy;
#proxy_pass http://www.byedbl.com;
#root /usr/share/nginx/html/system;
}
- CPU亲和力设置
worker_processes 2;
worker_cpu_affinity 01 10;
- 记录请求内容,用于调试的时候用
#记录客户端发过来的POST请求内容
client_body_in_file_only on;
#指定缓存文件的路径,最多3层子目录,1 2 表示第一层为1个数字,第二层为2个数字
client_body_temp_path /var/cache/path 1 2 ;
例子:
[root@localhost client_temp]# more 0000000001
----------------------------055840557212412661906914
Content-Disposition: form-data; name="name"
zzj
----------------------------055840557212412661906914
Content-Disposition: form-data; name="age"
18
----------------------------055840557212412661906914--
- 限制HTTP方法,白名单
limit_except GET {
allow 192.168.1.0/32;
deny all;
}
- 监听两个端口,注意Dockerfile和docker-compose文件要放端口出来
listen 80;
listen 8080;
listen 443 default ssl;
- basic认证
auth_basic "Byedbl";
auth_basic_user_file conf.d/htpasswd ;
printf "byedbl1:$(openssl passwd -crypt xxxx)\n" >>conf.d/htpasswd