Nginx日常笔记

2016-06-30

Docker Nginx

1.启动一个测试容器

 docker run --rm --name nginx-test -p 8080:80 -d nginx

2.创建本地目录

mkdir -p /app/nginx/www /app/nginx/logs /app/nginx/conf

3.将测试容器的nginx.conf配置文件拷出

docker cp nginx-test:/etc/nginx/nginx.conf /app/nginx/conf/

4.启动新的容器,并挂载本地目录

docker run --rm -d -p 8081:80 --name nginx-test-web \
  -v /app/nginx/www:/usr/share/nginx/html \
  -v /app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
  -v /app/nginx/logs:/var/log/nginx \
  nginx

高并发测试使用的配置文件 nginx.conf

user  nginx;
worker_processes  12;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  65535;
}


http {
    include       /etc/nginx/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  /var/log/nginx/access.log  main;
    access_log  off;
    
    sendfile        on;
    tcp_nopush     on;
    
    keepalive_timeout  65;
    
    #gzip  on;
    
    include /etc/nginx/conf.d/*.conf;

}

快速安装

apt-get install nginx

配置文件 /etc/nginx/nginx.conf

Nginx的配置文件是/etc/nginx/nginx.conf,其中设置了一些必要的参数,我们发现其中这样的语句:

include /etc/nginx/sites-enabled/*

可以看出/etc/nginx/sites-enabled/default文件也是一个核心的配置文件,其中包含了主要的配置信息,

如服务器跟目录、服务器名称、location信息和server信息。

开启反向代理

开启代理池:

upstream malu.me {
    server 192.168.1.210:80; #Apache
}

location配置:

    location / {
            proxy_pass  http://malu.me;

            #Proxy Settings
            proxy_redirect     off;
            #For relay ip
            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_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
            proxy_max_temp_file_size 0;
            proxy_connect_timeout      90;
            proxy_send_timeout         90;
            proxy_read_timeout         90;
            proxy_buffer_size          4k;
            proxy_buffers              4 32k;
            proxy_busy_buffers_size    64k;
            proxy_temp_file_write_size 64k;
            client_max_body_size 20M;
    }

开启缓存

缓存目录配置:http

#proxy cache
proxy_cache_path /data/nginx/cache/webserver levels=1:2 keys_zone=webserver:20m max_size=1g;

然后新建缓存目录:

mkdir -pv /data/nginx/cache/webserver

添加配置规则:http server

    #proxy cache
    #add_header X-Via $server_addr;
    add_header X-Cache $upstream_cache_status;

    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
            proxy_pass  http://malu.me;
            #host header         
            proxy_set_header   Host             $host;
            #proxy cache
            proxy_cache webserver;
            proxy_cache_valid 200 302 1m;
            proxy_cache_valid 404 1m;
            proxy_cache_valid 1m;
            proxy_cache_valid any 1m;
    }

关闭Web服务器头信息(Header)里的Server值

默认会看到nginx返回的头信息里有版本号,比如:Server:nginx/1.4.6 (Ubuntu)

将这个信息去除

http{}里面加:

server_tokens off;

上传文件大小配置

默认情况下使用nginx反向代理上传超过2MB的文件,会报错413 Request Entity Too Large

解决这个方法很简单,修改配置client_max_body_size值即可 http server location:

client_max_body_size 10M;

添加HTTPS支持:

在http server里添加

    listen 443 ssl;
    ssl on;
    ssl_certificate /etc/nginx/ssl/malu.me.crt;
    ssl_certificate_key /etc/nginx/ssl/malu.me.key;

完整配置如下:

upstream malu.me {
    server 192.168.1.210:80; #Apache
}

#proxy cache
proxy_cache_path /data/nginx/cache/webserver levels=1:2 keys_zone=webserver:20m max_size=1g;

server {
        listen 80 default_server;
        #IPv6配置
        #listen [::]:80 default_server ipv6only=on;

        listen 443 ssl;

        #ssi支持(Server Side Includes)
        ssi on;
        ssi_silent_errors on;  
        ssi_types text/shtml;

        #同时开启80和443是这边ssl on要注释掉!
        #ssl on;
        ssl_certificate /etc/nginx/ssl/malu.me.crt;
        ssl_certificate_key /etc/nginx/ssl/malu.me.key;

        #有CA证书情况下开启
        #ssl_client_certificate /etc/nginx/ssl/ca.crt;  

        ssl_session_timeout  5m;
        ssl_verify_client on;  #打开客户端证书验证,有CA证书情况下关闭off  

        #加密配置
        ssl_protocols  SSLv2 SSLv3 TLSv1;  
        ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;  
        ssl_prefer_server_ciphers   on;  

        server_name malu.me;

        #proxy cache
        #add_header X-Via $server_addr;
        add_header X-Cache $upstream_cache_status;

        location / {
                proxy_pass  http://malu.me;

                #Proxy Settings
                proxy_redirect     off;
                #For relay ip
                proxy_set_header   Host             $host;
                proxy_set_header   X-Real-IP        $remote_addr;
                #防止客户端伪造IP
                proxy_set_header   X-Forwarded-For  $remote_addr;
                #proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
                #给后端传递https或http状态信息
                proxy_set_header   X-Forwarded-Proto  $scheme;

                proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
                proxy_max_temp_file_size 0;
                proxy_connect_timeout      90;
                proxy_send_timeout         90;
                proxy_read_timeout         90;
                proxy_buffer_size          4k;
                proxy_buffers              4 32k;
                proxy_busy_buffers_size    64k;
                proxy_temp_file_write_size 64k;
                client_max_body_size 20M;
        }

        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|css|ico)$ {
                proxy_pass  http://malu.me;
                #host header 虚拟主机用得到,否则会出现404错误 
                proxy_set_header   Host             $host;
                #proxy cache
                proxy_cache_valid 404 10s;
                proxy_cache webserver;
                proxy_cache_valid 200 302 1m;
                proxy_cache_valid 1m;
                proxy_cache_valid any 1m;
                #proxy_cache_key $host$uri$is_args$args;  #清理缓存需要ngx_cache_purge模块
        }
}

生成HTTPS证书

nginx要实现ssl,在编译时要添加–with-http_ssl_module,如: ./configure –with-http_ssl_module

# cd /etc/nginx/
# mkdir ssl
# cd ssl

生成一个私有key

# openssl genrsa -des3 -out malu.me.key 1024

提示输入密码 生成CSR(Certificate Signing Request)文件:

# openssl req -new -key malu.me.key -out malu.me.csr

填写证书内容,组织机构、域名等,Common Name填写域名

# cp malu.me.key malu.me.key.bak
# openssl rsa -in malu.me.key.bak -out malu.me.key
# openssl x509 -req -days 365 -in malu.me.csr -signkey malu.me.key -out malu.me.crt

完整配置参数说明

#定义Nginx运行的用户和用户组
user www www;

#nginx进程数,建议设置为等于CPU总核心数。
worker_processes 8;

#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx/error.log info;

#进程文件
pid /var/run/nginx.pid;

#一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致。
worker_rlimit_nofile 65535;

#工作模式与连接数上限
events {

	#参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
	use epoll;
	
	#单个进程最大连接数(最大连接数=连接数*进程数)
	worker_connections 768;
}

#设定http服务器
http {
	include mime.types; #文件扩展名与文件类型映射表
	default_type application/octet-stream; #默认文件类型
	#charset utf-8; #默认编码
	server_names_hash_bucket_size 128; #服务器名字的hash表大小
	client_header_buffer_size 32k; #上传文件大小限制
	large_client_header_buffers 4 64k; #设定请求缓
	client_max_body_size 8m; #设定请求缓
	sendfile on; #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
	autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。
	tcp_nopush on; #防止网络阻塞
	tcp_nodelay on; #防止网络阻塞
	keepalive_timeout 120; #长连接超时时间,单位是秒

	#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。下面参数看字面意思都能理解。
	fastcgi_connect_timeout 300;
	fastcgi_send_timeout 300;
	fastcgi_read_timeout 300;
	fastcgi_buffer_size 64k;
	fastcgi_buffers 4 64k;
	fastcgi_busy_buffers_size 128k;
	fastcgi_temp_file_write_size 128k;

	#gzip模块设置
	gzip on; #开启gzip压缩输出
	gzip_min_length 1k; #最小压缩文件大小
	gzip_buffers 4 16k; #压缩缓冲区
	gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
	gzip_comp_level 2; #压缩等级
	gzip_types text/plain application/x-javascript text/css application/xml;
	
	#压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
	gzip_vary on;
	#limit_zone crawler $binary_remote_addr 10m; #开启限制IP连接数的时候需要使用

	#nginx版本信息关闭
	server_tokens off;

	upstream malu.me {
		#upstream的负载均衡,weight是权重,可以根据机器配置定义权重。weigth参数表示权值,权值越高被分配到的几率越大。
		server 192.168.0.222:80 weight=3;
		server 192.168.0.221:80 weight=2;
		server 192.168.0.220:80 weight=3;
	}

	#虚拟主机的配置
	server {

		#监听端口
		listen 80;
		
		#域名可以有多个,用空格隔开
		server_name blog.malu.me malu.me;
		index index.html index.htm index.php;
		root /data/www/html;

		location ~ .*.(php|php5)?$ {
			fastcgi_pass 127.0.0.1:9000;
			fastcgi_index index.php;
			include fastcgi.conf;
		}

		#图片缓存时间设置
		location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ {
			expires 10d;
		}

		#JS和CSS缓存时间设置
		location ~ .*.(js|css)?$ {
			expires 1h;
		}

		#日志格式设定 $scheme访问协议 $request_time请求时间
		log_format access '$remote_addr - $remote_user [$time_local] "$scheme $request" '
		'$status $body_bytes_sent "$http_referer" '
		'"$http_user_agent" $http_x_forwarded_for "$request_time"';
		
		#定义本虚拟主机的访问日志
		access_log /var/log/nginx/access.log access;

		#对 "/" 启用反向代理
		location / {
			proxy_pass http://127.0.0.1:88;
			proxy_redirect off;
			proxy_set_header X-Real-IP $remote_addr;
			
			#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
			
			#以下是一些反向代理的配置,可选。
			proxy_set_header Host $host; #向后台主机传递host头
			client_max_body_size 10m; #允许客户端请求的最大单文件字节数
			client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数,
			proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
			proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
			proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
			proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
			proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的设置
			proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
			proxy_temp_file_write_size 64k;
			#设定缓存文件夹大小,大于这个值,将从upstream服务器传
		}

		#设定查看Nginx状态的地址
		location /NginxStatus {
			stub_status on;
			access_log on;
			auth_basic "NginxStatus";
			auth_basic_user_file conf/htpasswd;
			#htpasswd文件的内容可以用apache提供的htpasswd工具来产生。
		}

		#本地动静分离反向代理配置
		#所有jsp的页面均交由tomcat或resin处理
		location ~ .(jsp|jspx|do)?$ {
			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_pass http://127.0.0.1:8080;
		}

		#所有静态文件由nginx直接读取不经过tomcat或resin
		location ~ .*.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$ {
			expires 15d; 
		}
		
		location ~ .*.(js|css)?$ {
			expires 1h;
		}
	}
}

log_format日志格式说明

$remote_addr, $http_x_forwarded_for 记录客户端IP地址
$remote_user 记录客户端用户名称
$request 记录请求的URL和HTTP协议
$status 记录请求状态
$body_bytes_sent 发送给客户端的字节数,不包括响应头的大小; 该变量与Apache模块mod_log_config里的“%B”参数兼容。
$bytes_sent 发送给客户端的总字节数。
$connection 连接的序列号。
$connection_requests 当前通过一个连接获得的请求数量。
$msec 日志写入时间。单位为秒,精度是毫秒。
$pipe 如果请求是通过HTTP流水线(pipelined)发送,pipe值为“p”,否则为“.”。
$http_referer 记录从哪个页面链接访问过来的
$http_user_agent 记录客户端浏览器相关信息
$request_length 请求的长度(包括请求行,请求头和请求正文)。
$request_time 请求处理时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
$time_iso8601 ISO8601标准格式下的本地时间。
$time_local 通用日志格式下的本地时间。

log写入redis

让nginx登录到syslog服务器,从syslog-ng到redis这里是我在nginx http指令中的配置

apt install syslog-ng
systemctl start syslog-ng
systemctl enable syslog-ng

log_format xxx_log_format '$remote_addr - $remote_user [$time_local] '
                       '"$request" $status $bytes_sent '
                       '"$http_referer" "$http_user_agent" "$gzip_ratio"';

在nginx server指令中

access_log syslog:server=127.0.0.1:601 xxx_log_format;

在syslog-ng config中

source s_syslog {
    udp(
        port(601)
    );
};

destination d_redis {
    redis(
        host("REDIS-IP")
        port(6379)
        command("LPUSH", "access_logs", "${MESSAGE}")
    );
};

log {
    source(s_syslog);
    destination(d_redis);
};

ip访问频率限制

使用limit_req_zone和limit_req指令配合使用来达到限制。一旦并发连接超过指定数量,就会返回503错误。

http{
    ...

    #定义一个名为allips的limit_req_zone用来存储session,大小是10M内存,
    #以$binary_remote_addr 为key,限制平均每秒的请求为20个,
    #1M能存储16000个状态,rete的值必须为整数,
    #如果限制两秒钟一个请求,可以设置成30r/m

    limit_req_zone $binary_remote_addr zone=allips:10m rate=20r/s;
    ...
    server{
        ...
        location {
            ...

            #限制每ip每秒不超过20个请求,漏桶数burst为5
            #brust的意思就是,如果第1秒、2,3,4秒请求为19个,
            #第5秒的请求为25个是被允许的。
            #但是如果你第1秒就25个请求,第2秒超过20的请求返回503错误。
            #nodelay,如果不设置该选项,严格使用平均速率限制请求数,
            #第1秒25个请求时,5个请求放到第2秒执行,
            #设置nodelay,25个请求将在第1秒执行。

            limit_req zone=allips burst=5 nodelay;
            ...
        }
        ...
    }
    ...
}

Nginx + php-fpm

Nginx相比Apache高并发优势明显,下面介绍php7.1的部署过程:

1.安装

apt-get install php7.1-fpm

2.修改配置文件

php-fpm

vim /etc/php/7.1/fpm/pool.d/www.conf

;listen = /run/php/php7.1-fpm.sock
listen = 127.0.0.1:9000   #推荐用TCP socket方式

nginx

vim /etc/nginx/sites-enabled/default

location ~ \.php$ {
	fastcgi_split_path_info ^(.+\.php)(/.+)$;
	# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

	# With php5-cgi alone:
	fastcgi_pass 127.0.0.1:9000;
	# With php5-fpm:
	#fastcgi_pass unix:/var/run/php5-fpm.sock;
	#fastcgi_pass unix:/run/php/php7.1-fpm.sock;   #Unix socket方式
	fastcgi_index index.php;
	include fastcgi_params;
}

3.重启2个进程

service nginx restart
service php7.1-fpm restart

socket.io (websocket)反向代理

server {  
    listen 80;
    listen 443 ssl;
    server_name example.domain;
    root "/project/path";

    index index.html index.htm index.php;

	// ssl密钥设定
    ssl on;
    ssl_certificate /ssl/malu.pem;
    ssl_certificate_key  /ssl/malu.key;
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
    ssl_prefer_server_ciphers on; 

    // 配置负载的后端
    upstream socket_nodes {
        ip_hash;
        server server1.app:5000 weight=5;
        server server2.app:5000;
        server server3.app:5000;
        server server4.app:5000;
    }

    location /socket.io/ {
        proxy_pass http://socket_nodes;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-real-ip $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
    }

    // 其他配置项
    // ...
}

WebSocket proxying 官方文档:http://nginx.org/en/docs/http/websocket.html

nginx服务器安装及配置文件详解: http://seanlook.com/2015/05/17/nginx-install-and-config/