Nginx

本文最后更新于:8 个月前

与Apache相比,Nginx是更轻量高效的Web服务器,更适用来提供静态资源服务

Nginx

一、简介

Nginx 是开源、高性能、高可靠的 Web 和反向代理服务器,而且支持热部署,几乎可以做到 7 * 24 小时不间断运行,即使运行几个月也不需要重新启动,还能在不间断服务的情况下对软件版本进行热更新。性能是 Nginx 最重要的考量,其占用内存少、并发能力强、能支持高达 5w 个并发连接数,最重要的是,Nginx 是免费的并可以商业化,配置使用也比较简单。

Nginx 的最重要的几个使用场景:

  • 静态资源服务,通过本地文件系统提供服务;

  • 反向代理服务,延伸出包括缓存、负载均衡等;

  • 虚拟主机,一台服务器虚拟出多个网站

  • 安全管理,搭建API接口网关,对每个接口服务进行拦截

  • 限流,限制用户请求速度,防止服务器受不了

Nginx 和 Node.js 的很多理念类似,HTTP 服务器、事件驱动、异步非阻塞等,且 Nginx 的大部分功能使用 Node.js 也可以实现,但 Nginx 和 Node.js 并不冲突,都有自己擅长的领域。

  • Nginx 擅长于底层服务器端资源的处理(静态资源处理转发、反向代理,负载均衡等)
  • Node.js 更擅长上层具体业务逻辑的处理

两者可以完美组合,共同助力前端开发。

二、安装Nginx

1、安装命令

1
2
3
yum install nginx
nginx -v #安装好后就可以查看到版本信息
nginx version: nginx/1.20.1 #这是输出结果

2、相关文件

1
rpm -ql nginx | grep -v /usr/share
image-20221123113700699
  • 主配置文件:/etc/nginx/nginx.conf
  • 默认web目录:/etc/share/nginx/html/

3、运行Nginx

1
2
3
systemctl enable nginx	#设置开机启动
systemctl start nginx #启动nginx服务
systemctl status nginx

之后我们输入正确的URL,就可以看到默认页面了

image-20221123174814603

4、查看Nginx状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
systemctl status nginx	#查看unit状态

ps -ef | grep nginx #查看是否有nginx进程
root 853 1 0 17:01 ? 00:00:00 nginx: master process /usr/sbin/nginx
nginx 857 853 0 17:01 ? 00:00:00 nginx: worker process
nginx 858 853 0 17:01 ? 00:00:00 nginx: worker process
root 2142 1163 0 17:20 pts/0 00:00:00 grep --color=auto nginx

netstat -lnt #查看端口开放状态
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:27017 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp6 0 0 :::80 :::* LISTEN

systemctl status firewalld #查看防火墙状态
firewall-cmd --state #同上
#其实nginx不用到系统防火墙,网络安全已经在云服务器的控制台的安全规则上做了,所以CentOS并没有使用firewalld

5、前置准备

想要正常访问nginx,除了以上步骤之后,还需要在云服务器的「安全规则」上打开对应的端口,http-80,https-443。

三、Nginx配置

  • 主配置文件:/etc/nginx/nginx.conf
  • 默认web目录:/etc/share/nginx/html/

1、主配置文件 nginx.conf

配置文件结构解析:

1
2
3
4
5
6
7
8
9
10
11
main        # 全局配置,对全局生效
├── events # 配置影响 Nginx 服务器或与用户的网络连接
├── http # 配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置
│ ├── upstream # 配置后端服务器具体地址,负载均衡配置不可或缺的部分
│ ├── server # 配置虚拟主机的相关参数,一个 http 块中可以有多个 server 块
│ ├── server
│ │ ├── location # server 块可以包含多个 location 块,location 指令用于匹配 uri
│ │ ├── location
│ │ └── ...
│ └── ...
└── ...

配置文件的语法:

  1. 配置文件由指令与指令块构成;

  2. 每条指令以 ; 分号结尾,指令与参数间以空格符号分隔;

  3. 指令块以 {} 大括号将多条指令组织在一起;

  4. include 语句允许组合多个配置文件以提升可维护性;

  5. 使用 # 符号添加注释,提高可读性;

  6. 使用 $ 符号使用变量;

  7. 部分指令的参数支持正则表达式;

2、全局变量

Nginx 有一些常用的全局变量,你可以在配置的任何位置使用它们,如下表:

全局变量名 功能
$host 请求信息中的 Host,如果请求中没有 Host 行,则等于设置的服务器名,不包含端口
$request_method 客户端请求类型,如 GET、POST
$remote_addr 客户端的 IP 地址
$args 请求中的参数
$content_length 请求头中的 Content-length 字段
$http_cookie 客户端cookie信息
$scheme HTTP 方法(如http,https)
$server_protocol 请求使用的协议,如 HTTP/1.0、HTTP/1.1

还有更多的内置预定义变量,可以直接搜索关键字「nginx内置预定义变量」可以看到一堆博客写这个,这些变量都可以在配置文件中直接使用。

3、location属性

location指令的功能是用来匹配不同的url请求,进而对请求做不同的处理和响应,其中难点在于location的匹配机制

语法格式:location [ | = | ~ | ~* | ^~ ] URI {...}

匹配参数:

  • =,精确匹配,内容必须完全一致才匹配成功

    1
    2
    3
    location = /abc/ {...}
    http://abc.com/abc #匹配成功
    http://abc.com/abc/index #匹配失败
  • 空格,直接是一个空格,匹配那些以指定pattern开头的URL(普通字符串而不是正则表达式)

    1
    2
    3
    location /laf {...}
    http://abc.com/laf #匹配成功
    http://abc.com/laf/api #匹配成功
  • ^~,前缀匹配,只匹配普通字符串。

    1
    2
    3
    4
    location ^~ /index/ {...}
    #以 /index/ 开头的请求,都会匹配上
    http://abc.com/index/index.page #匹配成功
    http://abc.com/error/error.page #匹配失败
  • ~,正则匹配,区分大小写

    1
    2
    3
    location ~ /Abc/ {...}
    http://abc.com/Abc/ #匹配成功
    http://abc.com/abc/ #匹配失败
  • ~*,正则匹配,不区分大小写

    1
    2
    3
    location ~* /Abc/ {...}
    http://abc.com/Abc/ #匹配成功
    http://abc.com/abc/ #匹配成功

优先级:

(1)精确匹配,即=。如果匹配上,则匹配过程到此结束
(2)字符串前缀匹配,即:空格和^~,找到匹配前缀最长的那个,如果匹配上,则匹配过程到此结束
(3)正则表达式匹配,取第一个匹配成功的,这里不看匹配长度,而是看在配置文件中的前后顺序。

注意:

「空格」和「^~」都表示字符串前缀匹配,这也意味着两者可能发生冲突,如下

1
2
3
4
5
6
7
8
# 两者的匹配规则是一样的,这时候是通不过Nginx的语法检查的
location /images/test.png {
return 200 '1';
}

location ^~ /images/test.png {
return 200 '2';
}

4、root指令 & alias指令

1
2
3
4
5
6
7
8
9
#root指令
语 法: root path;
默认值: root html;
配置段(可以放到哪些段里配置): http, server, location, if in location

#alias指令
语 法: alias path;
默认值: —
配置段: location

两者的用法区别:

  • root配置如下:

    1
    2
    3
    4
    location /blog/ {
    root /usr/local/nginx/html;
    index index.html index.htm;
    }

    请求 http://127.0.0.1:80/blog/index.html 这个地址时,那么在服务器里面对应的真正的资源是 /usr/local/nginx/html/blog/index.html文件。

    即:真实的路径是:root指定的地址 + location的值

  • alias配置如下:

    1
    2
    3
    4
    location /blog/ {
    alias /usr/local/nginx/html/;
    index index.html index.htm;
    }

    同样请求http://127.0.0.1:80/blog/index.html时,在服务器查找的资源路径是:**/usr/local/nginx/html/index.html**文件

    即:真实的路径是:alias指定的路径,与location无关。alias指定的路径就是location的别名。

使用alias注意:

  • alias后面必需要用/结束,不然会被认为是文件,从而找不到对应的目录。(而root对/的添加可有可无)
  • alias只能用在location中

参考链接:

Nginx系列:root与alias指令用法的区别 - 腾讯云开发者社区-腾讯云 (tencent.com)

四、Nginx常用命令

1
2
3
4
5
6
7
8
9
10
11
12
nginx -v #显示版本信息并退出
nginx -V #显示版本和配置选项信息,然后退出
nginx -t #检测配置文件是否有语法错误,然后退出
nginx -q #在检测配置文件期间屏蔽非错误信息
nginx -s reload #重新加载Nginx配置文件,然后以优雅的方式重启Nginx
nginx -c filename #设置配置文件(默认是:/etc/nginx/nginx.conf)
nginx -g directives #设置配置文件外的全局指令
nginx -p prefix #设置前缀路径(默认是:/usr/share/nginx/)
nginx -?,-h #打开帮助信息  

killall nginx #杀死所有nginx进程  
nginx -s quit #优雅地停止Nginx服务(即处理完所有请求后再停止服务)

五、Nginx配置HTTPS

1. 配置SSL证书

第一步,把/etc/nginx/nginx.conf文件中关于TLS的注释去除

image-20221123201318989
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
# Settings for a TLS enabled server.

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name _;
root /usr/share/nginx/html;

ssl_certificate "/etc/pki/nginx/server.crt"; #证书文件地址
ssl_certificate_key "/etc/pki/nginx/private/server.key"; #私钥文件地址
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

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

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

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

第二步,从阿里云服务器控制台下载SSL证书

image-20221123202034799

第三步,在云服务器对应位置创建目录,放置对应文件

image-20221123204917866

第四步,修改nginx.conf中对应的文件名

第五步,校验配置文件,确认无误后热重载Nginx

1
2
nginx -t
nginx -s reload #重新加载Nginx配置文件,然后以优雅的方式重启Nginx

现在就可以通过https协议访问网页了

image-20221123205542513

2. 配置多个SSL证书

只需要按照上面的格式,并列写多个server, 针对不同的server_name, 配置对应的ssl证书。

3. http自动跳转https

在http的配置文件中的server中添加一行代码即可,如下:

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name scnulaf.top;

# 将所有HTTP请求通过rewrite指令重定向到HTTPS
rewrite ^(.)* https://$host$1;

location / {
root /var/laf_frontend/dist/;
index index.html index.htm;
}
}

六、Nginx配置反向代理

在http模块的server内部添加location规则,进行代理

1
2
3
4
5
6
7
8
server {
...
#配置反向代理,实现的效果是:当URL的前面部分为"域名/api"时,跳转或者说代理到"http://127.0.0.1:3000/api"
#location + proxy_pass实现的效果是,用 "proxy_pass+location" 替代 "域名+location"
location /api/ {
proxy_pass http://127.0.0.1:3000;
}
}

这和Apache有很大区别。

Apache上的效果是:访问域名/express,会直接跳转到http://127.0.0.1:3000上,并且不会在http://127.0.0.1:3000后面添加/express。实际上,/express相当于是http://127.0.0.1:3000的别名。

image-20221124094323085

七、Nginx配置二级路径

使用alias指令

alias指令的作用是:用alias指定的路径替代location指定的路径

1
2
3
4
5
6
7
8
server {
...
#使用alias指令配置二级目录,实现的效果是:访问"域名/test/"时,跳转到"域名/timegogo/test_cache/"目录
location /test {
alias /timegogo/test_cache/; #最后面必须添加/,否则会被视为文件,而不是目录
index index.html index.htm;
}
}

八、Nginx开启Gzip压缩

开启Gzip压缩有什么好处?A:减小通过网络传输的数据量,提高传输速度,但是会增加服务器和客户端压缩、解压缩的性能消耗。所以需要权衡使用。

如何查看网页是否开启压缩:检测站点:www.timegogo.top/laf网页GZIP压缩检测结果 (chinaz.com)

/etc/nginx/conf.d目录下新建一个gzip.conf文件

1
2
3
4
5
6
7
8
9
10
11
12
13
# 开启gzip压缩,该文件会在nginx.conf的http模块中被include进去

gzip on; #默认off,是否开启gzip
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

#上面两项已经可以把gzip跑起来了,以下是一些进阶选项
gzip_static on;
gzip_proxied any;
gzip_vary on;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_min_length 1k;
gzip_http_version 1.1;
  • gzip_types:要采用 gzip 压缩的 MIME 文件类型,其中 text/html 被系统强制启用;

  • gzip_static:默认 off,该模块启用后,Nginx 首先检查是否存在请求静态文件的 gz 结尾的文件,如果有则直接返回该 .gz 文件内容。可以结合Webpack使用,在打包时就打包出.gz文件

    image-20200427144824829
  • gzip_proxied:默认 off,nginx做为反向代理时启用,用于设置启用或禁用从代理服务器上收到相应内容 gzip 压缩;

  • gzip_vary:用于在响应消息头中添加 Vary:Accept-Encoding,使代理服务器根据请求头中的 Accept-Encoding 识别是否启用 gzip 压缩;

  • gzip_comp_level:gzip 压缩比,压缩级别是 1-9,1 压缩级别最低,9 最高,级别越高压缩率越大,压缩时间越长,建议 4-6;

  • gzip_buffers:获取多少内存用于缓存压缩结果,16 8k 表示以 8k*16 为单位获得;

  • gzip_min_length:允许压缩的页面最小字节数,页面字节数从header头中的 Content-Length 中进行获取。默认值是 0,不管页面多大都压缩。建议设置成大于 1k 的字节数,小于 1k 可能会越压越大

  • gzip_http_version:默认 1.1,启用 gzip 所需的 HTTP 最低版本;

效果对比:

下面是没有开启gzip之前的请求头和响应头

image-20221126203925320

下面是开启gzip之后的响应头

image-20221126204447846

并没有在响应头中看到期望出现的Content-Encoding字段,不过通过「站长工具-网页GZIP压缩检测」看到对应的URL已经开启了Gzip

image-20221126204619919

九、Nginx跨域

Nginx跨域大体分为两种方式:一种是在Nginx中配置http响应头,另一种是将Nginx作为正向代理服务器

1. CORS跨域

在Nginx中配置http响应头这种方式,本质上属于配置CORS跨域。它和在服务端代码中配置CORS没有本质区别,只是所处的位置不同,下面给出示例:(下面是nginx.conf配置文件,以配置http连接的响应头为例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
listen 80;
server_name localhost;

location / {
proxy_pass http://localhost:8188;

# 允许所有源跨域访问,比较简单粗暴,不够安全,也可以指定允许的源头(不过只能指定一个)
add_header Access-Control-Allow-Origin * Always;
# 允许跨域的请求方法
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

}
}

2. 代理跨域

在前端网页(应用)所在的服务器下,部署一个Nginx服务器,并使用Nginx的代理,让网页向Nginx发送后端请求,然后再由Nginx向实际的服务端发送请求。因为前端网页和Nginx服务器同源,所以不存在跨域问题。

问题合集

  1. 阿里云服务器上(CentOS7),Nginx服务正常启动,但是无法访问网址。系统没有开启防火墙,云服务器访问规则里也打开了80端口。

    A:URL错误导致的,Edge浏览器默认给我添加了https前缀,但是实际需要使用http协议。从http转换到https应该需要在nginx中进行配置


Nginx
http://timegogo.top/2022/11/23/前端工程化/web服务器:Nginx/
作者
丘智聪
发布于
2022年11月23日
更新于
2023年7月16日
许可协议