# Web服务-Nginx

### 一、Nginx介绍

* Web服务器  反向代理服务器   邮件代理服务器
* 轻量级的Web服务器  删减优化
* 延伸版本 Tengine(淘宝), OpenResty(章亦春)
* <http://nginx.org>
* [http://www.nginx.cn](http://www.nginx.cn/doc/index.html)

### 二、Nginx 安装

#### **1. 获得软件**

sudo wget <http://nginx.org/download/nginx-1.17.1.tar.gz> -P /usr/src

**2. 安装前准备**

```bash
sudo tar zxvf nginx-1.17.1.tar.gz
cd nginx-1.17.1/
sudo apt-get install gcc
sudo apt-get install libpcre3 libpcre3-dev
sudo apt-get install zlib1g-dev
sudo apt-get install openssl libssl-dev
```

**3. 配置**

* 检查环境是否满足安装条件 依赖解决
* 指定安装方式 如配置文件, 命令文件等各类文件放在哪里 开启模块功能(内置模块 三方模块)
* 指定软件安装在哪里

```bash
sudo ./configure --prefix=/usr/local/nginx
```

结果汇总

```
Configuration summary
  + using system PCRE library
  + OpenSSL library is not used
  + using system zlib library

  nginx path prefix: "/usr/local/nginx"
  nginx binary file: "/usr/local/nginx/sbin/nginx"
  nginx modules path: "/usr/local/nginx/modules"
  nginx configuration prefix: "/usr/local/nginx/conf"
  nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
  nginx pid file: "/usr/local/nginx/logs/nginx.pid"
  nginx error log file: "/usr/local/nginx/logs/error.log"
  nginx http access log file: "/usr/local/nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"
```

**4. 编译**

使用gcc将源码生成可执行程序

```bash
sudo make -j4
```

**5. 安装**

```bash
sudo make install
```

**6. 启动**

```bash
sudo /usr/local/nginx/sbin/nginx
```

**7. 验证**

```bash
sudo lsof -i :80
sudo netstat -ntpl
```

**8. 浏览器测试**

```bash
elinks http://127.0.0.1 --dump
```

### 三、Nginx 配置文件详解

配置文件相当于变量文件

/usr/local/nginx/conf/nginx.conf

```
#user nobody;          --> 启动子进程默认用户, 主进程一般是root
worker_processes 1;    -->
```

**相关命令**

```
sudo lsof -i :80
sudo useradd -s /sbin/nologin -r www
sudo killall nginx
```

<https://www.cnblogs.com/ivy-zheng/p/10991915.html>

### 四、默认网站

nginx配置文件中只有一个server的时候, 该server被nginx认为是默认网站, 所有发给服务器80端口的数据都会默认给该server

```
server {
    listen 80;
    server_name localhost;
    location / {
        root html;
        index index.html index.htm;
    }
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root html;
    }
}
```

#### **1. 目录访问控制**

```
cd html
# 访问控制: 允许个别, 拒绝所有
location /a {
    allow 127.0.0.1;
    deny all;

    return 404;
    return 502;
    return http://www.jd.com;
}

# 任何人都可以访问, 当需要用户名密码
location /c {
    auth_basic "登录验证";
    auth_basic_user_file /etc/nginx/htpasswd;
}

htpasswd生成包含用户名和密码的文本文件 "用户名:密码" 浏览网页基本认证
sudo apt search htpasswd
sudo apt install apache2-utils
which htpasswd
sudo htpasswd -m /etc/nginx/htpasswd linda
```

**2. 日志管理**

```
nginx访问日志主要有两个参数控制

log_format # 用来定义记录日志的格式(可以定义多种日志格式, 取不同名字即可)  
log_format test '[$time_local] $remote_addr $request $status';

access_log # 用来指定访问日志文件的路径及格式  
access_log logs/access.log main;

tail -f /usr/local/nginx/logs/access.log
```

自定义json格式 为以后分析做铺垫

```
log_format main_json '{"timestamp": "$time_local",'
'"client_ip": "$remote_addr",'
'"request": "$request",'
'"referer": "$http_referer",'
'"status": "$status"'
'}';
```

**3. 防盗链**

```
location /images/ {
    valid_referers none;
    if($invalid_referer){
        rewrite ^/ http://xxxxx.png;
    }
}
```

**4. 日志截断**

### 五、虚拟主机

把一台物理服务器划分为多个"虚拟"的服务器, 每一个虚拟主机都可以有独立的域名和独立的目录

同时发布两个网站:\
DocumentRoot /usr/local/nginx/html/web01\
DocumentRoot /usr/local/nginx/html/web02

**1. 基于IP的虚拟主机**

实现条件: 两个IP, 两个DocumentRoot并有相应索引页index.html

缺点: 需要多个IP 如果是公网IP 需要收费

```
server {
    listen 192.168.10.20:80;
    location / {
        root html/web01;
        index index.html index.htm index.php;
    }
}
server {
    listen 192.168.10.21:80;
    location / {
        root html/web02;
        index index.html index.htm index.php;
    }
}
```

**2. 基于端口的虚拟主机**

实现条件: 只需一个IP, 多个端口

缺点: 端口是无法告诉公网用户, 无法适用于公网客户, 适合内部用户

```
server {
    listen 80;
    location / {
        root html/web01;
        index index.html index.htm index.php;
    }
}
server {
    listen 8080;
    location / {
        root html/web02;
        index index.html index.htm index.php;
    }
}
```

**3. 基于域名**

一个网站必然有一个域名, 推荐使用

```
sudo sed -i '/#/d' nginx.conf
sudo sed -i '/^$/d' nginx.conf

server {
    listen 80;
    server_name wwww.nining.website nining.website;
    location / {
        root html/web02;
        index index.html index.htm index.php;
    }
}

server {
    listen 80;
    server_name www.nining1314.com nining1314.com;
    location / {
        root html/web01;
        index index.html index.htm index.php;
    }
}
```

### 六、反向代理

正向代理: 小区宽带 局域网 代用户上网\
反向代理: 代理服务器

代理中间多了一层

**堡垒机场景**

网络安全复杂

安全配置只接受来自堡垒机的链接访问, 其他都拒绝

```
graph LR
网络用户客户端 --> 反向代理服务器-公网 
反向代理服务器-公网  --> 业务服务器-私网
```

业务服务器的安全配置只接受来自堡垒机的链接访问, 其他都拒绝

**发布内网服务器**

```
graph LR
网络用户客户端 --> 反向代理服务器-公网 
反向代理服务器-公网  --> 业务服务器-私网PHP
反向代理服务器-公网  --> 业务服务器-私网Java
反向代理服务器-公网  --> 业务服务器-私网Python
```

适合于公网IP地址不足的场景

**缓存场景**

```
graph LR
网络用户客户端 --> 缓存服务器 
缓存服务器  --> 业务服务器
```

静态资源 缓存服务器 比例8\
动态数据 业务服务器 比例2

**反向代理实现**

```
server {
    listen 80;
    server_name localhost;
    location / {
        proxy_pass http://118.190.209.153:4000;

        # 设置header
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # 各类优化，根据实际配置
        client_max_body_size 10m;
        client_body_buffer_size 128k;
        proxy_connect_timeout 90;
        proxy_send_timeout 90;
        proxy_read_timeout 90;
        proxy_buffer_size 4k;
        proxy_buffers 4 32k;
        proxy_busy_buffers_size 64k;
        proxy_temp_file_write_size 64k;
    }
}
```

### 七、限速

防止用户海量请求, 如DDOS防御\
保护磁盘IO, 如下载场景

**限速原理**

水(请求)从上方倒入水桶, 从水桶下方流出(被处理);\
来不及流出的水存在水桶中(缓冲), 以固定速率流出;\
水桶满后水溢出(丢弃)

这个算法的核心: 缓存请求, 匀速处理, 多余的请求直接丢弃

**实现方式**

nginx官方版本限制IP的连接和并发分别有两个模块:

limit\_req\_zone 用来限制单位时间内的请求数, 即速率限制\
limit\_conn\_zone 用来限制同一时间连接数, 即并发限制

```
http {
    limit_req_zone $binary_remote_addr zone=reqlimit:10m rate=1r/s;
    limit_conn_zone $binary_remote_addr zone=connlimit:10m;
    location /abc {
        limit_req zone=reqlimit burst=5 nodelay;
        limit_conn connlimit 1;
        limit_rate 100k;
    }
}
```

### 八、URL重写

rewrite几乎是所有web产品必备技能\
nginx服务器rewrite功能实现依赖pcre(Perl Compatible Regular Expression)

* 域名变更(京东)
* 用户跳转(从某个连接跳转到另个连接)
* 伪静态场景(便于CDN缓存动态页面数据)

原理: Client -> Nginx -> Client ->业务服务

```
# 模糊匹配 ~
# 模糊不匹配 !~
# 不区分大小写匹配 ~*

set $name aaaa;
rewrite ^(.*)$ http://ni-ning.cn/$name;

if ($http_user_agent ~* 'chrome') {
    return 403;
}
```

**url rewrite语法**

```
rewrite <regex> <replacement> [flag]  
关键字  正则    替代内容      标记

redirect   # 返回302临时重定向, 搜索引擎以旧网址排名
permanent  # 返回301永久重定向, 搜索引擎以新网址排名

rewrite ^/$ http://ni-ning.cn permanent;
```

### 九、优化

软件安装的时候，以硬件最小化进行安装，需要优化;\
提高用户体验

#### **1. 工作进程**

* nginx是主进程+工作进程模型
* worker\_processes 1;  工作进程数 按CPU的总核心数
* worker\_cpu\_affinity 0001 0010 0100 1000; CPU的亲和力
* worker\_connections 1024; 一个工作进程的并发数

cat /proc/cpuinfo | grep "flags" | wc -l\
top

#### **2. 长连接**

http协议底层协议为tcp\
优化目标: 减少三次握手和四次断开的次数

* keepalive\_timeout 5; 长连接时间
* keepalive\_requests 8192; 每个长连接接受最大请求数

#### **3. 数据压缩**

减少带宽成本

```
gzip on;
gzip_proxied any;
gzip_min_length 1k;
gzip_buffers 4 8k;
gzip_comp_level 6;
gzip_types text/plain text/css application/x-javascript application/javascript application/xml;
```

**4. 客户端缓存**

```
location ~* \.(png|gif)$ {
    expires 1h;
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://nining.website/python/enterprise-tools/nginx.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
