零、前言
本文先介绍了什么是nginx,然后从零开始给一台Linux服务器安装nginx,最后介绍了相关的nginx配置示例。
本文基于系统:Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-60-generic x86_64)
本文使用远程SSH客户端:OpenSSH Client
本文基于nginx版本:1.24.0
nginx官网:点击前往
注:在官网上,我看到官网都是叫“nginx”或“NGINX”,而国内外的各种文章/书有的叫“Nginx”,有的叫“nginx”,有的叫“NGINX”,看样子似乎都行。
注:虽然基本都是在Linux上玩nginx,但是其实nginx有支持windows,且一直在更新,只是没看到支持到了什么程度(有些较早的文章说相比于Linux缺乏了不少功能,随着时间的推进,不知道补齐功能了没有)。
一、什么是nginx
nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server, originally written by Igor Sysoev. For a long time, it has been running on many heavily loaded Russian sites including Yandex, Mail.Ru, VK, and Rambler. According to Netcraft, nginx served or proxied 20.72% busiest sites in December 2023.
——官网介绍
收购变化:2019 年 3 月,著名硬件负载均衡厂商 F5 宣布收购 nginx,nginx 成为 F5 的一部分。
特点:系统资源消耗低、运行稳定且具有高性能的并发处理能力。
编写语言:C
nginx的不同版本:
开源版 nginx(官方):2004年发布。
商业版 nginx plus(官方):2013年推出。
淘宝版 Tengine:2011年开始开源。
OpenResty:开源。
二、安装(Linux-Ubuntu)
官方教程:Installing nginx
注:不同操作系统平台安装的方式存在差异,建议遵循上面官方教程的步骤执行为主。
注:这里是使用apt安装的方式,还有通过压缩包安装的,建议另行寻找教程。
1、安装必备组件
执行命令:sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring
注意:可以先一个一个检测一下看看是否已经安装了,已安装了就不要重复安装。
Linux因为安装软件的方式多种多样,实在是不好检查一个软件是否真的没安装。
可能是用rpm安装的(检查命令例如:rpm -qa|grep curl)
可能是用apt安装的(检查命令例如:apt list --installed|grep curl)
源码编译安装的等等。
还可以检查一下相关文件是否存在,比如用 whereis curl
注意:如果rpm等没安装,则基本可以排除用对应方式安装的可能。
2、导入官方的 nginx 签名密钥
目的:以便 apt 可以验证下载的nginx软件包的真实性。
执行命令:curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
执行示例
命令解析(扩展了解):
curl 地址:发出get请求,这里是向nginx官网请求获取签名密钥。
gpg:GNU Privacy Guard,是PGP的一个开源替代品。PGP,即Pretty Good Privacy,一个专有的加密程序,用于对文件和目录进行签名、加密和解密。
gpg --dearmor:将下载到的pgp内容转换成gpg内容。
tee:将转换后的gpg内容输出到指定的文件中(命令行输出流照常输出)。
/usr/share/keyrings:在Ubuntu上,该目录是转换后的GPG文件的推荐位置,因为它是Ubuntu存储keyring的默认位置。
>/dev/null:在 Linux 系统中,/dev/null 是一个特殊的文件,它被称为“空设备”。它没有任何数据,读取它永远不会产生任何输出,写入它永远不会导致任何数据被存储。/dev/null 起着丢弃数据的作用,可以用于一些需要忽略输出或者输入的场合。>/dev/null表示禁止输出。(这里是让原本会显示的gpg密钥不显示出来)
3、验证下载的文件是否包含正确的密钥
执行命令:gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
执行示例
注意:执行结果要和官网提供的示例结果做比对,如果输出的密钥信息不对,就要删除掉,重新下。点击前往官网
命令解析(扩展了解):
--dry-run:gpg指令,表示不进行任何更改,仅查看密钥
--quiet:gpg指令,表示尽量保持静默(让GPG别打印它的一些运行信息)
--no-keyring:gpg指令,表示不使用任何keyring。这将会覆盖默认和其他指定keyring的指令。(gpg几乎所有操作都需要一个keyring,如果不用这个选项则要么是gpg会使用默认的keyring,要么你必须指定一个keyring)
--import --import-options import-show:gpg指令,表示显示导入的密钥的信息,和--dry-run结合就是只查看密钥,不修改/导入到系统中。
4、 设置apt存储库为找稳定版的nginx软件包
执行命令:echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
其实就是往apt的配置里,写上去哪里下nginx,以及用什么密钥去校验。
5、设置存储库固定以优先选择nginx官方提供的发行版
执行命令:echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" | sudo tee /etc/apt/preferences.d/99nginx
执行示例
其实本身也是在给apt写配置信息,优先级为900。
6、apt获得系统上所有包的最新信息
执行命令:sudo apt update
该命令实际上是为了加载nginx的最新信息,使得等下就可以安装最新的nginx官方提供的稳定版的nginx。
7、安装nginx
执行命令:sudo apt install nginx
执行示例
注意:提示文本最后第二行,有写nginx.service的绝对路径(而且还配置进了sytemctl里),比如我的是在这里:/lib/systemd/system/nginx.service
注意安装过程中有文本提示:The following packages were automatically installed and are no longer required.
所以我们可以按照提示,删除这些无用的包。
执行命令:sudo apt autoremove (当然,删不删取决于你,都行)
三、配置与操作
nginx的各种官方文档(包括配置文件的各字段说明):nginx documentation
nginx操作指引:Beginner’s Guide
1、先查看一下nginx服务的启动配置
service nginx status (或systemctl status nginx)
服务未启动
注意服务运行中时的Unit描述内容里的第二行:
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Loaded 描述的是操作系统启动时会不会启动这个服务。
enabled 表示开机时启动,disabled 表示开机时不启动。
该服务路径为:/lib/systemd/system/nginx.service
vendor preset 为 Linux发行版 默认配置,是在Linux 发行制作过程预设的,一般一些重要的系统服务会配置为enabled。使用 systemctl enable/disable 来设置为开机自启动,并没有设置到操作系统的发行预设里,所以进行设置开机启动项的时候,不会影响到 vendor preset 的值。 如果是同一名称的服务(例如现在这个nginx.service),既使用了 systemctl enable,又配置了vendor preset,systemctl enable/disable 的优先级要高于vendor preset(毕竟 systemctl 相当于是用户手动设置)。
如果要禁止nginx.service开机自启动,则可以执行命令:systemctl disable nginx.service
如果要设置nginx.service开机自启动,则可以执行命令:systemctl enable nginx.service
2、启动nginx
执行命令:service nginx start (或:systemctl start nginx)
注意:用 service/systemctl 启动的话,就得用 service/systemctl 停止nginx,service和sytemctl可以混用,但是不能和nginx -s xxx混用,具体为啥请见下文 【停止nginx】的内容。
(直接操作nginx来启动的方式,见下文)
启动实例
注:service nginx status 是看启动后的情况,非必须执行。
通过查看nginx服务的信息,可以看到几个关键信息。
① 执行的nginx程序位于 /usr/sbin/nginx
所以,实际上你也可以去到这个目录,直接执行这个 可执行文件 来启动nginx。(如果是以本文的安装方式,任意位置都能直接执行nginx,不需要特意到达文件所在目录)
步骤:
执行命令:cd /usr/sbin
执行命令:nginx
注意,这种方式启动的话,Linux服务感知不到nginx已经启动了。所以此后不能用service和systemctl来管理。
示例
② nginx加载的配置文件在/etc/nginx/nginx.conf
按照官方描述,默认情况下,nginx的配置文件叫nginx.conf,会被放置在这几个目录之一中:
/usr/local/nginx/conf
/etc/nginx
/usr/local/etc/nginx
③ nginx有三个进程,一个主进程,多个工作进程
nignx正常会有一个主进程,多个工作进程。
主进程用来读取和验证配置,以及管理工作进程(比如创建)。
工作进程用来真正意义上的处理请求。工作进程的数量由配置文件进行设置,默认是会和CPU核心数一致(配置文件里对应值配置成auto)。
默认情况下,nginx启动后,就在监听80端口。
可以通过端口监听命令查看到,执行命令:netstat -ntulp | grep nginx
此时浏览器中输入:服务器IP:80 (例如:127.0.0.1:80)就能访问到nginx的默认页面(该页面也是用来证明nginx运行正常的途径)(因为80是http的默认端口,所以访问80端口时其实也可以不附带端口号)
nginx默认页面
注:如果访问不通,可能是 防火墙 或 安全组 没开启对应端口的访问允许。
3、修改nginx配置以定义代理
前文中,我们已经知道nginx所加载的配置文件的路径。
那么,我们就可以去编辑对应的配置文件。
注:下文仅以常见的http代理为例,不涉及mail等代理。
nginx修改配置文件前须知:
① 其实nginx的代理,简单来说就是在一个个顶级上下文(如:http,stream,mail)里写一个一个的server块。具体server块是直接放在nginx.conf里,还是以独立的文件形式存在再配置好路径加载,都行。(这也就使得下文定义代理的修改配置方式有两种)
② 监听的端口,需要检查Linux防火墙是否允许访问(命令:sudo ufw status),如果是云服务器,则还要检查云服务的安全组是否开放了对应端口。
Ubuntu防火墙允许外部访问端口(以12300为例),执行命令:sudo ufw allow 12300
Ubuntu防火墙删除增加的规则(以12300为例),执行命令:sudo ufw delete allow 12300
接下来是操作:
(1) 进入到配置文件所在目录(比如我的在 /etc/nginx/ )
执行命令:cd /etc/nginx/
(2) 修改配置(方式一:直接修改配置文件nginx.conf)(不太推荐在这里写server)
执行命令: vi nginx.conf
默认内容
各个字段含义:
error_log /var/log/nginx/error.log notice:配置nginx运行期间的处理流程相关信息的日志输出路径,不只是错误日志信息(当前级别为notice,所有选项:debug
, info
, notice
, warn
, error
, crit
, alert
, emerg
)
worker_connections 1024:单个工作进程的最大同时连接数(所有连接,包括与客户端和代理服务器之间的连接等)。需要注意不能超过系统的最大同时打开文件数。
log_formatmain xxxx:配置access_log的日志格式,main表示这个格式的命名,后面一大串就是格式定义。
access_log /var/log/nginx/access.log main:配置请求接入,即访问的相关信息日志输出路径。main是指定使用的日志格式的名字。
include /etc/nginx/conf.d/*.conf:加载指定的文件。这里是指明当前的http上下文额外加载的配置文件路径(注意通配符)
例:新增http代理server(代理静态文件的加载)
执行命令:vi nginx.conf
访问某文件夹里的静态文件代理
在其他PC上获取nginx代理的这个静态文件内容,执行命令:curl 128.0.0.1:12302/files/example.txt
(128.0.0.1是nginx所在服务器的地址)
(example.txt是nginx所在服务器上/apps/files文件夹中的一个文件)
请求获取文件内容示例
listen值将被nginx用于监听网络请求,可以是 IP 协议的形式(主机有多个IP时可以指定监听某个IP下的请求,不写IP只写端口就是所有IP的该端口),也可以是 UNIX 域套接字(sock文件路径)。如果不设置 listen 指令,nginx 在以超管运行时则监听 80 端口,以非超管运行时则监听 8000 端口。
server_name,有域名写域名,没域名写服务器的ip地址。
location 表示请求路径匹配(后面跟着的URI可以写正则表达式),以匹配程度最高的作为优先,然后是按出现顺序。匹配到后,就会进入location里面。
root设置请求的根路径。这里配置的路径,会被放在location的URI前面。例如本例中,root配置的是【/apps/】 ,location匹配的是 【/files/】 ,则请求 【128.0.0.1:12302/files/example.txt 】会变成 【128.0.0.1:12302/apps/files/example.txt 】。
(实测,root 路径的最后加不加斜杠都一样,即也可以写成【/apps】)
(实测,像此处访问本地路径,location 路径的最后加不加斜杠都一样,即也可以写成 【/files】)
(如果路径规则写错,获取文件失败,则会在error_log中看到对应的日志信息)
(2)修改配置 (方式二:独立配置文件)(推荐如此新增server)
进入前文nginx.conf中的【额外加载的配置文件路径】(例如我的是在:/etc/nginx/conf.d/)
执行命令:cd /etc/nginx/conf.d/
新建的配置,只要文件名符合 *.conf 的命名格式,就会被nginx加载(依据nginx.conf中的加载配置)。
例1:代理前端静态文件的加载
执行命令(新建并编辑新配置文件):vi simpleFront.conf
文件里输入如下的内容:
server {
listen 12300;
server_name 127.0.0.1;
location / {
root /apps/simpleWeb/dist;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
index 定义将用作索引的文件,名称可以包含变量,可以提供多个,最后一个文件可以是绝对路径,nginx将按照顺序检查提供的文件。使用索引文件,会使得内部进行重定向,即路径只输入到了 / ,但是最终重定向加载了index匹配到的文件(比如常见的Vue项目的index.html)。
error_page 定义发生特定错误时(500 502之类的HTTP状态码)将给客户端展示的页面(如 /50x.html最终指向的/usr/share/nginx/html/50x.html)。
例2:代理后端服务
执行命令(新建并编辑新配置文件):vi simpleBackend.conf
输入如下的内容:
server {
listen 12301;
server_name 127.0.0.1;
charset utf-8;
location / {
proxy_pass http://127.0.0.1:12313;
}
}
charset将指定的字符集添加到响应的标头“Content-Type”上,例如常见的utf-8。
proxy_pass表示要把监听到的请求转发到哪里(哪个被代理的服务),例如这里写的是【本机的12313端口】(本机访问本机时防火墙不需要开放12313端口出来)。转发的目标路径,可以在端口后面加上URI路径,例如 http://127.0.0.1:12313/test/ 。
4、热更新nginx配置
先到达nginx可执行文件所在目录(前文启动的时候可以看到所在目录),执行命令:cd /usr/sbin/
注:如果是按照前文的方式安装,则在任意位置都能执行nginx。可以不用到达nginx可执行文件所在的目录。
执行nginx校验配置文件命令:nginx -t
校验通过
如果校验没通过,就要回过头改改自己写的配置了。
热更新nginx配置,执行命令:nginx -s reload
注意,如果配置文件格式不对,nginx -s reload 会失败,此时 nginx使用的还是旧的配置信息。
实际上,也可以先停止nginx,然后再启动,以这种“重启”的方式来达到更新nginx配置的目的。
5、停止nginx
(1)service/systemctl
如果启动时,执行命令: service nginx start(或:systemctl start nginx),则建议执行命令:service nginx stop(或:systemctl stop nginx)来停止nginx。
(2)nginx自身
如果启动时,执行命令: nginx,则建议用下方的方式来停止nginx。
执行命令:nginx -s quit
执行命令:nginx -s stop
两种方式都是停止nginx服务。
quit是比较优雅地退出,会让工作线程把所有当前的请求处理完再停止。
stop是快速退出,不管工作线程是否正在处理请求。
注意:官网有提示说,执行停止nginx的命令的用户要和启动nginx时一致。(不太确定不一致会怎样)
额外说明:
执行命令:service nginx start(或:systemctl start nginx)启动,但是用nginx自身命令停止nginx,实测会导致nginx虽然明面上关闭退出了,但是进程依然在。(如果反过来,则执行无效)
执行命令: netstat -ntulp 可以看到:
执行命令: service nginx status 会看到:
此时,若要再启动nginx,就要先杀死这些残存的进程。
查看监听端口的程序,执行命令:lsof -i:80 (其中80是前文发现nginx残存进程还在监听的端口)
依据结果执行命令:kill 522085 (522085是残存的进程ID)
把nginx残存的进程全部干掉,就行了。
四、Nginx 更新
如果已经按照以上流程完成安装旧版本的 Nginx,现在准备更新Nginx,则很简单。
1、更新 APT 源里的 Nginx的信息
apt update
如果出现类似报错:
An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://nginx.org/packages/ubuntu jammy InRelease: The following signatures were invalid: EXPKEYSIG ABF5BD827BD9BF62 nginx signing key <signing-key@nginx.com>
Failed to fetch http://nginx.org/packages/ubuntu/dists/jammy/InRelease The following signatures were invalid: EXPKEYSIG ABF5BD827BD9BF62 nginx signing key <signing-key@nginx.com>
则需要更新 nginx 签名密钥:
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
更新后,可以通过以下命令,查看 APT 可以安装的 Nginx的版本信息。
apt-cache show nginx
2、执行更新Nginx命令
不指定版本的话,会以最新版本进行更新:
apt install nginx
此时,可以通过以下命令查看当前 Nginx 版本
nginx -v
五、相关词汇
1、C10K问题
2003年由 Dan Kegel 在个人网站上提出的——单机同时处理10k个连接问题。
文章链接:The C10K Problem
我的译文:The C10K Problem(译文)
具体刨析可以看原文,也可以去搜索一下相关分析,有很多文章,这里不赘述。
另外,虽然现在早已解决了C10K问题,但是我们也即将迎来C10M问题(即现在是10M)。如果有兴趣,可以另行搜索相关研究材料。
2、LNMP/LEMP/LAMP
LNMP 的全称是 Linux + nginx + MySQL + PHP (国外喜欢简称为LEMP,搜英文资料需要搜LEMP)
LAMP 的全称是 Linux + Apache + MySQL + PHP
3、反向代理(reverse proxy)
nginx就是一个反向代理服务。
简述:代理服务器“冒充”真正的目标服务器,给服务使用者(如浏览器)提供服务。对服务使用者(如浏览器)而言,并不关心谁才是真的目标服务器,反正它获得的服务是真的就行。(服务使用者不知道服务被代理了)
正向代理(proxy)简述:服务使用者主动配置代理服务器的地址,以代理服务器作为“中间商”去访问真正的目标服务器,以此获取服务。(服务使用者知道服务被代理了)
以浏览器为例,“是否知道服务被代理”,对应的就是有没有去给目标网址配置代理服务器地址。
4、事件驱动(Event-Driven)
即nginx基于的模型。
比喻:B一直在等着某事件的发生(事件处理器进行事件监听)。A做了某个行为,于是A大声喊“我产生了某事件”(事件源主动产生事件)。B听到这句话(事件处理器监听到事件发生),于是B开始依据事件信息做特定的事情(事件处理器执行事件处理)。
5、异步非阻塞I/O模型
即nginx基于的模型。
Linux:epoll
FreeBSD:kquene
Windows:IOCP
Solaris:/dev/poll
上面各个平台接口的统一封装库:libevent
6、MIME
全程:Multipurpose Internet Mail Extensions(多用途互联网邮件扩展类型)