传统的 Web 服务器,每个客户端连接作为一个单独的进程或线程处理,需在切换任务时将 CPU 切换到新的任务并创建一个新的运行时上下文,消耗额外的内存和 CPU 时间,当并发请求增加时,服务器响应变慢,从而对性能产生负面影响。
Nginx 是开源、高性能、高可靠的 Web 和反向代理服务器,而且支持热部署,几乎可以做到 7 * 24 小时不间断运行,即使运行几个月也不需要重新启动,还能在不间断服务的情况下对软件版本进行热更新。性能是 Nginx 最重要的考量,其占用内存少、并发能力强、能支持高达 5w 个并发连接数,最重要的是,Nginx 是免费的并可以商业化,配置使用也比较简单。
Nginx 的最重要的几个使用场景:
对于前端来说 Node.js 不陌生了,Nginx 和 Node.js 的很多理念类似,HTTP 服务器、事件驱动、异步非阻塞等,且 Nginx 的大部分功能使用 Node.js 也可以实现,但 Nginx 和 Node.js 并不冲突,都有自己擅长的领域。Nginx 擅长于底层服务器端资源的处理(静态资源处理转发、反向代理,负载均衡等),Node.js 更擅长上层具体业务逻辑的处理,两者可以完美组合,共同助力前端开发
apt list | grep nginx
root@rion:~# apt list | grep nginxWARNING: apt does not have a stable CLI interface. Use with caution in scripts.......
nginx-common/focal-updates,focal-security 1.18.0-0ubuntu1.4 all
nginx-core/focal-updates,focal-security 1.18.0-0ubuntu1.4 amd64
nginx-doc/focal-updates,focal-security 1.18.0-0ubuntu1.4 all
nginx-extras/focal-updates,focal-security 1.18.0-0ubuntu1.4 amd64
nginx-full/focal-updates,focal-security 1.18.0-0ubuntu1.4 amd64
nginx-light/focal-updates,focal-security 1.18.0-0ubuntu1.4 amd64
nginx/focal-updates,focal-security 1.18.0-0ubuntu1.4 all
.....
apt install nginxroot@rion:~# nginx -v
nginx version: nginx/1.18.0 (Ubuntu)
whereis nginx
来查看nginx相关的文件的位置root@rion:~# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx /usr/share/man/man8/nginx.8.gz# 文件路径说明
# /usr/sbin/nginx 终端nginx服务管理的命令
# /usr/lib/nginx nginx 相关的包文件
# /etc/nginx nginx 配置文件存放路径
# /usr/share/nginx 资源存放路径
systemctl start firewalld # 开启防火墙
systemctl stop firewalld # 关闭防火墙
systemctl status firewalld # 查看防火墙开启状态,显示running则是正在运行
firewall-cmd --reload # 重启防火墙,永久打开端口需要reload一下# 添加开启端口,--permanent表示永久打开,不加是临时打开重启之后失效
firewall-cmd --permanent --zone=public --add-port=8888/tcp# 查看防火墙,添加的端口也可以看到
firewall-cmd --list-all
systemctl start nginx
docker search nginx
docker pull nginx
docker images
# -p 表示递归创建文件夹,不加-p只能创建一层文件夹,创建多层则会报错
mkdir -p /app/nginx/conf # /app 是隶属于根下的文件夹,个人喜好
启动前需要先创建Nginx外部挂载的配置文件( /home/nginx/conf/nginx.conf)
之所以要先创建 , 是因为Nginx本身容器只存在/etc/nginx 目录 , 本身就不创建 nginx.conf 文件
当服务器和容器都不存在 nginx.conf 文件时, 执行启动命令的时候 docker会将nginx.conf 作为目录创建 , 这并不是我们想要的结果 。
root@rion:~# docker run --name nginx-test -d nginx
1e3a6ea2eae268e0fcd6a3a5209f26fce8f173ecde42536d6de5ab5fba345fd6root@rion:~# docker ps -a | grep nginx
1e3a6ea2eae2 nginx "/docker-entrypoint.…" 11 seconds ago Up 10 seconds 80/tcp nginx-test
docker 相关命令介绍:
run 表示启动一个镜像
–name 表示给将要启动的镜像起个别名
-d 表示后台启动
# 生成容器
docker run --name nginx-test -d nginx
# 将容器nginx.conf文件复制到宿主机
docker cp nginx-test:/etc/nginx/nginx.conf /app/nginx/conf
# 将容器conf.d文件夹下内容复制到宿主机
docker cp nginx-test:/etc/nginx/conf.d /app/nginx/conf/conf.d
# 将容器中的html文件夹复制到宿主机
docker cp nginx-test:/usr/share/nginx/html /app/nginx
docker cp [SrcAddress] [DstFileAddress]
栗子:
docker cp nginx-test:/etc/nginx/nginx.conf /home
// 表示将nginx-test容器中/etc/nginx/nginx.conf 复制到宿主机(本机)的home目录下
docker cp /home/1.txt nginx-test:/root
// 表示将宿主机/home 下的1.txt文件拷贝到nginx-test 容器的/root/目录下
root@rion:/app/nginx# tree
.
├── conf
│ ├── conf.d
│ │ └── default.conf
│ └── nginx.conf
└── html├── 50x.html└── index.html
# 1. 停止nginx-test容器
docker stop nginx-test# 2. 删除前面创建的nginx-test容器,默认不能直接删除运行中的容器
docker rm nginx-test# 3. 创建nginx容器
docker run \
-p 80:80 \
--name nginx \
-v /app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \
-v /app/nginx/conf/conf.d:/etc/nginx/conf.d \
-v /app/nginx/log:/var/log/nginx \
-v /app/nginx/html:/usr/share/nginx/html \
-d nginx
-v 表示挂载文件,宿主机文件路径 : 容器文件路径
-p 表示将容器的 80(后面那个) 端口映射到主机的 80(前面那个) 端口
\ shell 命令换行
root@rion:/app/nginx# curl http://127.0.0.1
Welcome to nginx!
Welcome to nginx!
If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.
For online documentation and support please refer to
nginx.org.
Commercial support is available at
nginx.com.
Thank you for using nginx.
成功访问了nginx的默认页面,我们修改html中的index.html 文件内容
root@rion:/app/nginx# vim html/index.html
Welcome To RION Blog
再次访问,成功获取修改后的内容。
root@rion:/app/nginx# curl http://127.0.0.1
Welcome To RION Blog
nginx 下载地址:http://nginx.org/en/download.html
访问nginx下载地址,下载解压后双击nginx.exe程序,此时nginx服务就启动了。如果出错了请检测本机80端口是否被占用了。
nginx 命令
nginx -s reload # 向主进程发送信号,重新加载配置文件,热重启
nginx -s reopen # 重启 Nginx
nginx -s stop # 快速关闭
nginx -s quit # 等待工作进程处理完成后关闭
nginx -T # 查看当前 Nginx 最终的配置
nginx -t -c <配置路径> # 检查配置是否有问题,如果已经在配置目录,则不需要-c
systemctl 运行 nginx相关
systemctl start nginx # 启动 Nginx
systemctl stop nginx # 停止 Nginx
systemctl restart nginx # 重启 Nginx
systemctl reload nginx # 重新加载 Nginx,用于修改配置后
systemctl enable nginx # 设置开机启动 Nginx
systemctl disable nginx # 关闭开机启动 Nginx
systemctl status nginx # 查看 Nginx 运行状态
nginx主要的配置文件为/etc/nginx/nginx.conf
文件,内部结构大体如下:
# 主要包含三大块
main # 全局配置,对全局生效,即最外层的配置
├── events # 配置影响 Nginx 服务器或与用户的网络连接
├── http # 配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置
│ ├── upstream # 配置后端服务器具体地址,负载均衡配置不可或缺的部分
│ ├── server # 配置虚拟主机的相关参数,一个 http 块中可以有多个 server 块
│ ├── server
│ │ ├── location # server 块可以包含多个 location 块,location 指令用于匹配 uri
│ │ ├── location
│ │ └── ...
│ └── ...
└── ...
一个 Nginx 配置文件的结构就像 nginx.conf 显示的那样,配置文件的语法规则:
- 配置文件由指令与指令块构成;
- 每条指令以
;
分号结尾,指令与参数间以空格符号分隔;- 指令块以
{}
大括号将多条指令组织在一起;include
语句允许组合多个配置文件以提升可维护性;- 使用
#
符号添加注释,提高可读性;- 使用
$
符号使用变量;- 部分指令的参数支持正则表达式;
main 全局块
user nginx; # 以nignx用户运行
worker_processes auto; # Nginx 进程数,auto为自动调节error_log /var/log/nginx/error.log notice; # Nginx 的错误日志存放目录
pid /var/run/nginx.pid; # Nginx 服务启动时的 pid 存放位置
events 块
events {worker_connections 1024; # 每个进程允许最大并发数
}
http 块
# 配置最频繁的部分,代理、缓存、日志等大部分功能和第三方配置
http {include /etc/nginx/mime.types; # 文件扩展名与对应的映射表,即http mime类型default_type application/octet-stream; # 如果mime类型没匹配上,默认使用二进制流的方式传输。# 设置日志的记录格式 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; # Nginx 访问日志记录位置# sendfile on; # 开启高效传输模式,也就是数据0拷贝#tcp_nopush on; # 减少网络报文段的数量keepalive_timeout 65; # 保持连接的时间,也称为超时时间,单位秒include /etc/nginx/conf.d/*.conf; # 最后会加载conf.d 文件夹下的配置文件# /etc/nginx/conf.d/default.confserver {listen 80; # 监听端口server_name localhost; # 配置域名location / { # 匹配请求网址root /usr/share/nginx/html; # 网址根目录,且全局有且仅有一个rootindex index.html index.htm; # 默认首页文件deny 172.168.22.11; # 禁止访问的ip地址,可以为allallow 172.168.33.44; # 允许访问的ip地址,可以为all}#error_page 404 /404.html; # 404 状态码显示的网页# redirect server error pages to the static page /50x.html#error_page 500 502 503 504 /50x.html; # http状态码为50x的时候对应的页面 location = /50x.html {root /usr/share/nginx/html;}}
}
server 块中可以包含多个location,每个location 支持正则匹配
匹配规则
=
精确匹配路径,用于不含正则表达式的 uri 前,如果匹配成功,不再进行后续的查找;^~
用于不含正则表达式的 uri 前,表示如果该符号后面的字符是最佳匹配,采用该规则,不再进行后续的查找;~
表示用该符号后面的正则去匹配路径,区分大小写;~*
表示用该符号后面的正则去匹配路径,不区分大小写。跟 ~ 优先级都比较低,如有多个location的正则能匹配的话,则使用正则表达式最长的那个;如果 url 包含正则表达式,则必须要有 ~ 或 ~* 标志。
$host
:请求信息中的 Host,如果请求中没有 Host 行,则等于设置的服务器名,不包含端口
$request_method
:客户端请求类型,如 GET、POST
$remote_addr
:客户端的 IP 地址
$args
:请求中的参数
$arg_PARAMETER
:GET 请求中变量名 PARAMETER 参数的值,例如:$http_user_agent(Uaer-Agent 值), $http_referer...
$content_length
:请求头中的 Content-length 字段
$http_user_agent
:客户端agent信息
$http_cookie
:客户端cookie信息
$remote_addr
:客户端的IP地址
$remote_port
:客户端的端口
$http_user_agent
:客户端agent信息
$server_protocol
:请求使用的协议,如 HTTP/1.0、HTTP/1.1
$server_addr
:服务器地址
$server_name
:服务器名称
$server_port
:服务器的端口号
$scheme
:HTTP 方法(如http,https)
正常情况下,用户要访问网站直接访问即可,此时用户不想让对方服务器知道自己的信息(比如自己的IP等),就可以通过配置代理服务器,让我们的代理服务器来代替我们发送请求获取数据,并将数据返回给我们。这就叫做正向代理
正向代理隐藏了真实的客户端信息,对方服务器获取的都是代理服务器的信息
当用户访问网站时,使用反向代理服务器之后,用户访问的是我们的代理服务器,而代理服务器会根据nginx配置项来请求真正的服务器,nginx将获取的数据返回给用户。
反向代理隐藏了服务器信息,在处理跨域时比较常用。
当用户访问 www.rion.top:8080
网站时,nginx将用户的请求转发到一个flask程序中去。
这里简单的介绍一下用户输入网址的一个解析流程
用户输入网址后,本机先会检测
hosts
文件是否有IP和域名的对应关系。
Windows在C:\Windows\System32\drivers\etc\hosts
Linux 在/etc/hosts
2.配置hosts文件
因为互联网上没有www.rion.top 这个域名,所以我们需改hosts文件,使其指向本地的127.0.0.1,推荐使用vscode打开,其他软件打开可能会出现无法修改的情况
3.启动一个web服务
本次以flask程序为例,提供了2个api接口
from flask import Flaskapp = Flask(__name__) # Flask 实例对象@app.route("/api/home") # 路由地址
def home(): # 处理函数return "Home Page" # 响应数据@app.route("/api/login")
def login():return "Please Login"if __name__ == "__main__":app.run() # 运行flask程序,默认监听本机127.0.0.1:5000
4.配置nginx反向解析
server {listen 8080;server_name www.rion.top;location /api {proxy_pass http://127.0.0.1:5000;}# proxy_pass 将匹配到的请求转发到后面的url地址去
检测nginx配置是否错误,并重载配置文件
5.测试
当用户输入http://127.0.0.1:8080/api/home
时,nginx会将请求转发到我们的flask程序上。
6.总结
通过proxy_pass
来实现请求转发,默认location /
表示截获所有的请求。
1.需求
当用户访问http://127.0.0.1:8080/flask
时,访问我们的flask服务
当用户访问http://127.0.0.1:8080/django
时,访问我们的django服务
django 的这边定义了2个简单的api接口,
# 伪代码,细节代码就不展示了。flask 程序和上面的一样,返回值一点点不一样# urls.py
urlpatterns = [path('api/login', views.login),path('api/home', views.home)
]# views.py
def home(request):return HttpResponse("Django Home !")def login(request):return HttpResponse("Django Login")
2.nginx 配置
server {listen 8080;server_name www.rion.top;location /flask/ {proxy_pass http://127.0.0.1:5000/;}location /django/ {proxy_pass http://127.0.0.1:8000/;}}
3.测试
测试前记得重载nginx配置文件
4.总结
本质就是通过location 来区分不同的前缀,当nginx发现前缀时/flask
时,就会将请求转发到flask程序上,同理访问/django
时,就会将请求转发到django程序上
为什么这里要单独作为一个小节呢?在配置反向代理过程中这里其实是有坑的。因为 location 配置代理时,location 地址匹配结尾带/
和不带/
获取的url会不一样。而proxy_pass
url末尾带/
和 不带/
也会出现不同的情况。所以一共会出现四种不同的情况。
location /django { # 后续location这里的地址匹配我称呼为location 带不带 /proxy_pass http://127.0.0.1:8000; # 后续proxy_pass 后面url地址我称呼为url 带不带/ }
此时我们查看django后端接收到的请求路径,发现接收的是/django/api/login
,所以django程序返回了404 ,因为压根就没有这个api接口。
/djangoxxx/api/login
,看后端能不能接收到这个请求你会发现nginx将/djangoxxx
的请求也转发到了django程序
总结:
当location 不带/ ,url 不带/ 时,nginx会匹配以 /django
开头的字符,不管django末尾是什么字符都会成功匹配,并将匹配到的内容追加在url的末尾。就类似于模糊匹配,不过指定了开头。
如上述实际请求的是http://www.rion.top/djangoxxx/api/login
location /django/ { # 后续location这里的地址匹配我称呼为location 带不带 /proxy_pass http://127.0.0.1:8000; # 后续proxy_pass 后面url地址我称呼为url 带不带/ }
/django/api/login
时,nginx 将请求转发到了django程序,此时django程序获取的请求地址为/django/api/login
/djangoxxx/api/login
时,nginx 并没有将请求转发到django,说明location 匹配失败了,此时我们的django程序也没有收到任何请求。/django
时,nginx 也将请求转发到了django程序,所以nginx 是能够匹配/django
的,并且会自动给你补齐最末尾的/
总结
当location 带/ 结尾时,就类似于精确匹配,必须是/django
或/django/
结尾才会匹配
location /django {proxy_pass http://127.0.0.1:8000/;}
/django/api/login
时,nginx将请求转发到了django程序,但是django响应的还是404,当时你会发现请求的地址不再是以django开头,而是把/django
替换从了 /
,所以就变成了//api/login
,不明白的可以仔细看看请求的地址/django => / + /api/login ===> //api/login
/djangoxxx/api/login
,nginx匹配成功,但是django程序接收的地址也却是/xxx/api/login
,说明/djangoxxx
被nginx 替换成了 /xxx
/yy/
结尾时,用户请求/djangoxxx/api/login
,则最终请求的为/yy/xxx/api/login
location /django {proxy_pass http://127.0.0.1:8000/yy/;}
总结
若url 带 / 时,当location 匹配成功,会将匹配的内容替换为 /
,若url 以url 带/yy/
结尾,则location匹配的内容将会被替换成/yy/
在加上剩余部分。
location /django/ {proxy_pass http://127.0.0.1:8000/;
}
/django/api/login
发起请求,nginx会将/django/
替换成 /
,最终的请求为/api/login
,此时django程序api接口成功请求成功。/djangoxxx/api/login
,会匹配失败。总结
location 带 / ,就类似于精确匹配,url 带 /
则会见匹配到的内容替换为 /
整体简单概述一下:
url /
后的内容。实际项目开发中,location 往往是以/结尾的。url 也往往是以/ 结尾,这样能够有效保障精确的匹配api,并后端服务能够正确的处理。
例如
location /admin/api/ {proxy_pass http://127.0.0.1:8000/api/;
}# 将匹配/admin/api/ 替换成 /api/ 开头,
# 这样请求 http://www.rion.top/admin/api/ ,实际转发后为 http://127.0.0.1:8000/api/;
# 此时对用户来说他是无感知的,但是访问的后端服务以及切换到另一个了。
在早期,用户访问量不大的时候,用户每次请求,nginx将服务器响应的数据返回给用户,当用户访问越来越多时,服后端务器开始处理不过来,此时我们可以配置多台服务器,当A服务器负载较高时,nginx将请求转发到B服务器来响应用户,这样就能保障用户访问时的快速响应。
例如,晚高峰乘坐地铁的时候,入站口经常会有地铁工作人员大喇叭“请走 B 口,B 口人少车空…”,这个工作人员的作用就是负载均衡。
一般来说,都需要将动态资源和静态资源分开,由于 Nginx 的高并发和静态资源缓存等特性,经常将静态资源部署在 Nginx 上。如果请求的是静态资源,直接到静态资源目录获取资源,如果是动态资源的请求,则利用反向代理的原理,把请求转发给对应后台应用去处理,从而实现动静分离。
使用前后端分离后,可以很大程度提升静态资源的访问速度,即使动态服务不可用,静态资源的访问也不会受到影响。
upstream flask {server 127.0.0.1:5000 weight=2; # weight : 权重,表示3次请求有2次请求会发送到 8000 端口的服务器server 127.0.0.1:5001 weight=1;
}server {listen 8080;server_name www.rion.top;location / {proxy_pass http://flask;}
}
当服务器性能不一致时,权重就需要设置了。
参数介绍:
down:表示当前的server暂时不参与负载
weight:默认为1.weight越大,负载的权重就越大。
backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。
注意:
前面我们提到需要注意location 和 url 是否带 / 的问题,在这里也是同样的道理。
[http://www.rion.top:8080/flask/api/login](http://www.rion.top:8080/flask/api/login)
到flask程序时,nginx会在url后面拼接上/flask
upstream flask {server 127.0.0.1:5000 weight=2;server 127.0.0.1:5001 weight=1;}server {listen 8080;server_name www.rion.top;location /flask {proxy_pass http://flask;}}
[http://www.rion.top:8080/flask/api/login](http://www.rion.top:8080/flask/api/login)
时 upstream flask {server 127.0.0.1:5000 weight=2;server 127.0.0.1:5001 weight=1;}server {listen 8080;server_name www.rion.top;location /flask/ {proxy_pass http://flask/; # 注意,url的 / 是加在这里,并不是加在upstram 中}}
其余两种情况,朋友们可以自己去测试了。
nginx 的基本使用就介绍到这里了,有任何错误欢迎大家指出~
参考链接: https://blog.csdn.net/BThinker/article/details/123507820
参考链接: https://www.nginx.org.cn/article/detail/545