Nginx入门指南

168 阅读10分钟

前言

最近工作中用到了Nginx,虽然作为一名前端,平时也不怎么配置服务器相关的东西,但是如果我们要是自己搭建个博客,自己捣鼓捣鼓,那Nginx必然是绕不开的话题,至于Nginx的优势就不过多介绍了,网上有很多关于这些的介绍了,这里我只是对常用的场景和使用做一些总结~

准备

环境准备

  • Centos 7.6

开始

基本介绍

首先,我们可以看一下Nginx的yum版本

yum list | grep nginx

image.png

我们可以看到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,就不用理会了

image.png

安全组的话,如果你是阿里云,那么需要查看一下你的端口是否被限制,基本上80端口都是默认开启的

image.png

下面启动nginx

// 设置开机启动nginx
systemctl enable nginx
// 启动nginx
systemctl start nginx

然后浏览器输入你的ip地址,就可以访问到Nginx的页面了

image.png

常用命令

下面总结一下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配置项

image.png

  • 如果填入空或@,在不输入www的情况下,匹配wwwserver image.png

反向代理

首先我们要知道,什么是正向代理

我们想打韩服英雄联盟,但是直接访问是访问不了或访问很慢,我们要找一个能访问韩服服务器的服务器,即代理服务器

召唤师即用户将请求代理到加速器提供商,进而提升游戏体验,而接受请求的服务器只知道发来请求的是代理服务器,而不知道具体玩家是谁

image.png

那什么是反向代理

如图,玩家不知道LOL服务器具体有哪个服务器真正的处理了我们的请求,而是被LOL服务器反向代理了

image.png

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项目,部署到服务器,前端打包好的代码就是静态资源,那么前端访问后端的接口就是动态资源

image.png

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,那么以谁为准呢?这里就需要讨论它们的优先级

= > ^~ > ~~* > 前缀字符串

  1. =

精确匹配全路径,命中后不再进行后续匹配

  1. ^~

精确匹配开头,命中后不再进行后续匹配

  1. ~~*的正则

正则会按照先后顺序匹配,选择最先匹配的,因此最精细的应该越靠前

  1. 无符号的前缀字符

通用匹配,匹配后还会向下进行探索寻找匹配,但是会取路径最长的匹配

root & alias

这里再补充一个知识点,rootalias的区别

可以看到下面是rootalias的配置

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/,rootpathlocation拼接的目录

使用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: 添加允许访问的白名单,可设置一个或者多个,会检查HeaderReferer的值是否为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;
}

单页应用

如果我们部署过前端项目,如VueReact的时候都会遇到一个问题,就是路由跳转后,刷新就会白屏,其原因就是访问的路径的确没有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; # 开启静态资源
  }
}

基本上大多常用的知识点也总结的差不多了,如有错误欢迎下方留言探讨~