0%

Nginx基本使用

Nginx简介

高性能的web服务器

Nginx安装

https://pcj600.github.io/2024/1109163902.html

Nginx版本

  • Nginx
  • Nginx plus 商业版
  • OpenResty
  • Tengine

Nginx应用场景

反向代理、虚拟主机、域名解析、负载均衡、防盗链、url重定向、https

Nginx特点/为什么用Nginx

  • 高并发连接
  • 低内存消耗
  • 支持热部署
  • BSD许可协议,允许用户免费使用Nginx,且允许用户在自己项目中直接使用或修改Nginx源码

Nginx常用命令

1
2
3
4
5
6
7
nginx -h        # 查看Nginx用法
nginx -s reload # 向主进程发HUP信号,重新加载配置文件,热重启
nginx -s reopen # 向主进程发USR1信号,重新打开日志文件
nginx -s quit # 向主进程发QUIT信号, 处理完所有正在进行请求后再停止服务 (优雅关闭)
nginx -s stop # 向主进程发TERM信号,立即停止所有服务
nginx -T # 查看当前配置
nginx -t # 测试配置是否有问题

Nginx主配置文件

主配置文件/etc/nginx/nginx.conf, 基础配置说明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
user nginx;                               # 以Nginx用户启动
worker_processes auto; # work process进程的个数
error_log /var/log/nginx/error.log; # 错误日志路径
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
worker_connections 1024; # 单个进程可接收连接数
}

http {
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;

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;

include /etc/nginx/mime.types; # 服务器发送MIME type给客户端,让客户端知道请求的文件类型
default_type application/octet-stream;

include /etc/nginx/conf.d/*.conf;

server {
listen 80; # LISTEN端口
listen [::]:80;
server_name _; # 主机名
root /usr/share/nginx/html; # 在哪里找页面

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

error_page 404 /404.html;
location = /404.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}

虚拟主机配置

  • 虚拟主机是指,在一台服务器主机虚拟出多台主机,每台虚拟主机都可以具有独立的域名,具有完整的服务器功能
  • 同一台主机上的虚拟主机之间是完全独立的。从网站访问者来看,每一台虚拟主机和一台独立的主机完全一样。
  • 利用虚拟主机,不必为每个要运行的网站提供一台单独的Nginx服务器或单独运行一组Nginx进程。虚拟主机提供了在同一台服务器、同一组Nginx进程上运行多个网站的功能。

实例:在一台机器上配置多台虚拟主机

例如,我需要实现如下效果:

  • 访问80端口返回/www/www页面, 显示”this is www web site”
  • 访问88端口返回/www/vod页面,显示”this is vod web site”

操作步骤:
配置多个站点

1
2
3
mkdir -p /www/vod /www/www
cat "welcome to vod site" > /www/vod/index.html
cat "welcome to www site" > /www/www/index.html

修改nginx.conf,添加两个server配置,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 虚拟主机1
server {
listen 80;
server_name _;
root /www/www;

include /etc/nginx/default.d/*.conf;

error_page 404 /404.html;
location = /404.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# 虚拟主机2
server {
listen 88; # 第二个虚拟主机使用88端口
server_name _;
root /www/vod; # 访问/www/vod下的页面

include /etc/nginx/default.d/*.conf;

error_page 404 /404.html;
location = /404.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

使用nginx -s reload重新加载配置,测试80,88两个端口可以访问

1
2
3
4
# curl localhost:88
this is vod web site
# curl localhost:80
this is www web site

注: 如遇到Nginx报错: bind() to 0.0.0.0:8088 failed (13: Permission denied), 可参考link

servername的多种匹配方式

同一个servername中匹配多个域名

例如,我需要通过不同的域名访问相同的页面, 实现如下效果:

  • vod.petertest.com -> 访问/vww/vod 页面 -> 输出 this is vod site
  • vod1.petertest.com -> 也访问/www/vod 页面 -> 输出 this is vod site

操作步骤:
nginx.conf中, 只需一个server配置项,就可以配多个servername, 不需要复制server配置块。修改方法如下:

1
2
3
4
5
6
7
  server {
listen 80;
server_name vod.petertest.com vod1.petertest.com; # 在一个server中配置多个servername
root /www/vod;
include /etc/nginx/default.d/*.conf;
# ...
}

测试结果:

1
2
3
4
# curl vod.petertest.com
this is vod web site
# curl vod1.petertest.com
this is vod web site

通配符匹配多个servername

修改nginx.conf

1
2
3
4
5
6
7
  server {
listen 80;
server_name *.petertest.com;
root /www/vod;
include /etc/nginx/default.d/*.conf;
# ...
}

通配符结束匹配

例如,我需要实现如下匹配:

  • vod.petertest.com 匹配到/www/www
  • 其他vod.petertest.XXX 匹配到/www/vod

操作步骤:
修改Nginx.conf, 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  server {
listen 80;
server_name vod.petertest.com;
root /www/www;
include /etc/nginx/default.d/*.conf;
# ...
}
server {
listen 80;
server_name vod.petertest.*; # 通配符结束匹配
root /www/vod;
include /etc/nginx/default.d/*.conf;
# ...
}

测试结果

1
2
3
4
# curl vod.petertest.com
this is www web site
# curl vod.petertest.io
this is vod web site

正则匹配

例如,我需要实现如下匹配:

  • vod.petertest.com 匹配到/www/www
  • 其他vod.petertest.XXX 匹配到/www/vod

操作步骤:
修改Nginx.conf, 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  server {
listen 80;
server_name vod.petertest.com;
root /www/www;
include /etc/nginx/default.d/*.conf;
# ...
}
server {
listen 80;
server_name ~^[0-9]+\.petertest\.com$; # 通配符结束匹配
root /www/vod;
include /etc/nginx/default.d/*.conf;
# ...
}

测试结果:

1
2
3
4
# curl vod.petertest.com
this is www web site
# curl 123.petertest.com
this is vod web site

基于域名的几种互联网需求解析

补充: hosts泛解析 https://cloud.tencent.com/developer/article/1534150 (dnsmaxq) 本机DNS指向dnsmasq,dnsmasq做泛解析,把域名都解析到同一个IP

多用户二级域名需求(微博)

*.weibo.com -> Nginx -> 真正的业务服务器(拿到域名,解析出二级域名)

短网址

*.com/asdasjda12312 -> Nginx -> 真正的网址

反向代理

正向代理:国内无法访问谷歌, 必须用梯子,这个梯子就是正向代理
反向代理:指Nginx代理了”目标服务器”,去和客户端交互; 对于客户端来说, 目标服务器被隐藏。

负载均衡

Nginx -> 服务器集群(任意一台提供的服务都是相同的)
实战操作:
先准备三台RHEL9 VM机器,每台机器都安装Nginx

1
2
3
192.168.52.200 Nginx1 
192.168.52.201 Nginx2
192.168.52.202 Nginx3

场景1: 配置最简单的proxypass (客户请求Nginx1, Nginx1把所有请求转发到Nginx2)

Nginx1上配置proxypass, 指向Nginx2, 把请求Nginx1的流量转发到Nginx2, 返回”Welcome to Nginx2”
先修改Nginx1的nginx.conf

1
2
3
4
5
6
7
8
9
  server {
listen 80;
server_name vod.petertest.com;
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://192.168.52.201; # 配置proxy_pass
}
# ...
}

再修改Nginx2的nginx.conf

1
2
3
4
5
6
7
server {
listen 80;
server_name _;
root /var/www/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
}

Nginx2添加一个主页

1
2
mkdir -p /var/www/html
cat "Welcome to Nginx2" > /var/www/html/index.html

测试

1
2
curl 192.168.52.200:80
Welcome to nginx2

场景2: 配置多个proxypass

请求Nginx1后, Nginx1通过RR算法把请求转发给Nginx2, Nginx3

实战操作:
修改Nginx1的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 添加upstream,和server同级
upstream my_servers{
server 192.168.52.201:80;
server 192.168.52.202:80;
}
server {
listen 80;
server_name _;
location / {
proxy_pass http://my_servers;
}
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
}

测试

1
2
3
4
# curl 192.168.52.200:80
Welcome to nginx2
# curl 192.168.52.200:80
Welcome to Nginx3

负载均衡策略

设置权重策略(weight)

修改Nginx1的配置文件,如下:

1
2
3
4
upstream my_servers {
server 192.168.52.201:80 weight=4;
server 192.168.52.202:80 weight=1;
}

测试

1
2
3
4
5
6
7
8
9
10
# curl 192.168.52.200:80
Welcome to nginx2
# curl 192.168.52.200:80
Welcome to nginx2
# curl 192.168.52.200:80
Welcome to Nginx3
# curl 192.168.52.200:80
Welcome to nginx2
# curl 192.168.52.200:80
Welcome to nginx2

让某台服务器下线(down)

修改Nginx1的配置文件,如下:

1
2
3
4
upstream my_servers {
server 192.168.52.201:80 weight=4 down;
server 192.168.52.202:80 weight=1;
}

测试: (Nginx2下线, 所有请求只转发到了Nginx3)

1
2
3
4
# curl 192.168.52.200:80
Welcome to Nginx3
# curl 192.168.52.200:80
Welcome to Nginx3

备用服务器(backup)

把一台服务器设为backup,是指正常情况Nginx不会把请求转到这台服务器,但如果其他服务器都出现故障,Nginx会把请求转到这台备用服务器

修改Nginx1的配置文件,如下:

1
2
3
4
upstream my_servers {
server 192.168.52.201:80;
server 192.168.52.202:80 backup;
}

测试, 设置Nginx3为backup后, Nginx1把请求只转发到了Nginx2;此时我手动stop Nginx2, Nginx1把请求都转发到了Nginx3

1
2
3
4
5
6
7
8
# curl 192.168.52.200:80
Welcome to nginx2
# curl 192.168.52.200:80
Welcome to nginx2

# 此时手动stop Nginx2
# curl 192.168.52.200:80
Welcome to Nginx3

其他负载均衡策略(不常用)

策略 描述
ip_hash 根据客户端IP地址转发到同一台服务器,可以保持会话
least_conn 最少连接访问
url_hash 根据用户访问的url定向转发请求,需要三房插件
fair 根据后端服务器响应时间选择,需要三方插件
注:
  • 单纯使用RR算法的问题: 不能维持会话
  • 一般不用ip_hash, 因为客户的IP地址经常会改变
  • least_conn也不常用, 对于不同带宽配置的服务器, 用least_conn策略不合适;
  • fair根据后端服务器响应时间选择, 会造成网络倾斜,并不常用
  • url_hash也不常用,不能做到维持会话,比如注册和登录的url是不同的,可能会转发到不同的服务器

动静分离

TODO

URLReWrite

一个最简单的URLReWrite例子

场景: 客户 -> 互联网 -> Nginx(网关服务器,反向代理/负载均衡器) -> 业务服务器
准备两台VM机器:

1
2
192.168.52.200 VM1 Nginx(80端口)
192.168.52.201 VM2 业务服务器(5000端口)

实现如下效果:

步骤:
1、先在VM2上搭建一个简单的目标服务器(这里用Flask搭建)
安装Flask

1
2
yum install -y python3-pip
pip3 install Flask

添加web.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python3

from flask import Flask, request

app = Flask(__name__)
@app.route('/')
def index():
return 'hello'

@app.route('/admin', methods=['GET'])
def show_admin():
page = request.args.get('page', default=0, type=int)
return f'You are on page {page}'

if __name__ == '__main__':
app.run()

启动server

1
flask --app web run --host=0.0.0.0 # 默认端口5000
  1. 再修改VM1上的Nginx配置文件,启动Nginx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
      upstream my_servers {
    server 192.168.52.201:5000;

    }
    server {
    listen 80;
    server_name _;
    include /etc/nginx/default.d/*.conf;

    location / {
    rewrite ^/([0-9]+).html$ /admin?page=$1 break; # rewriteUrl
    proxy_pass http://my_servers;
    }
    # ignore error_page ...
    }
  2. 测试URLReWrite OK

    1
    2
    3
    4
    5
    6
    7
    8
    # curl 192.168.52.200/2.html
    You are on page 2
    # curl 192.168.52.200/admin?page=2
    You are on page 2
    # curl 192.168.52.201:5000/admin?page=2
    You are on page 2
    # curl 192.168.52.201:5000/2.html
    404 Not Found

防盗链

判断referer字段,如果不是合法的referer,返回403
修改Nginx.conf

1
2
3
4
5
6
7
8
9
10
11
server {
listen 80;
server_name vod.petertest.com;
include /etc/nginx/default.d/*.conf;
location / {
valid_referers none 192.168.52.200; # referer不对, 返回403
if ($invalid_referer) {
return 403;
}
root /www/vod;
}

使用curl测试防盗链:

1
2
3
4
5
6
7
8
9
# 没有指定referer, 或referer为本机IP, 返回200 OK
[root@localhost ~]# curl -I 192.168.52.200/kuangsan.png
HTTP/1.1 200 OK
[root@localhost ~]# curl --referer "http://192.168.52.200" -I 192.168.52.200/kuangsan.png
HTTP/1.1 200 OK

# referer不合法, 返回403
[root@localhost ~]# curl --referer "http://4399.com" -I 192.168.52.200/kuangsan.png
HTTP/1.1 403 Forbidden

高可用场景及解决方案

问题: Nginx本身不可用怎么办

1
2
3
客户 -> 互联网 -> Nginx1(192.168.52.200)(主) -> Web Servers 
|
Nginx2(192.168.52.201)(备)

直接交换两台Nginx的IP很麻烦,会有IP冲突问题; 可以使用一个虚拟IP作为入口

1
客户 -> 互联网 -> Virtual IP -> 主Nginx IP -> 业务服务器

keepalived+Nginx实现高可用 https://www.cnblogs.com/youzhibing/p/7327342.html

HTTPS

TODO: 自签一个证书,做一个HTTPS服务, 测试一下看看

Nginx进阶(高并发网站技术架构实战)

Ingress-Controller
搜一下面试题