后端开发必备的 Nginx 知识

1,372 阅读12分钟

请看更详细的文章

Nginx (engine x) 是一款轻量级的 Web 服务器(软件)、反向代理服务器(软件)及电子邮件(IMAP/POP3)代理服务器(软件)。

在我们公司,Nginx 最常见的场景是用来配置域名,但“配置域名”这个说法其实过于笼统,且不严谨。为什么呢?

我们延伸一下,先来说说“域名”。

**域名(Domain Name)**说白了,就是一个字符串,比如 baidu.com。通过域名,我们能在浏览器里访问一个网站/站点,通过 IP,比如 220.181.38.148,也能访问,但 99% 的人都会选择通过域名访问网站,毕竟域名好记多了。

从技术角度来说,“网站”是一个部署在某台服务器上的软件,要访问到它,浏览器肯定得知道这台服务器在哪里。那么,为什么通过域名,浏览器就能知道网站在哪台服务器上呢?这就要提到 **DNS(Domain Name Server)**了。

顾名思义,DNS(Domain Name Server) 的意思是“域名服务器”。DNS 干的活,就是告诉浏览器,一个域名对应的 IP 地址是多少

DNS

那 DNS 又是如何知道域名和 IP 的对应关系的呢?这就涉及到**“域名解析”**了。

域名解析,对咱们公司而言,只需关注一种类型,就是**“A 记录”类型。A 是 Address 的意思,配置一条 A 记录,就是配置一条域名和 IP 地址**的对应关系记录。很多人说“配置域名”,其实他的目的可能只是要做一下“域名解析”。

**域名解析,可以在域名注册商的管理后台进行操作。**国内主要的域名注册商有万网(阿里的)、新网、DNSPod(腾讯的)等,这些域名注册商除了提供域名购买服务,也会提供域名解析服务,一般在管理后台都能看到“域名解析”的功能。

汇总一下域名的有关流程——

  1. 访问域名注册商网站,选择并购买一个域名(一般是购买一级域名,比如 aaa.com)

  2. 购买完成后,登录域名注册商管理后台,找到“域名解析”功能,添加一条域名解析 A 记录,一般是解析二级域名或对应子域名,比如将 1.aaa.com 解析到某个公网 IP 上(对于我们公司的项目而言,这个 IP 所对应的服务器上,通常都会安装 Nginx,或者这个 IP 对应的是医院防火墙服务器,它能通过端口映射,让公网用户访问到防火墙后方的 Nginx 服务器)

说了这么多域名相关的东西,跟 Nginx 又有什么关系呢?

简单来说,用户通过浏览器访问域名,只是完成了从客户端到服务器的访问。在这之后,Nginx 就登场了,它会捕获到这些来自于公网的请求,并根据相关配置规则,将请求转交给后端某台服务器上。后端服务器处理完请求后,将响应发送给 Nginx 服务器,Nginx 服务器收到响应后,将其发回给用户客户端,这样就完成了一次完整的请求过程,这其实就是“反向代理”的通俗化解释。

反向代理

Nginx 有很多优点,比如高性能(高并发支持非常给力)、高扩展性(模块化设计、庞大的第三方模块)、跨平台(二进制发布)、高可靠性(宕机概率极低)等等,所以熟悉 Nginx 的相关功能是很有必要的,尤其对于后端开发来说更是如此。

一、安装 Nginx

开发人员经常找运维分配一个域名,然后将这个域名的请求反向代理到某台服务器的某个端口上。运维人员的做法是,到 DNSPod 上(A 记录)解析一个新域名到公司的 Nginx 服务器(腾讯云 Nginx 服务器或公司内网 Nginx 服务器)的 IP 上,也就是 115.159.1.60(腾讯云)/183.129.254.168(公司内网),然后再到 Nginx 服务器上,在某个已有配置文件中新增一个 server 配置块或直接新增一个配置文件,最后重载 Nginx。

上面这个做法,是利用了公司已经有的 Nginx 来进行请求反向代理。对于某些非 SaaS 化(独立部署)的项目,可以这么做,但独立部署 Nginx 有独立部署的优势和必要性。

独立部署 Nginx,意味着——

  • 不占用公司 Nginx 服务器的带宽资源

  • 独立部署的项目,独占本地 Nginx 服务器的带宽资源

  • 一定程度上,加快了服务访问的速度

因此,独立部署 Nginx 是个很好的选择。**但由于服务的访问都要通过 Nginx 进行反向代理,所以 Nginx 所在服务器的公网带宽得保证足够高。**对于公司项目来说,一般建议 Nginx 服务器的带宽为 20M 起。

下面讲一下如何在服务器上安装 Nginx(直接联系运维人员安装也是个好办法)。

1、Linux 上安装 Nginx

鉴于公司独立部署的项目,一般都要求客户提供 CentOS 7.x 版本(可以在服务器上输入 cat /etc/redhat-release 查看版本)的服务器,所以就单独说下 CentOS 7.x 系统如何安装 Nginx。

先决条件

首先,得确保有一个拥有 CentOS 服务器 root 权限的用户(不一定是 root 用户,普通用户也可以设置 root 权限,有 root 权限的用户,sudo 命令才能生效)。

其次,得确保 CentOS 服务器能够访问公网(主要是为了方便通过 yum 安装软件),否则就只能上传二进制源码包进行手动编译,但这种方式大概率会导致编译失败,因为你基本上无法顺利地解决复杂的软件依赖问题。

第一步——添加 Nginx yum 源

$ sudo rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

安装完 yum 源后,检查一下是否添加成功

$ sudo yum repolist

如果看到有 nginx repo,则表示 Nginx 仓库添加成功。

第二步——安装 Nginx

$ sudo yum -y install nginx

第三步——启动 Nginx

$ sudo systemctl start nginx

这里注意一下服务器的防火墙状态,如果是开启着(active)的,需要设置允许对 HTTP(默认 80 端口)、HTTPS(默认 443 端口)服务进行访问。

查看防火墙状态(CentOS7 使用的防火墙 firewalld 默认是关闭 http 服务的)——

$ sudo systemctl status firewalld

如果看到 running,则表示防火墙是开启的,就需要输入如下命令设置允许访问 HTTP、HTTPS 服务

$ sudo firewall-cmd --permanent --zone=public --add-service=http $ sudo firewall-cmd --permanent --zone=public --add-service=https$ sudo firewall-cmd --reload

输入下面的命令,查看对 HTTP、HTTPS 服务的访问是否真的开启了

$ sudo firewall-cmd --list-service

如果能看到结果列表里有 http、https 就 OK 了。

再说几个 Nginx 相关的命令。

设置 Nginx 开机启动——

$ sudo systemctl enable nginx

重载 Nginx 配置——

$ sudo systemctl reload nginx

重启 Nginx 服务——

$ sudo systemctl restart nginx

需要指出的是 CentOS 7 的 SELinux,使用反向代理需要打开网络访问权限

2、Windows 上安装 Nginx

请注意,Nginx 官方将 Nginx Windows 版本看成是 beta 版本,因此其高性能、高扩展性无法和 Linux 版本相比。

第一步——下载最新的主线版本

最新的主线版本号是 1.17.4,官方下载地址: nginx.org/download/ng…

第二步——解压 Nginx

我们将主线版本压缩包放到某个目录下进行解压,比如放到 C 盘根目录下,然后解压。

第三步——启动 Nginx

解压后进入 nginx-1.17.4 目录,直接双击运行文件夹里的 nginx.exe 即可启动 Nginx。

可以打开一个 cmd 窗口,运行 tasklist 命令查看 Nginx 是否正常启动,比如——

C:\nginx-1.17.4>tasklist /fi "imagename eq nginx.exe"​Image Name           PID Session Name     Session#    Mem Usage=============== ======== ============== ========== ============nginx.exe            652 Console                 0      2 780 Knginx.exe           1332 Console                 0      3 112 K

上面一个是 master 主进程,一个是 worker 工作进程。

如果没有显示 nginx.exe 进程,可以进入 nginx-1.17.4 目录下的 logs 目录,查看 error.log 文件,排查错误信息。

注意,Nginx 运行目录,比如 C:\nginx-1.17.4,是 Nginx 配置文件(Nginx 的配置文件是 C:\nginx-1.17.4\conf\nginx.conf)里配置的相对路径的目录前缀。

但是通过双击 nginx.exe 启动的 Nginx 只是一个控制台应用,并不是一个系统服务,这就意味着一旦关闭这个 cmd 窗口,Nginx 进程也就停止了。当然,服务器如果意外关机了,重启后 Nginx 自然也没有在运行。

所以我们得想办法将其包装成一个系统服务,这样就可以设置开机自启动,并且也能方便地重启服务或停止服务。

我们通过开源的 Windows Service Wrapper(简称为 winsw)软件或者 nssm,将 Nginx 包装成 Windows 系统服务。多说一句,这个 winsw 也可以将 Java 的 jar 包(比如一个 Spring Boot 的 jar 包)包装成 Windows 系统服务。

具体步骤:

  1. 下载官方的 winsw 软件,目前最新版本 v2.3.0。winsw 需要 .NET 支持(也就是说服务器上要有 .NET 库),对于是 Windows Server 2008 R2 系统的服务器来说,下载 WinSW.NET4.exe 即可。

  2. 将下载的 WinSW.NET4.exe 放到 Nginx 的运行目录下,比如 C:\nginx-1.17.4。为了方便表示,可以将 WinSW.NET4.exe 重命名成 nginx-service.exe。然后在这个目录下,再创建一个同名的 XML 文件,即 nginx-service.xml。也就是说,nginx-service.exe 的完整路径是 C:\nginx-1.17.4\nginx-service.exe,nginx-service.xml 的完整路径是 C:\nginx-1.17.4\nginx-service.xml。

  3. 在 C:\nginx-1.17.4 下创建一个 cmd 文件,文件名为 nginx-stop.cmd,顾名思义它是用来杀掉 nginx 进程的,内容如下——

    @echo off​cd /C %~dp0​if not exist logs\nginx.pid GOTO skipnginx.exe -s quitdel logs\nginx.pid​:skip​taskkill /f /IM nginx.exe
    
  4. 编辑 nginx-service.xml 文件内容,如下所示——

    <?xml version="1.0" encoding="utf-8"?><service>   <id>Nginx Service</id>    <name>Nginx Service</name>    <description>High Performance Nginx Service</description>    <logpath>C:\nginx-1.17.4\logs</logpath>    <log mode="roll-by-size">     <sizeThreshold>10240</sizeThreshold>      <keepFiles>8</keepFiles>   </log>    <executable>C:\nginx-1.17.4\nginx.exe</executable>  <stopexecutable>C:\nginx-1.17.4\nginx-stop.cmd</stopexecutable> </service>
    
  5. 然后以管理员身份打开一个 cmd 窗口,并切换到 C:\nginx-1.17.4 目录。

  6. 运行 nginx-service.exe install 命令,即可完成 Nginx 服务的注册。

  7. 按 win+R 键,输入 services.msc 打开 Windows 系统服务列表,找到其中的 Nginx Service,右键点击启动,并点击属性菜单将启动类型设置为“自动”,完成服务的自启动设置。

二、配置 Nginx

首先,我们要知道 CentOS 服务器上安装的 Nginx,它的全局配置文件路径是 /etc/nginx/nginx.conf。但这个全局配置文件,一般都是用来进行 Nginx 进程运行用户(user)、Nginx 工作进程数(worker_processes)等的配置,对于开发人员来说,基本不用去修改它。

开发人员,一般只需要关注 /etc/nginx/conf.d/default.conf 以及 /etc/nginx/conf.d/自定义的.conf 等文件。我们在 conf.d 目录下自行创建的 *.conf 文件,一旦 Nginx 服务重新加载(nginx -s reload),马上就会加载生效。

对于 Windows 版本的 Nginx,我们一般不自定义 *.conf 配置文件,而是直接修改全局配置文件 default.conf,在文件最下面追加相关配置。

接下来说说最常用的 Nginx 配置。

1、server-反向代理配置

server 块的配置,可以说是运维及开发人员使用最多的配置了。我们常说的做一个域名配置、虚拟主机配置、服务反向代理配置,就是指新增一个 server 块的配置。

比如我们在 conf.d 目录下创建一个 hlwyy.conf 的配置文件,命令是 vi /etc/nginx/conf.d/hlwyy.conf。然后我们按键盘上的 i 键,进入插入模式。

(1)HTTP 反向代理配置

输入如下命令——

server {    listen 80;    server_name foobar.com;     
   location / {        proxy_pass http://127.0.0.1:8080/; 
   }}

完成后,按键盘 ESC 键退出插入模式,再按键 :wq 保存退出,这样就完成了一个最简单的 HTTP 域名反向代理配置。

我们分析一下上面的指令。

  1. server:不用说,既然写的是 server,那肯定是对服务做配置,或者说是对虚拟主机做配置

  2. listen:指定 Nginx 服务监听的本地端口,80 是 HTTP 服务的默认端口,443 是 HTTPS 服务的默认端口,监听 80 端口即代表监听 HTTP 连接

  3. server_name:一般是域名,很少会使用 IP 地址,上面写的 “foobar.com“ 是域名,而且这个域名解析到的 IP 地址,就是当前这台安装了 Nginx 的服务器的公网 IP 地址

  4. location:配置路由规则,后面可以是具体 URL 路径或者正则表达式,上面写的 / 就是表示匹配项目根目录的请求,也就是匹配访问 foobar.com/ 这个 URL 的请求

  5. proxy_pass:指定将请求反向代理到哪个服务上,上面的命令就是把 foobar.com/ 的请求,反向代理到本机占用 8080 端口的服务上(对于我们公司的项目而言,基本上都是 tomcat 进程)。注意,如果 Nginx 服务器本身无法访问得通后端的服务地址(换句话说,Nginx 所在的服务器,telnet 不通 127.0.0.1:8080),那么反向代理就是失效的,还是就是服务地址最末尾的正斜杠不要忘了写!

以上命令,还需要再注意一下空格、末尾分号,避免出现不必要的 Nginx 配置语法错误。

(2)HTTPS 反向代理配置

再来看一个最简单的 HTTPS 域名反向代理配置。

server {    listen 443 ssl;    server_name foobar.com;        ssl_certificate /etc/nginx/ssl/foobar.com.crt;    ssl_certificate_key /etc/nginx/ssl/foobar.com.key;        # 匹配根路径的 URL 请求    location / {        proxy_pass http://127.0.0.1:8080/;    }        # 匹配 /admin/ 路径的 URL 请求    location /admin/ {      proxy_pass http://127.0.0.1:13130/;    }        # 图片文件保存在 /data/images 目录下    location ~ \.(gif|jpg|png)$ {    root /data/images;  }}

相比 HTTP 域名的反向代理配置,HTTPS 域名的反向代理配置多了3个新指令。

  1. ssl:紧跟在 listen 监听的 443 端口后面,表示监听 443 端口,开启 ssl 访问

  2. ssl_certificate:指定 ssl 证书文件的路径,Nginx 类型的 ssl 证书文件,在 Linux 服务器上一般是以 .crt 结尾的文件,证书文件路径可以是相对路径,但是为了减少不必要的错误(比如文件权限问题),请设置成绝对路径,放到 /etc/nginx/ssl 目录下

  3. ssl_certificate_key:指定 ssl 私钥文件的路径,Nginx 类型的 ssl 私钥文件,一般是以 .key 结尾的文件,同样使用绝对路径,如 /etc/nginx/ssl/foobar.com.key

注意上面有三个 location 的配置,1个是匹配 foobar.com/ 这个 URL 的请求,1个是匹配 foobar.com/admin/ 这个 URL 的请求,Nginx 分别将它们反向代理到不同的服务上。最后1个 location 后面跟的是正则表达式(以 ~ 符号开头),它根据正则进行匹配,上面的例子是访问 foobar.com/1.png 这个 URL 时,Nginx 会把服务器上的 /data/images/1.png 图片返回给请求端。