vlambda博客
学习文章列表

前端视角:Nginx从入门到实践一


文章首发:https://fujia.site


在最开始,我们先明确一个认知,在大前端的环境下,Nginx不仅是运维工程师和后端工程师需要掌握的基础技能,也成为了前端工程的核心技能之一。 当然,根据「最小化」原则和自身情况,从前端视角来看,掌握的深度需要根据自身情况来调整。


前言

最近在个人站点(https://fujia.site)上,添加了基于egg.js + GitHub的第三方登录功能,千辛万苦的终于在本地调通了,结果部署到服务器上,cookies竟然失效了,简单梳理了下,就发现本地和服务器上区别就在于多了一层Nginx层,首要考虑问题是Nginx的配置问题,且在egg.js的官网上对这一块也是有说明的,见 https://www.eggjs.org/zh-CN/tutorials/passport  :

如应用部署在 Nginx/HAProxy 之后,需设置插件 proxy 选项为 true, 并检查以下配置:代理附加 HTTP 头字段:x-forwarded-proto 与 x-forwarded-host 配置中 config.proxy 应设置为 true

于是开始调试Nginx的配置,由于没有系统学习Nginx基础语法, 因语法问题导致多次部署失败,就正好趁此机会将相关内容梳理下。


Nginx介绍

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

  2. 使用场景:

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

  • 反向代理,进一步延伸如:缓存,负载均衡等;

  • API服务。

  1. Nginx和node.js的很多理念类似,如:http服务器、事件驱动以及异步非阻塞等,但各自有自己擅长的领域,Nginx擅长底层服务器端资源的代理,node.js更擅长上层具体业务逻辑的处理。


  2. 正向代理和反向代理

反向代理(Reverse Proxy)对应的是正向代理(Forward Proxy),他们的区别:

正向代理: 一般的访问流程是客户端直接向目标服务器发送请求并获取内容,使用正向代理后,客户端改为向代理服务器发送请求,并指定目标服务器(原始服务器),然后由代理服务器和原始服务器通信,转交请求并获得的内容,再返回给客户端。正向代理隐藏了真实的客户端,为客户端收发请求,使真实客户端对服务器不可见;

举个具体的例子 ,你的浏览器无法直接访问谷哥,这时候可以通过一个代理服务器来帮助你访问谷哥,那么这个服务器就叫正向代理。

反向代理: 与一般访问流程相比,使用反向代理后,直接收到请求的服务器是代理服务器,然后将请求转发给内部网络上真正进行处理的服务器,得到的结果返回给客户端。反向代理隐藏了真实的服务器,为服务器收发请求,使真实服务器对客户端不可见。一般在处理跨域请求的时候比较常用。现在基本上所有的大型网站都设置了反向代理。

举个具体的例子 ,去饭店吃饭,可以点川菜、粤菜、江浙菜,饭店也分别有三个菜系的厨师 ‍ ,但是你作为顾客不用管哪个厨师给你做的菜,只用点菜即可,小二将你菜单中的菜分配给不同的厨师来具体处理,那么这个小二就是反向代理服务器。

简单地说,一般给客户端做代理的都是正向代理,给服务器做代理的就是反向代理。


安装

Mac M1 下安装

  1. 安装和校验

arch -arm64 brew install nginx
brew info nginx
nginx: stable 1.21.6, HEADHTTP(S) server and reverse proxy, and IMAP/POP3 proxy serverhttps://nginx.org//opt/homebrew/Cellar/nginx/1.21.6_1 (26 files, 2.2MB) * Poured from bottle on 2022-03-26 at 09:24:26From: https://mirrors.ustc.edu.cn/homebrew-core.git/Formula/nginx.rbLicense: BSD-2-Clause==> DependenciesRequired: [email protected] ✔, pcre2 ✔==> Options--HEAD Install HEAD version==> CaveatsDocroot is: /opt/homebrew/var/www
The default port has been set in /opt/homebrew/etc/nginx/nginx.conf to 8080 so thatnginx can run without sudo.
nginx will load all files in /opt/homebrew/etc/nginx/servers/.
To restart nginx after an upgrade: brew services restart nginxOr, if you don't want/need a background service you can just run: /opt/homebrew/opt/nginx/bin/nginx -g daemon off;

NOTE: 可以从上面的信息找到很多基础的配置信息。

TIPS:一般来说,安装好nginx之后,我们主要关注两个文件夹

  • /etc/nginx/conf.d/ 文件夹,是进行子配置的配置项存放处,/etc/nginx/nginx.conf 主配置文件会默认把这个文件夹中所有子配置项都引入。

windows下,是对应的安装目录下的conf目录。Mac M1下,是/opt/homebrew/etc/nginx/servers目录。

  • /usr/share/nginx/html/ 文件夹,通常静态文件都放在这个文件夹

windows下, 对应的目录是在安装目录下的html目录。Mac M1下,是/opt/homebrew/var/www。

  1. 其它命令

  • sudo nginx 启动服务

  • sudo nginx -s stop 停止服务(直接走)

  • sudo nginx -s reload 重新加载

  • sudo nginx -s reopen 重新启动

  • sudo nginx -s quit 退出(处理完事情走)

  • open /opt/homebrew/etc/nginx/ 查看nginx安装目录

  1. max下使用brew安装的nginx的命令如下:

tips: 使用brew services -h查看brew services的使用帮助。

# 查看服务运行列表brew services list
# nginx nonebrew services start nginx
# 现在可以在浏览器中访问:http://127.0.0.1:8080/


使用

配置语法校验

  1. 使用下面命令:

nginx -t -c /usr/local/nginx/conf/nginx.conf
  • -c: 指定需要检验的配置文件

  • -t: 测试配置文件是否正确,在运行时需要重新加载配置的时候,此命令非常重要,用来检测所修改的配置文件是否有语法错误。

语法

这里只讨论一些基础常用的配置语法。

配置语法

  1. 配置文件由指令与指令块组成。

  2. 每条指令以分号(;)结尾,指令与参数间以空格符号分割,值参数可以是一个或多个附加参数,取决于解析该条指令的模块。

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

  4. 使用#添加注释。

  5. 使用$符号使用变量。

  6. 部分指令参数支持正则表达式。

一个示例,执行命令cat /opt/homebrew/etc/nginx/nginx.conf:

# worker进程运行的用户和组,如果没有提供则使用nginx的master进程的用户和用户组#user nobody;
# nginx进程数,一般和cpu核数一致worker_processes 1;
# 错误日志,级别有debug, info, notice, warn, error和crit(debug记录了全部日志,crit仅报告关键错误)#error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;
#pid logs/nginx.pid;events { # 每个进程允许的最大并发数 worker_connections 1024;}
http { # 引入其它配置,mime.types文件存储的是文件扩展名与类型映射表 include mime.types; default_type application/octet-stream;
# 日志格式 #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 logs/access.log main;
# 开启sendfile配置提高文件的传输速率 sendfile on; #tcp_nopush on;
#keepalive_timeout 0; # 指定KeepAlive的超时时间,即TCP可以保持的时长。 keepalive_timeout 65;
# 开启gzip压缩 #gzip on;
# 服务器配置 server { # 监听套接字使用的端口号 listen 8080; # 指定一个或多个主机名 server_name localhost;
#charset koi8-r;
# 开启访问日志 #access_log logs/host.access.log main;
# 访问地址 location / { root   html;    index  index.html index.htm;}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html {    root   html; }



#location ~ /\.ht { # deny all; #}
# 另一个虚拟主机使用基于IP,名称和端口的混合配置 # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias;
# location / { # root html; # index index.html index.htm; # }    #} # HTTPS server - https服务配置 # #server { # listen 443 ssl;    #    server_name  localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on;
# location / { # root html; # index index.html index.htm; # } #} # 加载子配置 include servers/*;}

tips: 可以在阿里云、腾讯云等云服务器商申请免费的SSL证书,一般使用期是一年,个人开发者足够使用。

说明:

  • nginx收到http请求时,根据请求header中Host值与所有server区段比较,第一个与主机名匹配的server块将被命中,如果没有server区段与客户端请求的主机名匹配,nginx会选择第一个server区段,匹配监听参数(如listen *:80), 另外具有default选项的listen会被优先选择。

  • sendfile,指定nginx是否调用sendfile函数来输出文件,减少内核空间和用户空间的上下文切换。对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。

备注:


nginx指令

文档:http://nginx.org/en/docs/ 

  1. Nginx的指令非常多,不建议死记硬背,使用时查询官方文档即可,实际上,可以通过模块名称大致了解到其功能。

  2. 常用的模块:

  • Alphabetical index of variables - nginx提供的所有变量。

  • Core functionality - 核心功能,主要针对main/event context的设置。

  1. 使用nginx -V查看nginx的配置参数,看除了核心模块之外还添加了哪些模块。

  2. 以ngx_http_gzip_module举个例子:

http://nginx.org/en/docs/http/ngx_http_gzip_module.html 

该模块表示是否启用响应的gzip压缩。

示例配置:

gzip on;gzip_min_length 1000;gzip_proxied expired no-cache no-store private auth;gzip_types text/plain application/xml;

$gzip_ratio变量可以记录实现的压缩率。

指令语法:

Syntax: gzip on | off;Default: gzip off;Context: http, server, location, if in location


  • Syntax - 表示使用语法;

  • Default - 默认情况下未使用;

  • Context - 表示该指令可以出现的位置,如上面表示可以出现在location、http和server指令块中。

如果块指令可以在括号内包含其它指令,则称其为context。

  1. 一个指令出现在多个指令块中,哪个会生效呢?

Nginx中指令继承规则是向上覆盖。 当子配置存在时,直接覆盖父配置,子配置不存在才使用父配置块或默认配置。

  1. 指令都有作用域。

  2. 配置(指令)块能相互嵌套。在某些情况下不同配置块能够相互嵌套,如在http区段,可以声明一个或多个server区段,server区段又可以插入一个或多个location区段。

  3. 字符串的值,如果指令值中包含空格、分号或者是大括号等特殊字符,需要使用单引号或双引号将其括起。


基本模块

Nginx是由一系列模块组成的,大致可以分为:

  • 核心模块

  • http核心模块

  • 其它模块

核心模块在编译时不能被禁用。 核心模块包含:main模块,events模块和includes包含指令。

  1. main模块位于配置文件顶层,提供如:进程管理和安全的能力,使用说明见上面。

  2. events模块,事件模块提供的指令可以用来配置网络机制。

accept_mutex:on; # 默认值on,启用或禁用使用一个接受互斥锁来打开套接字监听use epoll; # 指定nginx所使用的网络事件模型,可选值有/dev/poll,epoll,kqueue等,通常不需要显式指定它,默认情况下nginx将使用最有效方法worker_connections 1024; # 定义一个worker进程能够同时连接的数量


  1. include指令,用来包含子配置配置文件,在配置文件的任何地方均可插入该指令。注意,如果没有指定绝对路径,那么文件路径将和配置文件的目录相关。


参考资料

  1. 官网 - https://nginx.org/ 。

  2. 中文网 - https://www.nginx.cn/doc/ 。

  3. Nginx基础语法 - https://zhuanlan.zhihu.com/p/340295336 。

 4. 你不知道的 Nginx - https://zhuanlan.zhihu.com/p/139948268 。


大家加油 :)