简介
nginx是一个HTTP和反向代理服务器,一个邮件代理服务器和一个通用的TCP / UDP代理服务器,最初由Igor Sysoev编写。
Nginx的轻量级、内存占用少、启动极快,高并发能力强的特性,使它在互联网项目中广泛应用

正向代理
由于防火墙的原因,我们并不能直接访问谷歌,那么我们可以借助VPN来实现,这就是一个简单的正向代理的例子。这里你能够发现,正向代理“代理”的是客户端,而且客户端是知道目标的,而目标是不知道客户端是通过VPN访问的。
反向代理
当我们在外网访问百度的时候,其实会进行一个转发,代理到内网去,这就是所谓的反向代理,即反向代理“代理”的是服务器端,而且这一个过程对于客户端而言是透明的。
Nginx的技术架构
Master进程的作用是读取并验证配置文件nginx.conf;管理worker进程;
Worker进程的作用:每一个Worker进程都维护一个线程(避免线程切换),处理连接和请求;
注意Worker进程的个数由配置文件决定,一般和CPU个数相关(有利于进程切换),配置几个就有几个Worker进程。
特点:
-
主进程Master
Nginx启动时,会生成两种类型的 进程*,一个是 主进程(master),一个(windows版本的目前只有一个)或 多个工作进程(worker)。主进程 并不处理网络请求,主要负责 调度工作进程,也就是图示的3项:加载配置、启动工作进程 及 非停升级。所以,Nginx启动以后,查看操作系统的进程列表,我们就能看到 至少有两个Nginx进程。 -
工作进程Worker
服务器实际 处理网络请求 及 响应 的是 工作进程(
worker),在类unix系统上,Nginx可以配置 多个worker,而每个worker进程 都可以同时处理 数以千计 的 网络请求。 -
模块化设计
标准HTTP模块、可选的HTTP模块(gzip等)、邮件服务、第三方(Lua)
Nginx的worker进程,包括 核心 和 功能性模块,核心模块 负责维持一个 运行循环(run-loop),执行网络请求处理的 不同阶段 的模块功能,比如:网络读写、存储读写、内容传输、外出过滤,以及 将请求发往上游服务器 等。而其代码的 模块化设计,也使得我们可以根据需要对 功能模块 进行适当的 选择 和 修改,编译成具有 特定功能 的服务器。 -
事件驱动模型
基于 异步及非阻塞 的 事件驱动模型,可以说是
Nginx得以获得 高并发、高性能 的关键因素,同时也得益于对Linux、Solaris及类BSD等操作系统内核中 事件通知 及I/O性能增强功能 的采用,如kqueue、epoll及event ports。 -
代理设计
Nginx高可用
VRRP(Virtual Router Redundancy Protocol),即虚拟路由冗余协议。可以认为它是实现路由器高可用的容错协议,即将多台提供相同功能的路由器组成一个路由器组(Router Group),这个组里面有一个master和多个backup,但在外界看来就像一台一样,构成虚拟路由器,拥有一个虚拟IP(vip,也就是路由器所在局域网内其他机器的默认路由),占有这个IP的master实际负责ARP相应和转发IP数据包,组中的其它路由器作为备份的角色处于待命状态。master会发组播消息,当backup在超时时间内收不到vrrp包时就认为master宕掉了,这时就需要根据VRRP的优先级来选举一个backup当master,保证路由器的高可用。
Keepalived是一个基于VRRP协议来实现的服务高可用方案,可以利用其来避免IP单点故障,类似的工具还有heartbeat、corosync、pacemaker。但是它一般不会单独出现,而是与其它负载均衡技术(如lvs、haproxy、nginx)一起工作来达到集群的高可用。
KeepAlived + Nginx来组成高可用的方案:
第一:请求不要直接打到Nginx上,应该先通过Keepalived(这就是所谓虚拟IP,VIP)
第二:Keepalived应该能监控Nginx的生命状态(提供一个用户自定义的脚本,定期检查Nginx进程状态,进行权重变化,,从而实现Nginx故障切换)
Nginx服务安装
Centos安装方式
推荐使用在线安装方式:
| 分类 | yum方式 | 源码安装 |
|---|---|---|
| 网络 | 需要 | 可以不需要 |
| 安装位置 | /etc/nginx配置文件,/usr/sbin/nginx | /usr/local/nginx目录 |
| 管理命令 | 提供 | 不提供 |
| 启动 | service nginx start | 执行绝对路径/usr/local/nginx/sbin/nginx |
| 删除 | yum remove nginx或者rpm -e nginx | rm -rf /usr/local/nginx |
-
在线安装
添加nginx的repo:
$ vim /etc/yum.repos.d/nginx.repo输入以下内容:
[nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=0 enabled=1:wq保存后,使用yum update,接下来就是安装了。yum install -y nginx # 管理命令: # 启动/停止/重启 service nginx start/stop/restart # 卸载 yum remove -y nginx # 或者强制卸载,不考虑依赖 rpm -e nginx -
源码安装
-
安装对应的依赖:
yum -y install gcc gcc-c++ make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel -
下载源码包:
wget -O /tmp/nginx.tar.gz http://nginx.org/download/nginx-<version>.tar.gz比如:
wget -O /tmp/nginx.tar.gz http://nginx.org/download/nginx-1.17.0.tar.gz -
解压
cd /tmp/ tar zxvf nginx.tar.gz -
编译
$ ./configure Configuration summary - using system PCRE library - OpenSSL library is not used - using system zlib library nginx path prefix: "/usr/local/nginx" nginx binary file: "/usr/local/nginx/sbin/nginx" nginx modules path: "/usr/local/nginx/modules" nginx configuration prefix: "/usr/local/nginx/conf" nginx configuration file: "/usr/local/nginx/conf/nginx.conf" nginx pid file: "/usr/local/nginx/logs/nginx.pid" nginx error log file: "/usr/local/nginx/logs/error.log" nginx http access log file: "/usr/local/nginx/logs/access.log" nginx http client request body temporary files: "client_body_temp" nginx http proxy temporary files: "proxy_temp" nginx http fastcgi temporary files: "fastcgi_temp" nginx http uwsgi temporary files: "uwsgi_temp" nginx http scgi temporary files: "scgi_temp" -
安装
make && make install -
管理方法:
直接可以使用可执行文件进行启动/停止/重启
# 启动 /usr/local/nginx/sbin/nginx # 停止 /usr/local/nginx/sbin/nginx -s stop # 重启 /usr/local/nginx/sbin/nginx -s reload -
管理脚本
$ vi /etc/init.d/nginx输入如下内容:
#!/bin/sh # # nginx - this script starts and stops the nginx daemon # # chkconfig: - 85 15 # description: NGINX is an HTTP(S) server, HTTP(S) reverse \ # proxy and IMAP/POP3 proxy server # processname: nginx # config: /usr/local/nginx/conf/nginx.conf # config: /etc/sysconfig/nginx # pidfile: /usr/local/nginx/logs/nginx.pid # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. [ "$NETWORKING" = "no" ] && exit 0 nginx="/usr/local/nginx/sbin/nginx" prog=$(basename $nginx) NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf" [ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx lockfile=/var/lock/subsys/nginx make_dirs() { # make required directories user=`$nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=\([^ ]*\).*/\1/g' -` if [ -z "`grep $user /etc/passwd`" ]; then useradd -M -s /bin/nologin $user fi options=`$nginx -V 2>&1 | grep 'configure arguments:'` for opt in $options; do if [ `echo $opt | grep '.*-temp-path'` ]; then value=`echo $opt | cut -d "=" -f 2` if [ ! -d "$value" ]; then # echo "creating" $value mkdir -p $value && chown -R $user $value fi fi done } start() { [ -x $nginx ] || exit 5 [ -f $NGINX_CONF_FILE ] || exit 6 make_dirs echo -n $"Starting $prog: " daemon $nginx -c $NGINX_CONF_FILE retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc $prog -QUIT retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart() { configtest || return $? stop sleep 1 start } reload() { configtest || return $? echo -n $"Reloading $prog: " killproc $nginx -HUP RETVAL=$? echo } force_reload() { restart } configtest() { $nginx -t -c $NGINX_CONF_FILE } rh_status() { status $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart|configtest) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}" exit 2 esac添加开机启动:
# 给予执行权限 chmod a+x /etc/init.d/nginx # 设置开机启动 chkconfig nginx on # 启动 systemctl start nginx
Ubuntu安装方式
-
在线方式
sudo apt-get install nginx -
源码方式
安装依赖
# 安装gcc g++ sudo apt-get install build-essential sudo apt-get install libtool # 安装pcre依赖库(http://www.pcre.org/) sudo apt-get update sudo apt-get install libpcre3 libpcre3-dev # 安装zlib依赖库(http://www.zlib.net) sudo apt-get install zlib1g-dev # 安装SSL依赖库(16.04默认已经安装了) sudo apt-get install openssl下载源码启动:
# 下载最新版本: # 下面的version可以改为对应的版本 # http://nginx.org/download/nginx-1.17.0.tar.gz wget -O /tmp/nginx.tar.gz http://nginx.org/download/nginx-<version>.tar.gz # 解压: cd /tmp/ tar -zxvf nginx.tar.gz # 进入解压目录: cd nginx-1.13.6 # 配置: ./configure --prefix=/usr/local/nginx # 编译: make # 安装: sudo make install # 启动: #注意:-c 指定配置文件的路径,不加的话,nginx会自动加载默认路径的配置文件,可以通过-h查看帮助命令。 #查看进程: sudo /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf # 查看进程启动状态 ps -ef | grep nginx
Nginx配置及优化
配置文件结构
... #全局块
events { #events块
...
}
http #http块
{
... #http全局块--start
server #server块
{
... #server全局块
location [PATTERN] #location块
{
...
}
location [PATTERN]
{
...
}
}
server
{
...
}
... #http全局块--end
}
- 全局块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。
- events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。
- http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。
- server块:配置虚拟主机的相关参数,一个http中可以有多个server。
- location块:配置请求的路由,以及各种页面的处理情况。
配置优化
配置文件:
user www-data;
pid /run/nginx.pid;
# worker_processes用来设置Nginx服务的进程数。推荐是CPU内核数或者内核数的倍数,推荐使用CPU内核数
worker_processes 4;
# 默认情况下,Nginx的多个进程有可能跑在某一个CPU或CPU的某一核上,导致Nginx进程使用硬件的资源不均
worker_cpu_affinity 0001 0010 0100 1000;
# 设置一个进程理论允许的最大连接数,理论上越大越好,但不可以超过worker_rlimit_nofile的值
worker_rlimit_nofile 65535;
events {
# 设置事件驱动模型,是内核2.6以上支持
use epoll;
worker_connections 65535;
accept_mutex off;
multi_accept off;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 60 50;
send_timeout 10s;
types_hash_max_size 2048;
client_header_buffer_size 4k;
client_max_body_size 8m;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_min_length 1024;
gzip_vary on;
gzip_comp_level 2;
gzip_buffers 32 4k;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
nginxs配置说明:
worker_connections
设置一个进程理论允许的最大连接数,理论上越大越好,但不可以超过worker_rlimit_nofile的值。还有个问题,linux系统中有个指令open file resource limit,它设置了进程可以打开的文件句柄数量,可以用下面的指令查看你的linux系统中open file resource limit指令的值,cat /proc/sys/fs/file-max
可以将该指令设置为23900251
echo "2390251" > /proc/sys/fs/file-max
sysctl -p
压测工具Apache ab
我们要测试 nginx 的负载能力,需要借助压力测试工具。本博客是使用 Apache 服务器自带的一个 web 压力测试工具 ApacheBench ,简称 ab。ab 是一个命令行工具,即通过 ab 命令行,模拟多个请求同时对某一 URL 地址进行访问,因此可以用来测试目标服务器的负载压力。
yum -y install httpd-tools
# 查看安装结果
ab -V
# 简单的使用
# -c:一次并发请求的数量;-n:请求总次数
ab -c 5000 -n 200000 http://10.211.55.6:80/index.html
ulimit -a
ulimit 跟参数修改值
-
其他优化
net.ipv4.ip_forward = 0 net.ipv4.conf.default.rp_filter = 1 net.ipv4.conf.default.accept_source_route = 0 kernel.sysrq = 0 kernel.core_uses_pid = 1 # 开启SYN Cookies,当出现SYN等待队列溢出时,启用cookies来处理。 net.ipv4.tcp_syncookies = 1 kernel.msgmnb = 65536 kernel.msgmax = 65536 kernel.shmmax = 68719476736 kernel.shmall = 4294967296 # timewait的数量,默认是180000 net.ipv4.tcp_max_tw_buckets = 6000 net.ipv4.tcp_sack = 1 net.ipv4.tcp_window_scaling = 1 net.ipv4.tcp_rmem = 4096 87380 4194304 net.ipv4.tcp_wmem = 4096 16384 4194304 net.core.wmem_default = 8388608 net.core.rmem_default = 8388608 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 # # 每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。 net.core.netdev_max_backlog = 262144 # web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义 的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值 net.core.somaxconn = 262144 # 系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤儿连接将即刻被复位并打印出警告信息。这个限制仅仅 是为了防止简单的DoS攻击,不能过分依靠它或者人为地减小这个值,更应该增加这个值(如果增加了内存之后)。 net.ipv4.tcp_max_orphans = 3276800 # 记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M内存的系统而言,缺省值是1024,小内存的系统则是128。 net.ipv4.tcp_max_syn_backlog = 262144 # 时间戳可以避免序列号的卷绕。一个1Gbps的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包。这里需要将其关掉。 net.ipv4.tcp_timestamps = 0 # 为了打开对端的连接,内核需要发送一个SYN并附带一个回应前面一个SYN的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK包的数量。 net.ipv4.tcp_synack_retries = 1 # 在内核放弃建立连接之前发送SYN包的数量。 net.ipv4.tcp_syn_retries = 1 # 启用timewait快速回收 net.ipv4.tcp_tw_recycle = 1 # 开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接。 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_mem = 94500000 915000000 927000000 # 如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。对端可以出错并永远不关闭连接,甚至意外当机。缺省值是60秒。 2.2 内核的通常值是180秒,你可以按这个设置,但要记住的是,即使你的机器是一个轻载的WEB服务器,也有因为大量的死套接字而内存溢出的风险,FIN- WAIT-2的危险性比FIN-WAIT-1要小,因为它最多只能吃掉1.5K内存,但是它们的生存期长些。 net.ipv4.tcp_fin_timeout = 1 # 当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时 net.ipv4.tcp_keepalive_time = 30 # 允许系统打开的端口范围 net.ipv4.ip_local_port_range = 1024 65000
HTTP(s)
HTTP/HTTPS协议
超文本传输协议(英语:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议,HTTP是万维网的数据通信的基础。
请求信息包括:请求行、请求头、空行还有其他消息体
HTTP的特点:
-
客户端&服务端
-
简单(路径+方法+传递的类型)
客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
-
灵活
HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type(Content-Type是HTTP包中用来表示内容类型的标识)加以标记。
-
无连接
无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
-
无状态有会话
HTTP协议是无状态协议,无状态是指协议对于事务处理没有记忆能力。
缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
注意,HTTP本质是无状态的,使用Cookies可以创建有状态的会话。
HTTP 的不足之处
- 通信内容使用明文——内容可能被窃听
- 不验证通信方的身份——可能遭遇伪装
- 无法验证报文的完整性——报文有可能已遭篡改
HTTPS协议:
超文本传输安全协议(英语:HyperText Transfer Protocol Secure,缩写:HTTPS;常称为HTTP over TLS、HTTP over SSL或HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,但利用SSL/TLS来加密数据包。HTTPS开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。这个协议由网景公司(Netscape)在1994年首次提出,随后扩展到互联网上。
主要作用:在不安全的网络上创建一个安全信道。
HTTPS认证原理
认证方式:数字证书
认证机构:数字证书认证机构(Certificate Authority CA),EV SSL(Extended Validation SSL Certificate)证书,OpenSSL自认证。
证书信任方式:
- 操作系统和浏览器内置
- 证书颁发机构
- 手动指定证书
SSL握手过程:
如何配置HTTPS
-
Let's Encrypt组织介绍
-
acme来自动化申请
前提:需要域名
前置条件:
-
域名, 配置DNS解析,支持列表见下方
-
有公网IP的服务器(可选)
-
安装nginx, acme.sh
配置过程:
-
安装nginx与acme.sh
安装很简单, 一个命令:
curl https://get.acme.sh | sh普通用户和 root 用户都可以安装使用. 安装过程进行了以下几步:
把 acme.sh 安装到你的 home 目录下:
~/.acme.sh/并创建 一个 bash 的 alias, 方便你的使用:
alias acme.sh=~/.acme.sh/acme.sh自动为你创建 cronjob, 每天 0:00 点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书
使用
source命令,使上面的安装生效source ~/.bashrc -
两种方式,激活SSL证书(推荐DNS)
-
http 方式
需要在你的网站根目录下放置一个文件, 来验证你的域名所有权,完成验证. 然后就可以生成证书了
acme.sh --issue -d mydomain.com -d www.mydomain.com --webroot /home/wwwroot/mydomain.com/只需要指定域名, 并指定域名所在的网站根目录. acme.sh 会全自动的生成验证文件, 并放到网站的根目录, 然后自动完成验证. 最后会聪明的删除验证文件. 整个过程没有任何副作用.
如果你用的 apache服务器, acme.sh 还可以智能的从 apache的配置中自动完成验证, 你不需要指定网站根目录:
acme.sh --issue -d mydomain.com --apache如果你用的 nginx服务器, 或者反代, acme.sh 还可以智能的从 nginx的配置中自动完成验证, 你不需要指定网站根目录:
acme.sh --issue -d mydomain.com --nginx -
dns 方式(推荐)
在域名上添加一条 txt 解析记录, 验证域名所有权。
这种方式的好处是, 你不需要任何服务器, 不需要任何公网 ip, 只需要 dns 的解析记录即可完成验证. 坏处是,如果不同时配置 Automatic DNS API,使用这种方式 acme.sh 将无法自动更新证书,每次都需要手动再次重新解析验证域名所有权。
acme.sh --issue --dns -d mydomain.com然后, acme.sh 会生成相应的解析记录显示出来, 你只需要在你的域名管理面板中添加这条 txt 记录即可.
等待解析完成之后, 重新生成证书:
acme.sh --renew -d mydomain.com注意第二次这里用的是
--renewdns 方式的真正强大之处在于可以使用域名解析商提供的 api 自动添加 txt 记录完成验证.
acme.sh 目前支持 cloudflare, dnspod, cloudxns, godaddy 以及 ovh 等数十种解析商的自动集成.
以 dnspod 为例, 你需要先登录到 dnspod 账号, 生成你的 api id 和 api key, 都是免费的. 然后:
export DP_Id="1234" export DP_Key="sADDsdasdgdsf" acme.sh --issue --dns dns_dp -d aa.com -d www.aa.com证书就会自动生成了. 这里给出的 api id 和 api key 会被自动记录下来, 将来你在使用 dnspod api 的时候, 就不需要再次指定了. 直接生成就好了:
acme.sh --issue -d mydomain2.com --dns dns_dp
-
-
配置nginx配置,设置定时任务
生成dhparam.pem
$ openssl dhparam -out dhparam.pem 2048nginx中正确的使用方法是使用
--installcert命令,并指定目标位置, 然后证书文件会被copy到相应的位置, 例如:acme.sh --installcert -d <domain>.com \ --key-file /etc/nginx/ssl/<domain>.key \ --fullchain-file /etc/nginx/ssl/fullchain.cer \ --reloadcmd "service nginx force-reload"配置文件:
# server部分 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl on; ssl_certificate /etc/nginx/ssl/fullchain.cer; ssl_certificate_key /etc/nginx/ssl/<domain>.key; # ssl_dhparam ssl_dhparam /etc/nginx/ssl/dhparam.pem; -
对网站的SSL进行检验
-
其他需要注意的地方:
- 域名备案
- 防火墙