前言
最近工作中用到了Nginx,虽然作为一名前端,平时也不怎么配置服务器相关的东西,但是如果我们要是自己搭建个博客,自己捣鼓捣鼓,那Nginx必然是绕不开的话题,至于Nginx的优势就不过多介绍了,网上有很多关于这些的介绍了,这里我只是对常用的场景和使用做一些总结~
准备
环境准备
- Centos 7.6
开始
基本介绍
首先,我们可以看一下Nginx的yum版本
yum list | grep nginx
我们可以看到nginx的版本是1.20.1,下面我们通过以下命令安装它
// 安装nginx
yum install nginx
// 查看nginx安装目录
rpm -ql nginx
// 查看版本
nginx -v
当我们安装完nginx以后,我们需要重点关注三个目录
/etc/nginx/nginx.conf主配置配置项/etc/nginx/conf.d子配置配置项/usr/share/nginx/html存放静态文件
首先说说什么是主配置配置项和子配置配置项的关系,主配置配置项是配置Nginx所有基础类型配置的配置文件,我们可以看看它长啥样
这里我移除了部分注释,为了方便我们查看,我们可以重点看一下include /usr/share/nginx/modules/*.conf;,这段的意思是将所有此目录下含有.conf的配置项都引入至主配置中
其实这也很好理解,如果我们有多个项目,我们可以设置多个子配置,而不需要修改主配置文件
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
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;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
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 {
}
}
}
那么静态资源的存放目录自然很好理解,比如前端项目打包好后就可以存放在这个目录,比如我们就是一个静态网站,那么我们通过子配置配置项来访问了,下面是一个最简单的例子
这里注意子配置项一定要有.conf后缀
// /etc/nginx/conf.d/a.xxx.com.conf
server {
listen 80;
server_name a.xxx.com;
location / {
root /usr/share/nginx/html/react;
index index.html;
}
}
说了这么多,也该实战一下了
尝试一下
在安装好Nginx后,要关注两个问题
- 防火墙
- 安全组
然后查看一下防火墙,这里列举一下防火墙常用命令
// 打开防火墙
systemctl start firewalld
// 关闭防火墙
systemctl stop firewalld
// 查看防火墙状态
systemctl status firewalld
// 永久打开某个端口
firewall-cmd --permanent --zone=public --add-port=3000/tcp
// 查看防火墙开放端口
firewall-cmd --list-all
如果是dead,就不用理会了
安全组的话,如果你是阿里云,那么需要查看一下你的端口是否被限制,基本上80端口都是默认开启的
下面启动nginx
// 设置开机启动nginx
systemctl enable nginx
// 启动nginx
systemctl start nginx
然后浏览器输入你的ip地址,就可以访问到Nginx的页面了
常用命令
下面总结一下nginx,都有哪些最常用的命令
- nginx命令
// 重启 Nginx
nginx -s reopen
// 修改配置文件,重新加载配置,无需重启 Nginx
nginx -s reload
// 关闭 Nginx
nginx -s stop
// 查看配置是否正确
nginx -t
// 异步关闭,待其他进程处理结束后关闭
nginx -s quit
- systemctl命令
// 设置开机启动 Nginx
systemctl enable nginx
// 启动 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
- 其他
// 查看端口占用
netstat -tlnp
// 强制停止 Nginx 进程
killall nginx
配置详解
主配置项
主配置项是Nginx的全局配置
/etc/ngixn/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx; # 运行用户,默认即是nginx,可以不进行设置
worker_processes auto; # Nginx进程,一般设置为和CPU核数一样
error_log /var/log/nginx/error.log; # 错误日志存放目录
pid /run/nginx.pid; # 进程pid存放位置
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
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; # nginx 访问日志存放位置
sendfile on; # 开启高效传输模式
tcp_nopush on; # 减少网络报文段的数量
tcp_nodelay on;
keepalive_timeout 65; # 保持连接的时间,也叫超时时间
types_hash_max_size 4096;
include /etc/nginx/mime.types; # 文件扩展名与类型映射表
default_type application/octet-stream; # 默认文件类型
include /etc/nginx/conf.d/*.conf; # 子配置项
server {
listen 80; # 监听端口
listen [::]:80; # IPV6监听端口
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; # 404 错误页
location = /404.html {
}
error_page 500 502 503 504 /50x.html; # 50x 错误页
location = /50x.html {
}
}
}
子配置项
子配置项不是Nginx默认创建的,而是我们自己要创建的
在我们未修改主配置文件的情况下,创建子配置项有以下注意点:
- 创建在
/etc/nginx/conf.d目录下 - 创建的文件要
.conf作为文件后缀 - 通常可以根据域名作为区分,如:
www.baidu.com.conf,api.baidu.com.conf - 创建的子配置项文件就是创建一个
server
比如
server {
listen 80; # 监听端口
server_name www.baidu.com; # 配置域名
location / {
root /usr/share/nginx/html; # 服务默认访问目录
index index.html; # 默认访问文件
allow 192.168.31.1 # 允许访问的ip地址, all为所有
deny all # 禁止访问的ip地址
# 访问权限规则为先触发,先生效.如果deny all在allow前则禁止访问所有ip
}
error_page 500 502 /50x.html # 可配置多个
error_page 404 /404.html # 可单独配置
}
注意: 所有的修改配置项都必须使用reload重启才会生效
nginx -s reload
虚拟主机
虚拟主机是指将一台物理服务器划分为多个虚拟的服务器,因此可以将一台物理服务器跑多个服务,在Nginx我们可以理解为配置中的
server
那么,如何划分虚拟主机?
- 基于端口配置
通过以下配置可以得到,访问相同域名www.baidu.com 80端口 -> /usr/share/nginx/html/blog1,
而通过 3000端口 -> /usr/share/nginx/html/blog2
server {
listen 80;
server_name www.baidu.com;
location / {
root /usr/share/nginx/html/blog1;
index index.html;
}
}
server {
listen 3000;
server_name www.baidu.com;
location / {
root /usr/share/nginx/html/blog2;
index index.html;
}
}
- 基于二级域名配置 同理,也可以相同端口不同域名访问不同资源
server {
listen 80;
server_name blog1.baidu.com;
location / {
root /usr/share/nginx/html/blog1;
index index.html;
}
}
server {
listen 80;
server_name blog2.baidu.com;
location / {
root /usr/share/nginx/html/blog2;
index index.html;
}
}
server_name精确匹配优先级最高server_name可以匹配一个或多个域名,也可以匹配IP地址,通配符还有正则表达式.一般来说通过设置端口和二级域名就可以基本覆盖大多数场景,server_name设置很复杂的情况很少- 通过设置通配
server_name *.xxx.com可将任何非精确匹配的二级域名与之匹配,前提是配置了泛解析* - 通过对设置域名的泛解析
*,可以使得任何二级域名在都没有匹配的情况下,匹配第一个server配置项
- 如果填入空或
@,在不输入www的情况下,匹配www的server
反向代理
首先我们要知道,什么是正向代理
我们想打韩服英雄联盟,但是直接访问是访问不了或访问很慢,我们要找一个能访问韩服服务器的服务器,即代理服务器
召唤师即用户将请求代理到加速器提供商,进而提升游戏体验,而接受请求的服务器只知道发来请求的是代理服务器,而不知道具体玩家是谁
那什么是反向代理
如图,玩家不知道LOL服务器具体有哪个服务器真正的处理了我们的请求,而是被LOL服务器反向代理了
Nginx就可以作为我们的反向代理服务器,可以看一个例子
假如我有个xxx的域名,实现将www.baidu.com代理到学习网站http://www.bilibili.com
server {
listen 80;
server_name www.xxx.com;
location / {
proxy_pass http://www.bilibili.com; // 可以填URL或者IP
}
}
负载均衡
负载均衡可以分摊我们服务器集群的压力,做到雨露均沾,通过upstream可以配置要做负载均衡的服务器列表,并与proxy_pass相配合
server {
listen 80;
server_name www.xxx.com;
upstream servers { # 别名
server 192.168.31.1:80;
server 192.168.31.2:80;
}
location / {
proxy_pass http://servers; # 与别名对应
}
}
有的时候,我们的服务器集群性能各有不同,因此可以让性能更高的承担更多访问量,因此可以添加权重配置
server {
listen 80;
server_name www.xxx.com;
upstream servers { # 别名
server 192.168.31.1:80 weight=7;
server 192.168.31.2:80 weight=7;
}
location / {
proxy_pass http://servers; # 与别名对应
}
}
这里可以看到通过weight的比例设置来配置权重
动静分离
动静分离是指将动态资源和静态资源相分开,缓解动态资源服务器的压力,一个比较贴近我们实际的例子就是前端打包好的Vue或者React项目,部署到服务器,前端打包好的代码就是静态资源,那么前端访问后端的接口就是动态资源
server {
listen 80;
server_name www.xxx.com;
location / {
root /usr/share/nginx/html/www; # 前端页面
index index.html;
}
location ^~ /api {
proxy_pass http://www.xxx.com:8080; # 后端服务
}
}
location
location 的配置规则略微复杂,语法为:
location [ = | ~ | ~* | ^~ ] uri { ... }
=表示精确匹配
location = /hello {
}
/hello ✅
/hello/ ❎
/helloworld ❎
~表示区分大小写的正则匹配
location ~ ^/hello$ {
}
/hello ✅
/Hello/ ❎
/helloworld ❎
~*表示不区分大小写的正则匹配
location ~ ^/hello$ {
}
/hello ✅
/Hello/ ✅
/helloworld ❎
^~表示URI为某个字符串作为开头
location ^~ /api/ {
}
/api/list ✅
/表示通配,匹配任何URI
location / {
}
/123 ✅
/hello/ ✅
- 不写语法的字符串匹配
location /hello {
}
/hello ✅
/hello/ ✅
/helloworld/ ✅
那么,如果一个server中存在多个location,那么以谁为准呢?这里就需要讨论它们的优先级
= > ^~ > ~或~* > 前缀字符串
=
精确匹配全路径,命中后不再进行后续匹配
^~
精确匹配开头,命中后不再进行后续匹配
~或~*的正则
正则会按照先后顺序匹配,选择最先匹配的,因此最精细的应该越靠前
- 无符号的前缀字符
通用匹配,匹配后还会向下进行探索寻找匹配,但是会取路径最长的匹配
root & alias
这里再补充一个知识点,root与alias的区别
可以看到下面是root和alias的配置
location /img/ {
root /usr/share/nginx/html/www/;
index index.html;
}
location /img/ {
alias /usr/share/nginx/html/www/;
index index.html;
}
使用root -> /usr/share/nginx/html/www/img/,root是path和location拼接的目录
使用alias -> /usr/share/nginx/html/www/,alias是直接通过path指定一个目录
这里有一点需要格外注意,如果使用alias时注意最后要有/,不可以写成/usr/share/nginx/html/www
伪静态
有时候我们访问京东时,可以看到有很多的商品,可以看到它的URL地址是item.jd.com/10002666792… ,但是服务器上会有这么多html文件吗?当然是不可能的.这里京东为了更好的SEO而使用了伪静态,我们就仿照京东实现一下伪静态
server {
listen 80;
server_name localhost;
location / {
rewrite ^/([0-9]+).html$ /index.jsp?sku=$1 break; # break表示不会继续向下匹配
proxy_pass http://localhost:8080;
}
}
防盗链
防盗链可以限制其他服务器的访问,指定访问规则,通常做法是只允许本机IP访问
valid_referers 是防盗链设置
- none: 可以通过浏览器直接访问(直接访问不包含
Referer) - blocked: referer 可以不包含http/https,同样也可以访问
- server_names: 添加允许访问的白名单,可设置一个或者多个,会检查
Header中Referer的值是否为server_names的其中一个
location ~* \.(svg|gif|jpg|jpeg|png|bmp|swf)$ {
valid_referers none blocked server_names ~\.google\. ~\.baidu\.;
if ($invalid_referer){
return 403;
}
root /web;
index index.html;
}
通过上述配置,还可以配置在403错误码后给页面返回一个错误图片
location ~* \.(svg|gif|jpg|jpeg|png|bmp|swf)$ {
valid_referers none blocked server_names *.xxx.com ~\.baidu\. ~\.google\.;;
if ($invalid_referer){
rewrite ^/ /fail.png break;
}
root /web;
index index.html;
}
HTTPS
HTTPS是一种安全协议,它通过一些证书机构下发给我们的证书来保证访问的安全性,配置如下:
server {
listen 443 ssl http2 default_server;
server_name www.xxx.com;
ssl_certificate /etc/nginx/https/www.xxx.com.pem; # 公钥
ssl_certificate_key /etc/nginx/https/www.xxx.com.key; # 私钥
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
root /usr/share/nginx/html/web;
index index.html index.htm;
}
}
如果原先的80端口不再使用,我们可以进行如下配置
server {
listen 80;
server_name www.xxx.com;
return 301 https://$server_name$request_uri;
}
单页应用
如果我们部署过前端项目,如Vue或React的时候都会遇到一个问题,就是路由跳转后,刷新就会白屏,其原因就是访问的路径的确没有index.html,例如下面的配置中location /,默认访问的就是index.html
server {
listen 80;
server_name a.xxx.com;
location / {
root /usr/share/nginx/html/react;
index index.html;
}
}
因此当你访问一个/home,而你的项目目录中根本不存在/home,就会返回404了.解决方案也很简单,如果目录不存在,我们就把index.html返回
location / {
root /usr/share/nginx/html/;
try_files $uri $uri/ index.html;
index index.html;
}
可以看到,我们添加了try_files这个配置项,顾名思义,它的作用就是从左到右帮你去查找你所需的文件,这里面它的工作流程如下
查找$uri(原路径) -> 没找到 -> 查找$uri/index.html -> 没找到 -> 返回index.html
gzip压缩
开启gzip可以有效较少网络传输的文件大小,配置(http或server都可)如下:
gzip on; # 开启gzip
gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css; # 压缩的类型
gzip_min_length 1k; # 低于1k不压缩
gzip_comp_level 5; # 压缩级别,一般设置5
多端适配
我们可以发现,如果我们通过手机访问www.taobao.com时,会自动跳转到https://main.m.taobao.com/,这就是Nginx通过判断请求头user-agent来实现的,我们就来模仿一下这个配置是如何实现的
server {
listen 80;
server_name www.taobao.com;
location / {
root /usr/share/nginx/html/www;
if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
return 302 http://main.m.taobao.com;
}
index index.html index.htm;
}
}
还可以通过同一个域名访问不同的资源
server {
listen 80;
server_name www.taobao.com;
location / {
root /usr/share/nginx/html/www;
if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
root /usr/share/nginx/html/www/mobile;
}
index index.html index.htm;
}
}
静态服务
server {
listen 80;
server_name downloads.xxx.com;
charset utf-8; # 防止文件名有中文乱码
location / {
root /downloads;
autoindex on; # 开启静态资源
}
}
基本上大多常用的知识点也总结的差不多了,如有错误欢迎下方留言探讨~