使用windows入门学习Nginx

220 阅读7分钟

Nginx 功能

反向代理(reverse proxy):

image.png

负载均衡(load banancer):

image.png

加密(Encryption):

image.png

Nginx安装和下载

官网windows版安装教程
Nginx下载地址

如果是windows电脑,记得下载windows版。

image.png

下载解压完后,运行start nginx即可开始运行,运行tasklist命令行实用程序以查看nginx进程:

PS D:\PortableSoftware\nginx-1.23.3> start nginx
PS D:\PortableSoftware\nginx-1.23.3> tasklist /fi "imagename eq nginx.exe"

映像名称                       PID 会话名              会话#       内存使用
========================= ======== ================ =========== ============
nginx.exe                     6464 Console                   12      9,488 K
nginx.exe                    12792 Console                   12      9,472 K

其中一个进程是主进程,另一个是工作进程。如果nginx没有启动,在错误日志文件logs\error.log中查找原因。

运行成功后在浏览器打开localhost或者127.0.0.1 可以看到如下页面:

image.png

Nginx/Windows作为标准控制台应用程序(而不是服务)运行,可以使用以下命令进行管理:

nginx -s stop # fast shutdow
nginx -s quit # graceful shutdown
nginx -s reload # changing configuration, starting new worker processes with a new configuration, graceful shutdown of old worker processes
nginx -s reopen # re-opening log files

如果使用的是powershell需要在nginx前加上.\来运行命令,使用 cmd 则无须加前缀。

PS D:\PortableSoftware\nginx-1.23.3> nginx -s stop
nginx : 无法将“nginx”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确。
PS D:\PortableSoftware\nginx-1.23.3> .\nginx -s stop

有的时候尝试停止nginx出现了错误,我们可以使用taskkill来强制停止。

taskkill /pid <PID> /f
#  其中,`<PID>`是找到的Nginx进程的PID。

举例:

D:\PortableSoftware\nginx-1.23.3>tasklist /fi "imagename eq nginx.exe"

映像名称                       PID 会话名              会话#       内存使用
========================= ======== ================ =========== ============
nginx.exe                    23136 Console                    9      8,724 K
nginx.exe                     3304 Console                    9      9,052 K
D:\PortableSoftware\nginx-1.23.3>taskkill /pid 23136 /f
成功: 已终止 PID 为 23136 的进程。

D:\PortableSoftware\nginx-1.23.3>taskkill /pid 3304 /f
成功: 已终止 PID 为 3304 的进程。

Nignx术语

nginx.conf 这个文件是配置文件。

image.png 这种类似键值对的被叫作指令(directive):

worker_processes  1;

花括号包裹的代码块被叫作上下文(context),上下文里面可以有指令,上下文是指令生效的环境。

events {
    worker_connections  1024;
}

从零配置

接下来,删掉nginx.conf的内容,开始从零配置。

运行静态网站

首先,我们先用nginx让一个html文件能在浏览器运行起来,这里我使用nginx自带的html文件:

image.png

http {
  server {
    
    # 指定端口
    listen 80;
    
    # root表示当匹配这个请求的路径时,将会在这个文件夹内寻找相应的文件
    root html;
    
    # 当没有指定主页时,默认会选择这个指定的文件,它可以有多个,并按顺序来加载,如果第一个不存在,则找第二个,依此类推。
    index index.html
  }
}

events {}

然后我修改一下原来的html文件,并刷新一下浏览器,发现它work了!没想到啊,几行指令配置就可以。

image.png

在Nginx配置中,events {}块是必需的,因为它定义了Nginx服务器的全局事件模型。这个块主要用于配置与连接处理相关的参数,例如工作进程数、连接超时等。

events {}块中,可以设置以下参数:

  • worker_connections:指定每个工作进程的最大连接数。
  • use:指定事件驱动模型,如epollkqueueeventportselect
  • multi_accept:指定是否接受多个连接。
  • accept_mutex:指定是否使用互斥锁来接受新连接。
  • worker_processes:指定工作进程的数量。

虽然在简单的Nginx配置中,你可能不需要在events {}块中设置任何参数,但是它仍然是必需的,因为它定义了Nginx服务器的全局事件模型。如果你不包含events {}块,Nginx配置文件将无效。

配置Mine Type

如果在想在html通过link标签中引入css,则需要配置mine type,否则nginx就把响应类型设置成了text/plain

image.png

http {

  # 指定文件后缀对应的Content-Type
  types {
    # 如果文件后缀是css,则配置它的Content-Type为text/css
    text/css css;
    # 如果文件后缀是js,则配置它的Content-Type为application/javascript
    application/javascript js;
    
  }

  server {
    # 指定端口
    listen 80;
    root html;
    index index.html;
  }
}
events{

}

运行nginx -s reload后,就发现此时css文件的content-type被设置成了text/css

image.png

但实际环境下超级多的文件类型,如果一个一个的配置,会非常累。幸运的是,nginx已经给我们提供了mime.types文件,我们只需要在nginx.conf引入它即可。

image.png

http {
	
  include mime.types;

  server {
    # 指定端口
    listen 80;
    root html;
    index index.html;
  }

}
events{

}

配置location context

示例一

如果我们想要访问另外一个网页呢,比如当用户访问http://localhost:80/fruits后,进入到fruits网页。

image.png

我们可以这样通过指定location来实现:

http {

  include mime.types;

  server {
    # 指定端口
    listen 80;
    root html;
    index index.html;

    location /fruits { 
      # 当我们访问/fruits时,就会去访问html/fruits目录下的index.html文件
      root html;
    }
  }
}
events {

}

image.png

示例二 alias指令

如果想要访问/carbs的时候,nginx也给我们serve fruits 页面呢?

http {

  include mime.types;

  server {
    # 指定端口
    listen 80;
    root html;
    index index.html;

    location /fruits { 
      # 当我们访问/fruits时,就会去访问html/fruits目录下的index.html文件
      # 也就是nginx会自动拼接root和location的路径 变成了html/fruits/index.html
      root html;
    }

    location /carbs{
      # 不能使用root,因为我们并没有创建carbs目录
      alias html/fruits;
    }
  }
}
events {

}

示例3:try_files指令

如果我们再创建了一个vegetables目录后,但是我们的html文件不叫index.html,而叫做veggies.html。这个时候,我们可以配置try_files或者使用index直接指定主页。

http {

  include mime.types;

  server {
    # 指定端口
    listen 80;
    root html;
    index index.html;

    location /fruits {
      # 当我们访问/fruits时,就会去访问html/fruits目录下的index.html文件
      # 也就是nginx会自动拼接root和location的路径 变成了html/fruits/index.html
      root html;
    }

    location /carbs {
      # 不能使用root,因为我们并没有创建carbs目录
      alias html/fruits;
    }

    location /vegetables {
      root html;
      # 先去访问html/vegetables/veggies.html文件,如果没有就去访问html/index.html文件,如果还没有就返回404
      try_files /vegetables/veggies.html /index.html =404;
      # 直接指定主页时veggis.html
      index veggies.html;

    }
  }
}
events {

}


示例4:正则匹配

在 location context 中,可以使用正则表达式来匹配 URI。可以使用 ~ 或 ~* 前缀来指定正则表达式匹配,其中 ~ 区分大小写,~* 不区分大小写。

http {

  include mime.types;

  server {
    # 指定端口
    listen 80;
    root html;
    index index.html;
    # ~*表示正则匹配,如果请求的url是/count/开头的,就会去访问html/count目录下的文件
    location ~* /count/[0-9] {
      try_files /index.html =404;
    }
  }
}
events {

}

我们这里设置,如果用户访问的是/count/[0-9],则让nginx去serve 根目录下的index.html,但由于我们的这个index.html 还引入了style.css,nginx就去count/style.css去找css了,导致404。

image.png

所以我们可以这样配置:

http {

  include mime.types;

  server {
    # 指定端口
    listen 80;
    root html;
    index index.html;
    # ~*表示正则匹配,如果请求的url是/count/开头的,就会去访问html/count目录下的文件
    location ~* /count/[0-9] {
      alias html/;
      try_files /index.html =404;
    }
    location /count/style.css {
      alias html/style.css;
    }
  }
}
events {
}

重定向和重写

现在我们已经有/fruits路由了,如果想要当用户访问/crops时,重定向到/fruits路由,可以这样配置。

http {

  include mime.types;

  server {
    # 指定端口
    listen 80;
    root html;
    index index.html;
  
    location /fruits {
      # 当我们访问/fruits时,就会去访问html/fruits目录下的index.html文件
      # 也就是nginx会自动拼接root和location的路径 变成了html/fruits/index.html
      root html;
    }

    location /crops {
      # 307 临时重定向 302 也是临时重定向 302假设客户端会改用GET方法 307要求客户端继续使用原来的请求方法
      return 307 /fruits;
    }
  }
}
events {}

可以看到如果用户访问了/crops,他会被重定向到/fruits路由。

image.png

但如果,我们并不想重定向,只是想要别的路由下路由,就可以使用rewrite指令。下面的示例中,如果访问/number/数字,nginx则会提供/count/数字的内容

http {

  include mime.types;

  server {
    # 指定端口
    listen 80;
    root html;
    index index.html;

    rewrite ^/number/(\d+) /count/$1;

    location ~* /count/[0-9] {
      alias html/;
      try_files /index.html =404;
    }
   

  }
}
events {

}

负载均衡 (load banancer)

基本概念

负载均衡是一种将网络流量分发到多个服务器上的技术,以实现更高的可用性、性能和可扩展性。在负载均衡系统中,请求会被分发到不同的服务器上,从而避免任何一台服务器过载或出现故障时影响整个系统的运行。

nginx实现负载均衡的方式有多种,下面是其中两种常用的方式:

a.基于轮询(Round Robin) 默认情况下,nginx使用轮询算法进行负载均衡,将请求均匀地分发到多个后端服务器上。例如,在下面的配置中,nginx将请求轮流转发到server1和server2两台服务器上:

upstream backend {
    server server1;
    server server2;
}	

这种方法的优点是简单易用,可以均衡地分配请求。但是,如果某个后端服务器出现故障,则需要手动将其从upstream中删除,否则nginx仍然会将请求转发到该服务器上。

b.基于权重(Weighted Round Robin)

在轮询算法的基础上,nginx还可以使用权重算法进行负载均衡。通过为每个后端服务器分配不同的权重值,使得某些服务器能够处理更多的请求。例如,在下面的配置中,nginx将70%的请求转发到server1上,30%的请求转发到server2上:

upstream backend {
    server server1 weight=7;
    server server2 weight=3;
}

制作运行docker镜像

我们可以docker来运行多个server,这里就用express当作服务器。

npm init -y
npm i express
const express = require('express');
const app = express();

app.get('/',(req,res)=>{
  res.send('I am a endpoint');
})

app.listen(7777,()=>{
  console.log('listening on http://localhost:7777');
})

然后再创建DockerFile,跟着node官网的教程来操作:

FROM node:16

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

RUN npm install
# If you are building your code for production
# RUN npm ci --omit=dev

# Bundle app source
COPY . .

EXPOSE 7777
CMD [ "npm", "run","start" ]

image.png

最后制作镜像:

 docker build . -t myserver

可以在docker desktop看到已经制作完的镜像:

image.png

接着开始跑运行该镜像的容器,尽管我们容器是运行在7777端口的,但是我们可以映射为我们本机的任意端口。

# -p 端口映射 -d 后台运行
docker run -p 1111:7777 -d myserver

然后如果我们访问http://localhost,就可以发现运行成功了:

image.png

那我们再继续运行几个容器:

docker run -p 2222:7777 -d myserver
docker run -p 3333:7777 -d myserver
docker run -p 4444:7777 -d myserver

image.png

nginx配置负载均衡

http {

  include mime.types;

  upstream backendserver{
      server 127.0.0.1:1111;
      server 127.0.0.1:2222;
      server 127.0.0.1:3333;
      server 127.0.0.1:4444;
  }

  server {
    # 指定端口
    listen 80;
    

    location /{
      proxy_pass http://backendserver/;
    }


  }
}
events {

}

最后,这个是全部的配置:

http {

  include mime.types;

  upstream backendserver{
      server 127.0.0.1:1111;
      server 127.0.0.1:2222;
      server 127.0.0.1:3333;
      server 127.0.0.1:4444;
  }

  server {
    # 指定端口
    listen 80;
    root html;
    index index.html;

    rewrite ^/number/(\d+) /count/$1;

    # ~*表示正则匹配,如果请求的url是/count/开头的,就会去访问html/count目录下的文件
    location ~* /count/[0-9] {
      alias html/;
      try_files /index.html =404;
    }
    location /count/ {
      alias html/;
    }

    location /{
      proxy_pass http://backendserver/;
    }

    location /fruits {
      # 当我们访问/fruits时,就会去访问html/fruits目录下的index.html文件
      # 也就是nginx会自动拼接root和location的路径 变成了html/fruits/index.html
      root html;
    }

    location /carbs {
      # 不能使用root,因为我们并没有创建carbs目录
      alias html/fruits;
    }

    location /vegetables {
      root html;
      # 先去访问html/vegetables/veggies.html文件,如果没有就去访问html/index.html文件,如果还没有就返回404
      try_files /vegetables/veggies.html /index.html =404;
      # 直接指定主页时veggis.html
      index veggies.html;
    }

    location /crops{
      # 307 临时重定向 302 也是临时重定向 302假设客户端会改用GET方法 307要求客户端继续使用原来的请求方法
      return 307 /fruits;
    }
  }
}
events {

}

注:本文是根据此youtu.be/7VAI73roXaY 视频