Linux Nginx全套实战通关|静态站点/虚拟主机/HTTPS/PHP/反向代理/七层负载均衡,每行命令逐参数拆解


📢 写在前面

哈喽各位小伙伴!👋 今天这篇绝对是 Web运维入门到进阶的硬核干货

你是不是也遇到过这些问题:

  • 😫 装完Nginx只会放个静态页面,虚拟主机、HTTPS、反向代理完全不会配?
  • 😱 location匹配规则记不住,配完404完全不知道为什么?
  • 🤯 proxy_pass后面带不带斜杠 / 有什么区别?踩坑无数?
  • 🤔 负载均衡的轮询、权重、ip_hash、least_conn到底怎么选?

别慌!今天这篇文章我将用 最通俗的语言 + 最详细的命令注释 ,带你从零掌握Nginx六大核心实验:

基础部署 → 虚拟主机 → HTTPS加密 → Basic认证 → PHP动态站点 → 反向代理 → 七层负载均衡

每一行命令都给你掰碎了讲,小白也能轻松跟上~建议先收藏⭐再看!


📚 全文知识地图

模块 核心内容 运维实战价值 难度指数
Nginx基础 架构原理、master-worker、热重载、常用命令 理解Nginx为什么快,面试高频考点 ⭐⭐
基础部署 安装、静态站点、防火墙放行 最基础的Web服务搭建
虚拟主机 基于域名、基于端口 一台服务器跑多个网站,节约成本 ⭐⭐
HTTPS/SSL openssl生成证书、443配置、301跳转 生产网站标配,防抓包防劫持 ⭐⭐⭐
Basic认证 htpasswd生成密码、auth_basic配置 后台管理页面简单加密防护 ⭐⭐
PHP站点 php-fpm安装、FastCGI配置 动静分离架构,PHP网站标准部署 ⭐⭐⭐
反向代理 location匹配、proxy_pass、路径重写 隐藏后端服务,统一入口,企业标配 ⭐⭐⭐⭐
七层负载均衡 upstream、轮询/权重/ip_hash/least_conn 集群流量分发,高并发必备 ⭐⭐⭐⭐

💡 小贴士 :本文所有命令都在 CentOS 7 环境下验证通过,所有主机名中的 laogao 已统一替换为 jhl,放心抄作业!


🧠 第一部分:Nginx核心原理(先懂原理再动手)

🤔 1.1 Nginx是什么?

Nginx(发音:engine-x)是一款 高性能、事件驱动的开源Web服务器,同时也可做反向代理、负载均衡、HTTP缓存、静态资源服务器。由俄罗斯工程师 Igor Sysoev 开发,现在是互联网主流服务组件。

🎯 核心数据 :在高连接并发情况下,能够支持高达 5万个并发连接 的响应,而内存、CPU等系统资源消耗却非常低,运行非常稳定。

⚡ 1.2 Nginx三大核心特点

特点1:事件驱动模型(epoll/kqueue)

采用 异步非阻塞IO,单进程可以处理大量并发连接,高并发消耗资源少,万级并发很轻松,远优于传统Apache多进程模型。

对比项 传统Apache Nginx
模型 一连接一进程/线程 少量worker进程 + IO多路复用
1万并发 需要1万个进程,内存暴涨 一个worker同时处理上万个连接
资源消耗 上下文切换开销巨大 大部分连接空闲等待,几乎不消耗CPU

特点2:轻量

占用内存、CPU低,部署简单,配置文件简洁。

特点3:多角色能力(不止Web服务器)

角色 说明
Web服务器 直接托管静态文件(html/js/css/图片)
反向代理 把客户端请求转发给后端服务(Tomcat、SpringBoot、Node、PHP-FPM)
负载均衡 多台后端服务器分发流量,做集群
HTTP缓存 缓存后端响应,减轻后端压力
SSL/TLS终端 处理HTTPS证书解密加密
其他 限流、防盗链、gzip压缩、访问控制、虚拟主机

🏗️ 1.3 Nginx架构:master-worker多进程模型

Nginx是多进程模型,采用 master-worker架构

进程 运行权限 核心工作 是否处理业务请求
master主进程 root 读取解析配置文件、管理所有worker子进程、接收系统信号(启动/停止/reload/重开日志) ❌ 只做管理
worker工作进程 nginx 真正处理网络请求,执行TCP连接、HTTP解析、转发、读写文件 ✅ 全部业务逻辑
cache loader/manager nginx cache manager管理磁盘缓存清理过期文件;cache loader启动时加载缓存元数据 ❌ 缓存管理(可选)

💡 建议配置worker_processes auto;,自动等于CPU物理核心数。worker之间互相独立,不共享内存。

🔄 1.4 热重载原理(nginx -s reload)

这是Nginx最牛的特性之一,更新配置不中断服务

复制代码
1. master读取新配置,校验语法
    ↓
2. 启动一批新worker进程,新worker加载新配置处理新请求
    ↓
3. 向旧worker发送信号,旧worker不再接收新连接,处理完已有连接后退出
    ↓
✅ 整个过程服务不中断,无宕机

📋 1.5 Nginx常用命令

命令 作用
nginx 启动Nginx
nginx -s stop 快速停止(强制终止)
nginx -s quit 优雅停止,处理完现有连接再退出
nginx -s reload 重载配置(最常用,热重载不中断服务)
nginx -t 校验配置文件语法是否正确(改完配置必执行!)

🚀 第二部分:实验一 Nginx基础部署与静态站点

🤔 为什么要做这个实验?运维作用

这是所有Web服务的基础。学会安装Nginx、配置静态站点、放行防火墙,才能在此基础上做虚拟主机、HTTPS、反向代理等进阶功能。线上90%的网站前端都是Nginx。

💡 实验完整思路

  1. 两台机器配置主机名和静态IP(一台服务端、一台客户端);
  2. 服务端配置阿里EPEL源(CentOS7默认源没有Nginx);
  3. yum安装Nginx;
  4. 设置开机自启并启动;
  5. 替换默认首页为自定义内容;
  6. 防火墙放行HTTP 80端口;
  7. 客户端配置hosts域名解析,curl访问测试。

📋 节点规划

节点名称 节点IP 作用
nginx-server 10.1.8.10/24 搭建Nginx服务端
nginx-client 10.1.8.11/24 客户端访问测试

🔧 操作命令(逐行注释)

步骤1:nginx-server基础配置

bash 复制代码
# ============================================================
# hostnamectl set-hostname:永久修改系统主机名,重启后永久生效
# 参数:nginx-server 为新主机名
# ============================================================
[root@localhost ~]# hostnamectl set-hostname nginx-server

# ============================================================
# nmcli connection modify:修改网卡连接配置
#   ens33:网卡设备名
#   ipv4.method manual:关闭DHCP,启用手动静态IP模式
#   ipv4.addresses 10.1.8.10/24:设置IPv4地址,/24表示24位子网掩码
#   ipv4.gateway 10.1.8.2:默认网关地址
#   ipv4.dns 10.1.8.2:DNS服务器地址
#   autoconnect yes:开机自动激活网卡
# ============================================================
[root@localhost ~]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.10/24 ipv4.gateway 10.1.8.2 ipv4.dns 10.1.8.2 autoconnect yes

# ============================================================
# nmcli connection up:激活(重载)网卡连接,使配置立即生效,无需重启
# ============================================================
[root@localhost ~]# nmcli connection up ens33

步骤2:nginx-client基础配置

bash 复制代码
[root@localhost ~]# hostnamectl set-hostname nginx-client
[root@localhost ~]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.11/24 ipv4.gateway 10.1.8.2 ipv4.dns 10.1.8.2 autoconnect yes
[root@localhost ~]# nmcli connection up ens33

步骤3:安装Nginx(服务端)

bash 复制代码
# ============================================================
# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
#   下载阿里云EPEL软件源到yum源配置目录
#   -O:指定下载文件的输出路径(大写O)
#   CentOS7默认base源没有Nginx,必须先配置EPEL源
# ============================================================
[root@nginx-server ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

# ============================================================
# yum -y install nginx
#   yum在线安装Nginx
#   -y:自动确认所有交互提示,无需手动输入y
# ============================================================
[root@nginx-server ~]# yum -y install nginx

步骤4:启动Nginx

bash 复制代码
# ============================================================
# systemctl enable nginx --now
#   enable:设置Nginx开机自启
#   --now:同时立即启动服务(不用再单独执行start)
# ============================================================
[root@nginx-server ~]# systemctl enable nginx --now

步骤5:准备自定义首页

bash 复制代码
# ============================================================
# mv /usr/share/nginx/html/index.html{,.ori}
#   备份默认首页,大括号扩展等价于:
#   mv /usr/share/nginx/html/index.html /usr/share/nginx/html/index.html.ori
#   {,.ori} 表示在原文件名后加.ori后缀
# ============================================================
[root@nginx-server ~]# mv /usr/share/nginx/html/index.html{,.ori}

# ============================================================
# echo Hello World From Nginx > /usr/share/nginx/html/index.html
#   将文本写入新的首页文件
#   >:覆盖写入(如果文件存在则覆盖)
# ============================================================
[root@nginx-server ~]# echo Hello World From Nginx > /usr/share/nginx/html/index.html

步骤6:防火墙放行HTTP

bash 复制代码
# ============================================================
# firewall-cmd --add-service=http --permanent
#   永久放行HTTP服务(对应80端口)
#   --add-service:按服务名称放行(http对应TCP 80)
#   --permanent:永久写入防火墙规则,重启后不丢失
# ============================================================
[root@nginx-server ~]# firewall-cmd --add-service=http --permanent

# ============================================================
# firewall-cmd --reload
#   重载防火墙配置,使永久规则立即生效
# ============================================================
[root@nginx-server ~]# firewall-cmd --reload

步骤7:客户端测试访问

bash 复制代码
# ============================================================
# 配置域名解析(Windows客户端修改 C:\Windows\System32\drivers\etc\hosts)
# Linux客户端修改 /etc/hosts
# 添加如下记录:将www.jhl.cloud解析到10.1.8.10
# ============================================================
[root@nginx-client ~]# vim /etc/hosts
# 添加:10.1.8.10 www.jhl.cloud

# ============================================================
# curl http://www.jhl.cloud
#   通过域名访问Nginx站点,输出页面内容
# ============================================================
[root@nginx-client ~]# curl http://www.jhl.cloud
Hello World From Nginx

实验现象解释 :curl输出 Hello World From Nginx,说明Nginx安装成功、静态站点正常工作、防火墙80端口已放行、域名解析正确。


⚙️ 第三部分:Nginx配置文件详解

📂 配置文件路径

主配置文件:/etc/nginx/nginx.conf

🏗️ 配置结构(五层嵌套)

Nginx配置采用层级化、模块化的组织方式:

复制代码
全局块 → events块 → http块 → server块 → location块
配置块 作用范围 核心配置
全局块 整个Nginx实例 user、worker_processes、error_log、pid
events块 网络连接、并发参数 worker_connections、use epoll、multi_accept
http块 所有HTTP/HTTPS服务共用 mime.types、日志格式、sendfile、keepalive_timeout
server块 单个虚拟主机(站点) listen、server_name、root、error_page
location块 站点内不同URI路径规则 proxy_pass、root、alias、try_files

1. 全局配置块示例

nginx 复制代码
user nginx;                           # 运行Nginx的用户/用户组
worker_processes auto;                # 工作进程数(核心参数,建议设为CPU核心数)
error_log /var/log/nginx/error.log;   # 错误日志路径
pid /run/nginx.pid;                   # 主进程PID文件路径
include /usr/share/nginx/modules/*.conf;  # 加载外部模块配置(全局级引入)

2. events块(核心模块)

nginx 复制代码
events {
    worker_connections 1024;   # 单个worker最大并发连接数
    use epoll;                 # IO多路复用模型,Linux默认epoll
    multi_accept on;           # 允许一个进程一次性接受多个新连接
}

3. http块(业务模块)

nginx 复制代码
http {
    include             /etc/nginx/mime.types;     # 加载MIME类型映射
    default_type        application/octet-stream;  # 默认响应类型
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request"';  # 日志格式
    access_log      /var/log/nginx/access.log  main;  # 访问日志
    sendfile          on;    # 高效发送文件,静态文件性能优化
    keepalive_timeout   65;  # HTTP长连接超时(秒)

    # server块:虚拟主机配置(一个http块可包含多个server)
    server {
        listen       80;              # 监听端口(80=HTTP,443=HTTPS)
        server_name  localhost;       # 域名/IP(可配置多个,空格分隔)
        root         /usr/share/nginx/html;  # 网站根目录

        # location块:匹配URI路径,处理请求
        location / {
            index    index.html index.htm;     # 默认首页
            try_files $uri $uri/ /index.html;  # 路径匹配规则
        }

        # 错误页面配置
        error_page  404              /404.html;
        error_page  500 502 503 504  /50x.html;
    }
}

4. HTTPS专属配置块

nginx 复制代码
server {
    listen        443 ssl;      # 监听HTTPS端口并启用SSL
    server_name   example.com;
    ssl_certificate        /etc/nginx/cert/server.crt;   # 公钥文件
    ssl_certificate_key    /etc/nginx/cert/server.key;   # 私钥文件
    ssl_session_cache      shared:SSL:1m;
    ssl_session_timeout    5m;
    ssl_ciphers   HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers   on;
}

🎯 location匹配规则(优先级从高到低)

优先级 语法 说明
1(最高) location = /uri 精确匹配,完全一致才命中
2 location ^~ /uri 前缀匹配,命中后不执行正则
3 location ~ regex 大小写敏感正则匹配
4 location ~* regex 大小写不敏感正则匹配
5 location /uri 普通前缀匹配
6(最低) location / 默认兜底匹配

📦 Nginx内置常用变量

变量 含义
$uri 请求的URI,不带参数
$args URL后面的GET查询参数
$request_uri 完整URI + 参数
$remote_addr 客户端真实IP
$http_host 请求头Host
$http_user_agent 客户端浏览器UA
$scheme 协议 http/https
$server_name 当前server的域名
$request_method 请求方法 GET/POST

🌐 第四部分:实验二 虚拟主机(一台服务器跑多个网站)

🤔 为什么要做这个实验?运维作用

虚拟主机让一台服务器可以托管多个独立网站,大大节约硬件成本。企业官网、博客、后台系统可以共用一台Nginx服务器。

💡 实验思路

虚拟主机支持三种方式:

  1. 基于主机名(域名):最常用,不同域名区分站点;
  2. 基于端口号:同一域名不同端口区分站点;
  3. 基于IP地址:不同IP区分站点(基本不用)。

🔧 2.1 基于名称的虚拟主机

实验思路

  1. 复制主配置模板到conf.d目录(模块化管理);
  2. 编写两个server块,不同server_name对应不同root目录;
  3. 创建两个网站根目录和首页;
  4. 重启Nginx;
  5. 客户端配置hosts,分别curl两个域名验证。
bash 复制代码
# ============================================================
# cp /etc/nginx/nginx.conf /etc/nginx/conf.d/vhost-name.conf
#   复制主配置文件作为虚拟主机配置模板
#   /etc/nginx/conf.d/ 目录下的.conf文件会被主配置的include自动加载
# ============================================================
[root@nginx-server ~]# cp /etc/nginx/nginx.conf /etc/nginx/conf.d/vhost-name.conf

# ============================================================
# vim 编辑虚拟主机配置文件
# ============================================================
[root@nginx-server ~]# vim /etc/nginx/conf.d/vhost-name.conf

配置文件内容:

nginx 复制代码
# 第一个虚拟主机:web1.jhl.cloud
server {
    server_name    web1.jhl.cloud;   # 匹配域名web1.jhl.cloud
    root           /usr/share/nginx/web1;  # 网站根目录
}

# 第二个虚拟主机:web2.jhl.cloud
server {
    server_name    web2.jhl.cloud;   # 匹配域名web2.jhl.cloud
    root           /usr/share/nginx/web2;  # 网站根目录
}
bash 复制代码
# ============================================================
# mkdir /usr/share/nginx/web{1,2}
#   大括号扩展,同时创建web1和web2两个目录
#   等价于 mkdir /usr/share/nginx/web1 /usr/share/nginx/web2
# ============================================================
[root@nginx-server ~]# mkdir /usr/share/nginx/web{1,2}

# 分别写入两个站点的首页
[root@nginx-server ~]# echo web1.jhl.cloud > /usr/share/nginx/web1/index.html
[root@nginx-server ~]# echo web2.jhl.cloud > /usr/share/nginx/web2/index.html

# ============================================================
# systemctl restart nginx
#   重启Nginx使配置生效
#   (生产环境推荐用 nginx -s reload 热重载,不中断服务)
# ============================================================
[root@nginx-server ~]# systemctl restart nginx

客户端测试

bash 复制代码
# 配置名称解析,假设web服务器IP为10.1.8.10
[root@nginx-client ~]# vim /etc/hosts
# 添加:10.1.8.10 web1.jhl.cloud web2.jhl.cloud

# 访问web1
[root@nginx-client ~]# curl http://web1.jhl.cloud/
web1.jhl.cloud

# 访问web2
[root@nginx-client ~]# curl http://web2.jhl.cloud/
web2.jhl.cloud

实验现象:访问不同域名返回不同页面内容,说明基于名称的虚拟主机配置成功。

清理环境(避免影响后续实验)

bash 复制代码
[root@nginx-server ~]# mkdir /etc/nginx/conf.d/vhosts
[root@nginx-server ~]# mv /etc/nginx/conf.d/vhost-name.conf /etc/nginx/conf.d/vhosts

🔧 2.2 基于端口的虚拟主机

实验思路

  1. 编写两个server块,相同server_name但不同listen端口;
  2. 创建对应目录和首页;
  3. 重启Nginx;
  4. 客户端通过不同端口访问验证。
bash 复制代码
[root@nginx-server ~]# vim /etc/nginx/conf.d/vhost-port.conf

配置文件内容:

nginx 复制代码
# 第一个站点:监听8081端口
server {
    listen        8081;                # 监听8081端口
    server_name   www.jhl.cloud;       # 域名
    root          /usr/share/nginx/8081;  # 网站根目录
}

# 第二个站点:监听8082端口
server {
    listen        8082;                # 监听8082端口
    server_name   www.jhl.cloud;       # 相同域名
    root          /usr/share/nginx/8082;  # 不同根目录
}
bash 复制代码
# 创建目录(大括号扩展创建8081和8082)
[root@nginx-server ~]# mkdir /usr/share/nginx/808{1,2}

# 写入首页
[root@nginx-server ~]# echo 8081 > /usr/share/nginx/8081/index.html
[root@nginx-server ~]# echo 8082 > /usr/share/nginx/8082/index.html

# 重启Nginx
[root@nginx-server ~]# systemctl restart nginx

客户端测试

bash 复制代码
# 配置域名解析
[root@nginx-client ~]# vim /etc/hosts
# 添加:10.1.8.10 www.jhl.cloud

# 访问8081端口
[root@nginx-client ~]# curl http://www.jhl.cloud:8081
8081

# 访问8082端口
[root@nginx-client ~]# curl http://www.jhl.cloud:8082
8082

实验现象:同一域名不同端口返回不同页面,基于端口的虚拟主机配置成功。

⚠️ 注意:生产环境优先使用基于域名的虚拟主机,多端口需要用户手动输入端口,体验差。

清理环境

bash 复制代码
[root@nginx-server ~]# mv /etc/nginx/conf.d/vhost-port.conf /etc/nginx/conf.d/vhosts

🔒 第五部分:实验三 配置SSL/TLS(HTTPS加密)

🤔 为什么要做这个实验?运维作用

HTTPS = HTTP + SSL/TLS,加密传输防止数据被抓包篡改,是生产网站标配。浏览器对HTTP站点会标记"不安全",小程序、微信公众号也要求HTTPS。

💡 实验思路

  1. 使用openssl生成私钥(key);
  2. 生成证书请求文件(csr);
  3. 使用私钥自签名生成公钥证书(crt);
  4. 将证书文件移动到标准目录;
  5. 配置Nginx监听443端口,指定证书路径;
  6. 配置80端口301永久重定向到HTTPS;
  7. 防火墙放行HTTPS 443端口;
  8. 客户端curl测试(-k忽略自签名证书警告,-L跟随重定向)。

🔧 步骤1:生成证书

bash 复制代码
# ============================================================
# mkdir certs && cd certs
#   创建证书目录并进入该目录
#   &&:前一条命令成功才执行后一条
# ============================================================
[root@nginx-server ~]# mkdir certs && cd certs

# ============================================================
# openssl genrsa -out www.key 2048
#   生成RSA私钥
#   genrsa:生成RSA私钥子命令
#   -out www.key:输出私钥文件名为www.key
#   2048:密钥长度2048位(越长越安全,性能开销越大)
# ============================================================
[root@nginx-server certs]# openssl genrsa -out www.key 2048

# ============================================================
# openssl req -new -key www.key -out www.csr -subj "/C=CN/ST=JS/L=NJ/O=LG/OU=DEVOPS/CN=www.jhl.cloud/emailAddress=webadmin@jhl.cloud"
#   生成证书签名请求文件(CSR)
#   req:证书请求子命令
#   -new:生成新的证书请求
#   -key www.key:使用刚才生成的私钥
#   -out www.csr:输出CSR文件
#   -subj:一次性填写证书信息(免交互)
#     /C=CN:国家(China)
#     /ST=JS:省份(JiangSu)
#     /L=NJ:城市(NanJing)
#     /O=LG:组织名称
#     /OU=DEVOPS:部门名称
#     /CN=www.jhl.cloud:通用名称(必须是网站域名!最重要)
#     /emailAddress=webadmin@jhl.cloud:管理员邮箱
# ============================================================
[root@nginx-server certs]# openssl req -new -key www.key -out www.csr -subj "/C=CN/ST=JS/L=NJ/O=LG/OU=DEVOPS/CN=www.jhl.cloud/emailAddress=webadmin@jhl.cloud"

# ============================================================
# openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt
#   使用自己的私钥对CSR签名,生成自签名证书
#   x509:X.509证书子命令
#   -req:输入是CSR请求文件
#   -days 3650:证书有效期3650天(10年)
#   -in www.csr:输入CSR文件
#   -signkey www.key:使用私钥签名
#   -out www.crt:输出公钥证书文件
# ============================================================
[root@nginx-server certs]# openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt

📌 三个文件的作用

  • www.key:私钥(必须保密!)
  • www.csr:证书请求(中间文件,提交给CA签名用)
  • www.crt:公钥证书(配置HTTPS用,发给客户端)

🔧 步骤2:配置HTTPS站点

bash 复制代码
# 创建证书存放目录
[root@nginx-server certs]# mkdir /etc/ssl/certs/www.jhl.cloud

# 将所有证书相关文件移动到标准目录
[root@nginx-server certs]# mv www* /etc/ssl/certs/www.jhl.cloud

# 复制主配置模板
[root@nginx-server ~]# cp /etc/nginx/nginx.conf /etc/nginx/conf.d/vhost-www.jhl.cloud-ssl.conf

# 编辑配置文件
[root@nginx-server ~]# vim /etc/nginx/conf.d/vhost-www.jhl.cloud-ssl.conf

配置文件内容(HTTPS站点):

nginx 复制代码
server {
    listen            443 ssl http2;   # 监听443端口,启用SSL和HTTP/2
    listen            [::]:443 ssl http2;  # IPv6的443端口
    server_name       www.jhl.cloud;   # 网站域名
    root              /usr/share/nginx/html;  # 网站根目录

    # 证书(公钥)
    ssl_certificate "/etc/ssl/certs/www.jhl.cloud/www.crt";
    # 私钥(必须保密)
    ssl_certificate_key "/etc/ssl/certs/www.jhl.cloud/www.key";
}
bash 复制代码
# 重启Nginx
[root@nginx-server ~]# systemctl restart nginx

# 防火墙放行HTTPS
[root@nginx-server ~]# firewall-cmd --add-service=https --permanent
[root@nginx-server ~]# firewall-cmd --reload

🔧 步骤3:配置HTTP强制跳转HTTPS

编辑同一个配置文件,增加80端口的server块:

nginx 复制代码
# HTTPS站点
server {
    listen        443 ssl http2;
    listen        [::]:443 ssl http2;
    server_name   www.jhl.cloud;
    root          /usr/share/nginx/html;
    ssl_certificate "/etc/ssl/certs/www.jhl.cloud/www.crt";
    ssl_certificate_key "/etc/ssl/certs/www.jhl.cloud/www.key";
}

# 配置HTTP重定向到HTTPS
server {
    listen        80;
    listen        [::]:80;
    server_name   www.jhl.cloud;
    root          /usr/share/nginx/html;
    # 添加重定向:301永久重定向到HTTPS
    # $host:客户端请求的域名;$request_uri:完整请求URI+参数
    return        301 https://$host$request_uri;
}
bash 复制代码
[root@nginx-server ~]# systemctl restart nginx
[root@nginx-server ~]# firewall-cmd --add-service=https --permanent
[root@nginx-server ~]# firewall-cmd --reload

🔧 步骤4:客户端测试

bash 复制代码
# 测试HTTP访问(应该返回301跳转页面)
[root@nginx-client ~]# curl http://www.jhl.cloud/
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.20.1</center>
</body>
</html>

# ============================================================
# curl -k https://www.jhl.cloud
#   -k:忽略自签名证书不安全警告(生产环境用正规CA证书则不需要)
# ============================================================
[root@nginx-client ~]# curl -k https://www.jhl.cloud
Hello World From Nginx

# ============================================================
# curl -Lk http://www.jhl.cloud
#   -L:跟随301重定向(自动跳转到HTTPS)
#   -k:忽略证书警告
# ============================================================
[root@nginx-client ~]# curl -Lk http://www.jhl.cloud
Hello World From Nginx

实验现象解释

  • 直接访问HTTP返回301跳转页面,说明重定向配置生效;
  • -Lk 后自动跳转到HTTPS并返回页面内容,说明HTTP→HTTPS跳转+HTTPS站点都正常工作。

🔐 第六部分:实验四 配置Basic基本认证

🤔 为什么要做这个实验?运维作用

给网站的特定路径(如后台管理、监控页面)添加用户名密码认证,防止匿名访问。Basic认证用户名密码使用明文传输,所以最好配合SSL/TLS使用

💡 实验思路

  1. 安装httpd-tools(包含htpasswd工具);
  2. 在HTTPS的server块中添加 /auth-basic/ 的location,配置auth_basic;
  3. 使用htpasswd生成密码文件;
  4. 创建测试页面;
  5. 客户端使用 -u 用户名:密码 测试访问。

🔧 操作命令

bash 复制代码
# ============================================================
# yum -y install httpd-tools
#   安装Apache工具包,包含htpasswd密码生成工具
# ============================================================
[root@nginx-server ~]# yum -y install httpd-tools

编辑HTTPS配置文件,在server块中添加location:

nginx 复制代码
server {
    listen          443 ssl http2;
    listen         [::]:443 ssl http2;
    server_name    www.jhl.cloud;
    root           /usr/share/nginx/html;
    ssl_certificate "/etc/ssl/certs/www.jhl.cloud/www.crt";
    ssl_certificate_key "/etc/ssl/certs/www.jhl.cloud/www.key";

    # ============================================================
    # location /auth-basic/:匹配以/auth-basic/开头的路径
    # auth_basic "Basic Auth":开启基本认证,弹窗提示文字为"Basic Auth"
    # auth_basic_user_file:指定密码文件路径
    # ============================================================
    location /auth-basic/ {
        auth_basic             "Basic Auth";
        auth_basic_user_file   "/etc/nginx/.htpasswd";
    }
}

server {
    listen          80;
    listen         [::]:80;
    server_name    www.jhl.cloud;
    root           /usr/share/nginx/html;
    return          301 https://$host$request_uri;
}
bash 复制代码
# 重启Nginx
[root@nginx-server ~]# systemctl restart nginx

# ============================================================
# htpasswd -b -c /etc/nginx/.htpasswd jhl 123456
#   生成密码文件
#   -b:命令行直接传入密码(batch模式,免交互)
#   -c:创建新文件(如果文件已存在会覆盖!)
#   /etc/nginx/.htpasswd:密码文件路径
#   jhl:用户名
#   123456:密码
# ============================================================
[root@nginx-server ~]# htpasswd -b -c /etc/nginx/.htpasswd jhl 123456

# 创建认证页面目录
[root@nginx-server ~]# mkdir /usr/share/nginx/html/auth-basic

# 创建测试页面
[root@nginx-server ~]# vim /usr/share/nginx/html/auth-basic/index.html

测试页面内容:

html 复制代码
<html>
<body>
<div style="width: 100%; font-size: 40px; font-weight: bold; text-align: center;">
Test Page for Basic Authentication
</div>
</body>
</html>

客户端测试

bash 复制代码
# ============================================================
# curl -ku jhl:123456 https://www.jhl.cloud/auth-basic/
#   -k:忽略自签名证书警告
#   -u jhl:123456:指定用户名和密码进行Basic认证
# ============================================================
[root@nginx-client ~]# curl -ku jhl:123456 https://www.jhl.cloud/auth-basic/
<html>
<body>
<div style="width: 100%; font-size: 40px; font-weight: bold; text-align: center;">
Test Page for Basic Authentication
</div>
</body>
</html>

实验现象:带正确用户名密码访问返回测试页面;不带密码或密码错误会返回401 Unauthorized。


🐘 第七部分:实验五 PHP动态站点

🤔 为什么要做这个实验?运维作用

Nginx本身只能处理静态文件,PHP等动态页面需要转发给PHP-FPM处理。这是 动静分离架构 的基础:Nginx处理静态资源(html/css/js/图片),PHP-FPM处理动态PHP代码。

💡 实验思路

  1. 安装php和php-fpm(php-fpm负责接收Web发来的PHP代码,php负责解析执行);
  2. 安装PHP常用扩展(gd、mbstring、mcrypt等);
  3. 启动php-fpm服务(默认监听9000端口);
  4. 准备phpinfo测试页面;
  5. 在Nginx配置中添加 location ~ \.php$,将PHP请求转发给127.0.0.1:9000;
  6. 客户端访问info.php验证PHP解析正常。

🔧 步骤1:安装PHP和PHP-FPM

bash 复制代码
# ============================================================
# yum install -y php php-fpm
#   php:PHP解析器,负责解析和执行PHP代码
#   php-fpm:PHP FastCGI进程管理器,负责接收Web程序发来的PHP代码
#   工作流程:Nginx接收请求 → 转发给php-fpm → php-fpm调用php解析 → 返回结果给Nginx → 返回客户端
# ============================================================
[root@nginx-server ~]# yum install -y php php-fpm

# ============================================================
# systemctl enable php-fpm --now
#   设置php-fpm开机自启并立即启动
#   php-fpm默认监听127.0.0.1:9000
# ============================================================
[root@nginx-server ~]# systemctl enable php-fpm --now

# 安装常用PHP扩展包
[root@nginx-server ~]# yum install -y php-gd php-common php-pear php-mbstring php-mcrypt

🔧 步骤2:测试PHP是否正常

bash 复制代码
# 查看PHP版本
[root@nginx-server ~]# php -v

# 直接运行一段PHP代码
[root@nginx-server ~]# php -r "echo 'Hello PHP';"
Hello PHP

# 运行一个PHP文件
[root@nginx-server ~]# echo "<?php echo 'PHP Test Page'.\"\n\"; ?>" > php_test.php
[root@nginx-server ~]# php php_test.php
PHP Test Page

# 准备phpinfo测试页面(查看PHP详细配置信息)
[root@nginx-server ~]# echo "<?php phpinfo(); ?>" > /usr/share/nginx/html/info.php

🔧 步骤3:配置Nginx支持PHP

编辑HTTPS配置文件,在443的server块中添加PHP的location:

nginx 复制代码
server {
    listen        443 ssl http2;
    listen        [::]:443 ssl http2;
    server_name   www.jhl.cloud;
    root          /usr/share/nginx/html;
    ssl_certificate "/etc/ssl/certs/www.jhl.cloud/www.crt";
    ssl_certificate_key "/etc/ssl/certs/www.jhl.cloud/www.key";

    # ============================================================
    # location ~ \.php$:正则匹配所有以.php结尾的URL
    # ~:大小写敏感正则匹配
    # \.php$:\.转义点号,$表示以.php结尾
    # ============================================================
    location ~ \.php$ {
        # try_files:检测请求的PHP文件($uri)是否存在,不存在直接返回404
        # 安全防护:防止伪造PHP路径的恶意请求(如/xxx.php/yyy.jpg)被PHP-FPM解析
        try_files $uri =404;

        # fastcgi_pass:指定FastCGI服务地址,将PHP请求转发到本地9000端口的PHP-FPM
        fastcgi_pass 127.0.0.1:9000;

        # fastcgi_index:定义FastCGI默认索引文件,请求目录时默认用index.php
        fastcgi_index index.php;

        # fastcgi_param:设置传递给PHP-FPM的核心环境变量
        # SCRIPT_FILENAME:指定要执行的PHP文件绝对路径
        # $document_root是网站根目录,$fastcgi_script_name是请求的脚本名
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        # include:引入Nginx默认的FastCGI参数配置文件
        # 包含QUERY_STRING、REQUEST_METHOD等PHP运行必需的环境变量
        include fastcgi_params;
    }

    location /auth-basic/ {
        auth_basic             "Basic Auth";
        auth_basic_user_file   "/etc/nginx/.htpasswd";
    }
}

server {
    listen          80;
    listen         [::]:80;
    server_name    www.jhl.cloud;
    root           /usr/share/nginx/html;
    return          301 https://$host$request_uri;
}

💡 另一种方式 :也可以将PHP配置分离到独立文件,在server块中用 include /etc/nginx/default.d/*.conf; 引入,和上面的方法二选一。

bash 复制代码
# 方式二:分离配置(可选)
[root@nginx-server ~]# vim /etc/nginx/default.d/php.conf
nginx 复制代码
location ~ \.php$ {
    try_files $uri =404;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}
bash 复制代码
# 配置完成后,务必重启Nginx服务
[root@nginx-server ~]# systemctl restart nginx

🔧 步骤4:客户端测试

bash 复制代码
# Linux客户端通过HTTPS访问info.php
[root@nginx-client ~]# curl -k https://www.jhl.cloud/info.php

实验现象:返回PHP信息页面(大量PHP配置信息),说明Nginx已成功将PHP请求转发给PHP-FPM处理。


🔄 第八部分:反向代理核心原理

🤔 正向代理 vs 反向代理

类型 代理对象 隐藏谁 生活案例
正向代理 代理客户端 隐藏客户端 你让室友帮你买奶茶,奶茶店只知道是室友买的
反向代理 代理服务器 隐藏后端服务器 餐厅前台点餐,你不用管是哪个厨师做的

💡 反向代理定义:代理外网用户的请求到内部指定服务器,并将数据返回给用户。客户端不直接与后端服务器通信,隐藏了后端服务器的IP地址。

🎯 反向代理的主要作用

  1. 负载均衡:将请求分发给多个后端服务器,平衡负载;
  2. 缓存功能:缓存静态文件或动态页面,减轻后端压力;
  3. 动静分离:动态内容和静态资源分别处理;
  4. 多站点代理:代理多个域名,共享端口。

📍 Location匹配规则优先级

优先级 语法 说明
1(最高) location = /path 精确匹配,URL完全一致才命中
2 location ^~ /path 前缀匹配,命中后跳过正则
3 location ~ /regex 大小写敏感正则
4 location ~* /regex 大小写不敏感正则
5 location /path 普通前缀匹配(最长前缀优先)
6(最低) location / 兜底匹配

⚠️ proxy_pass末尾是否带 / 的区别(核心坑点!)

这是Nginx反向代理最容易踩的坑!

场景 proxy_pass写法 转发效果
带 / proxy_pass http://backend/; 剔除location匹配的路径前缀
不带 / proxy_pass http://backend; 保留location匹配的路径前缀

示例 :location匹配 /api/,客户端请求 /api/user/list

nginx 复制代码
# 带/:转发到 http://backend/user/list(剔除了/api/)
location /api/ {
    proxy_pass http://192.168.1.102:9090/;
}

# 不带/:转发到 http://backend/api/user/list(保留了/api/)
location /api/ {
    proxy_pass http://192.168.1.102:9090;
}

🖥️ 第九部分:实验六 反向代理实践(5台机器集群)

🤔 为什么要做这个实验?运维作用

这是企业最常用的架构:前端一台Nginx做反向代理/负载均衡,后端多台Nginx/Web服务器处理业务。客户端只访问代理服务器,后端服务对外不暴露,安全且易扩展。

📋 环境架构

复制代码
                    client.jhl.cloud (10.1.8.11)
                           ↓
                    proxy.jhl.cloud (10.1.8.20)  ← 反向代理/负载均衡
                  ↙          ↓          ↘
        nginx1 (10.1.8.21)  nginx2 (10.1.8.22)  nginx3 (10.1.8.23)  ← 后端Web服务器
主机名 IP地址 服务器角色
client.jhl.cloud 10.1.8.11 测试客户端
proxy.jhl.cloud 10.1.8.20 Nginx代理服务器
nginx1.jhl.cloud 10.1.8.21 Nginx Web服务器1
nginx2.jhl.cloud 10.1.8.22 Nginx Web服务器2
nginx3.jhl.cloud 10.1.8.23 Nginx Web服务器3

💡 完整实验思路

  1. 5台机器配置主机名和静态IP;
  2. 所有节点配置/etc/hosts(域名解析);
  3. proxy、nginx1、nginx2、nginx3安装Nginx并启动;
  4. 三台后端Nginx配置不同首页(用于区分请求落到哪台);
  5. proxy配置反向代理,先做本地静态测试,再做远端代理测试;
  6. 逐步验证location匹配优先级(无符号→正则→精确);
  7. 配置upstream负载均衡,验证轮询/权重/ip_hash等算法。

🔧 步骤1:5台机器基础配置

client

bash 复制代码
[root@localhost ~]# hostnamectl set-hostname client.jhl.cloud
[root@localhost ~]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.11/24 ipv4.gateway 10.1.8.2 ipv4.dns 10.1.8.2 autoconnect yes
[root@localhost ~]# nmcli connection up ens33

proxy

bash 复制代码
[root@localhost ~]# hostnamectl set-hostname proxy.jhl.cloud
[root@localhost ~]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.20/24 ipv4.gateway 10.1.8.2 ipv4.dns 10.1.8.2 autoconnect yes
[root@localhost ~]# nmcli connection up ens33

nginx1

bash 复制代码
[root@localhost ~]# hostnamectl set-hostname nginx1.jhl.cloud
[root@localhost ~]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.21/24 ipv4.gateway 10.1.8.2 ipv4.dns 10.1.8.2 autoconnect yes
[root@localhost ~]# nmcli connection up ens33

nginx2

bash 复制代码
[root@localhost ~]# hostnamectl set-hostname nginx2.jhl.cloud
[root@localhost ~]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.22/24 ipv4.gateway 10.1.8.2 ipv4.dns 10.1.8.2 autoconnect yes
[root@localhost ~]# nmcli connection up ens33

nginx3

bash 复制代码
[root@localhost ~]# hostnamectl set-hostname nginx3.jhl.cloud
[root@localhost ~]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.23/24 ipv4.gateway 10.1.8.2 ipv4.dns 10.1.8.2 autoconnect yes
[root@localhost ~]# nmcli connection up ens33

🔧 步骤2:所有节点配置/etc/hosts

bash 复制代码
# 所有节点都执行
[root@所有节点 ~]# vim /etc/hosts
复制代码
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
############ proxy ##################
10.1.8.11 client.jhl.cloud client
10.1.8.20 www.jhl.cloud www
10.1.8.20 proxy.jhl.cloud proxy
10.1.8.21 nginx1.jhl.cloud nginx1
10.1.8.22 nginx2.jhl.cloud nginx2
10.1.8.23 nginx3.jhl.cloud nginx3

🔧 步骤3:后端Nginx服务器配置(proxy、nginx1、nginx2、nginx3)

bash 复制代码
# 除了客户端,所有节点安装Nginx
[root@proxy,nginx1,nginx2,nginx3 ~]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[root@proxy,nginx1,nginx2,nginx3 ~]# yum -y install nginx

# 启动并启用服务
[root@proxy,nginx1,nginx2,nginx3 ~]# systemctl enable nginx --now

# 防火墙设置(永久+临时)
[root@proxy,nginx1,nginx2,nginx3 ~]# firewall-cmd --add-service=http --permanent
[root@proxy,nginx1,nginx2,nginx3 ~]# firewall-cmd --add-service=http

后端节点准备不同首页(区分请求落到哪台)

bash 复制代码
[root@nginx1 ~]# echo Welcome to $(hostname) > /usr/share/nginx/html/index.html
[root@nginx2 ~]# echo Welcome to $(hostname) > /usr/share/nginx/html/index.html
[root@nginx3 ~]# echo Welcome to $(hostname) > /usr/share/nginx/html/index.html

客户端测试后端节点

bash 复制代码
[root@nginx-client ~]# curl http://nginx1.jhl.cloud/
Welcome to nginx1.jhl.cloud
[root@nginx-client ~]# curl http://nginx2.jhl.cloud/
Welcome to nginx2.jhl.cloud
[root@nginx-client ~]# curl http://nginx3.jhl.cloud/
Welcome to nginx3.jhl.cloud

🔧 步骤4:proxy代理服务器准备本地测试文件

bash 复制代码
# 准备代理节点主页
[root@proxy ~]# echo Welcome to www.jhl.cloud > /usr/share/nginx/html/index.html

# 创建本地测试目录
[root@proxy ~]# mkdir /var/nginx
[root@proxy ~]# echo "Hello, Nginx" > /var/nginx/index.html
[root@proxy ~]# echo "Hello, jhl" > /var/nginx/test.txt
[root@proxy ~]# cp /usr/share/nginx/html/nginx-logo.png /var/nginx/
[root@proxy ~]# ls /var/nginx/
index.html   nginx-logo.png   test.txt

配置proxy基础配置

bash 复制代码
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
nginx 复制代码
server {
    listen     80;
    server_name www.jhl.cloud;
    # 匹配根位置
    location / {
        root /var/nginx;       # 网站根目录
        index index.html;      # 默认首页
    }
}
bash 复制代码
# 重新加载Nginx配置(热重载,不中断服务)
[root@proxy ~]# nginx -s reload

测试本地静态站点

bash 复制代码
[root@nginx-client ~]# curl http://www.jhl.cloud/
Hello, Nginx
[root@nginx-client ~]# curl http://www.jhl.cloud/test.txt
Hello, jhl

🤔 思考题 :如果在Nginx目录中创建一个 test.nn 文件,通过 www.jhl.cloud/test.nn 访问时,系统是否会返回对应文件内容?

:不可以。因为"nn"类型的文件不在mime.type中,Nginx无法对该文件进行解析,此时会将文件下载到本地。


🔧 步骤5:反向代理基础实践------代理本地(验证location优先级)

准备测试目录结构

bash 复制代码
# 创建/var/nginx下的子目录
[root@proxy ~]# mkdir /var/nginx/nginx{1,2}
[root@proxy ~]# echo "Hello, I'm here /var/nginx/nginx1" > /var/nginx/nginx1/index.html
[root@proxy ~]# echo "Hello, I'm here /var/nginx/nginx2" > /var/nginx/nginx2/index.html

# 创建/var下的独立目录(用于root /var 测试)
[root@proxy ~]# mkdir /var/nginx{1,2}
[root@proxy ~]# echo "Hello, Nginx1" > /var/nginx1/index.html
[root@proxy ~]# echo "Hello, Nginx2" > /var/nginx2/index.html

# 查看目录结构
[root@proxy ~]# tree /var/nginx*
/var/nginx
├── index.html                 # Hello,Nginx
├── nginx1
│   └── index.html             # Hello, I'm here /var/nginx/nginx1
├── nginx2
│   └── index.html             # Hello, I'm here /var/nginx/nginx2
├── nginx-logo.png
└── test.txt                   # Hello,jhl
/var/nginx1
└── index.html                 # Hello, Nginx1
/var/nginx2
└── index.html                 # Hello, Nginx2
bash 复制代码
# 创建www1/www2测试目录(用于正则/精确匹配测试)
[root@proxy ~]# for path1 in www{1..2}
do
     for path2 in nginx{1..2}
     do
       mkdir -p /var/$path1/$path2
       echo "Hello, I'm here /var/$path1/$path2" > /var/$path1/$path2/index.html
     done
done

[root@proxy ~]# tree /var/www*
/var/www1
├── nginx1
│     └── index.html           # Hello, I'm here /var/www1/nginx1
└── nginx2
      └── index.html           # Hello, I'm here /var/www1/nginx2
/var/www2
├── nginx1
│     └── index.html           # Hello, I'm here /var/www2/nginx1
└── nginx2
      └── index.html           # Hello, I'm here /var/www2/nginx2

基础测试(验证默认/匹配)

bash 复制代码
[root@nginx-client ~]# curl http://www.jhl.cloud/
Hello, Nginx

# 显示结果是目录/var/nginx/nginx1中内容
[root@nginx-client ~]# curl http://www.jhl.cloud/nginx1/
Hello, I'm here /var/nginx/nginx1

# 显示结果是目录/var/nginx/nginx2中内容
[root@nginx-client ~]# curl http://www.jhl.cloud/nginx2/
Hello, I'm here /var/nginx/nginx2

实践1:无符号匹配(普通前缀匹配)

💡 root拼接规则:root + URI原始请求路径

bash 复制代码
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
nginx 复制代码
server {
    listen   80;
    server_name www.jhl.cloud;
    # 匹配根位置(兜底)
    location / {
        root /var/nginx;
        index index.html;
    }
    # 匹配/nginx1时,root /var 表示在/var目录下找nginx1
    # 完整路径是 /var + /nginx1 = /var/nginx1
    location /nginx1 {
        root /var;
        # 等效于下面的 alias 语句,必须使用绝对路径
        # alias /var/nginx1;
        index index.html;
    }
}
bash 复制代码
[root@proxy ~]# nginx -s reload
bash 复制代码
# nginx1后面必须添加 / 符号
[root@nginx-client ~]# curl http://www.jhl.cloud/nginx1/
Hello, Nginx1
# 显示结果是目录/var/nginx1中内容(因为root /var + /nginx1 = /var/nginx1)

# nginx2没有匹配的location,走兜底/,root /var/nginx + /nginx2 = /var/nginx/nginx2
[root@nginx-client ~]# curl http://www.jhl.cloud/nginx2/
Hello, I'm here /var/nginx/nginx2
# 显示结果是目录/var/nginx/nginx2中内容

实验结果 :无符号匹配(普通前缀)优先级高于默认的 /


实践2:正则表达式匹配

bash 复制代码
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
nginx 复制代码
server {
    listen    80;
    server_name www.jhl.cloud;
    location / {
        root /var/nginx;
        index index.html;
    }
    location /nginx1 {
        root /var;
        index index.html;
    }
    # 正则表达式匹配 /nginx.* (~表示大小写敏感)
    # 匹配 /nginx1、/nginx2、/nginxxxx 等
    location ~ /nginx.* {
        root /var/www1;
        index index.html;
    }
}
bash 复制代码
[root@proxy ~]# nginx -s reload
bash 复制代码
[root@nginx-client ~]# curl http://www.jhl.cloud/nginx1/
Hello, I'm here /var/www1/nginx1
# 显示结果是目录/var/www1/nginx1中内容(正则匹配优先级高于无符号)

[root@nginx-client ~]# curl http://www.jhl.cloud/nginx2/
Hello, I'm here /var/www1/nginx2
# 显示结果是目录/var/www1/nginx2中内容

实验结果:正则表达式匹配优先级高于无符号(普通前缀)匹配。


实践3:精确匹配

bash 复制代码
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
nginx 复制代码
server {
    listen    80;
    server_name www.jhl.cloud;
    location / {
        root /var/nginx;
        index index.html;
    }
    location /nginx1 {
        root /var;
        index index.html;
    }
    location ~ /nginx.* {
        root /var/www1;
        index index.html;
    }
    # 精确匹配 = /nginx2/index.html(优先级最高)
    location = /nginx2/index.html {
        root /var/www2;
        index index.html;
    }
}
bash 复制代码
[root@proxy ~]# nginx -s reload
bash 复制代码
[root@nginx-client ~]# curl http://www.jhl.cloud/nginx1/
Hello, I'm here /var/www1/nginx1
# 走正则匹配,/var/www1/nginx1

[root@nginx-client ~]# curl http://www.jhl.cloud/nginx2/
Hello, I'm here /var/www2/nginx2
# 精确匹配命中,/var/www2/nginx2

实验结果 :精确匹配(=)优先级高于正则表达式匹配。

🎯 优先级总结 :精确匹配(=) > 正则匹配(~/~*) > 普通前缀匹配(无符号) > 兜底(/)


🔧 步骤6:反向代理基础实践------代理远端

实践1:无符号匹配(代理到远端nginx1)

bash 复制代码
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
nginx 复制代码
server {
    listen     80;
    server_name www.jhl.cloud;
    location / {
        root /var/nginx;
        index index.html;
    }
    # 匹配 /nginx1/ 开头,代理到nginx1.jhl.cloud
    # proxy_pass末尾带 /,/nginx1/ 不组合到后端服务器
    # 访问 /nginx1/ 相当于直接访问 http://nginx1.jhl.cloud/
    location /nginx1/ {
        proxy_pass http://nginx1.jhl.cloud/;  # 注意:代理后端后面有 /
        index index.html;
    }
}
bash 复制代码
[root@proxy ~]# nginx -s reload
bash 复制代码
[root@nginx-client ~]# curl http://www.jhl.cloud/nginx1/
Welcome to nginx1.jhl.cloud
# 显示结果是服务器 nginx1.jhl.cloud 内容(代理远端成功)

[root@nginx-client ~]# curl http://www.jhl.cloud/nginx2/
Hello, I'm here /var/nginx/nginx2
# nginx2没有匹配location,走本地兜底/

实验结果 :无符号匹配优先级高于默认的 /,请求被代理到远端nginx1。


实践2:正则表达式匹配(代理到远端nginx2)

bash 复制代码
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
nginx 复制代码
server {
    listen     80;
    server_name www.jhl.cloud;
    location / {
        root /var/nginx;
        index index.html;
    }
    location /nginx1/ {
        proxy_pass http://nginx1.jhl.cloud/;
        index index.html;
    }
    # 正则匹配 /nginx[12].* (匹配nginx1或nginx2开头)
    location ~ /nginx[12].* {
        # rewrite:手动重写路径,去掉 /nginx 前缀
        # ^/nginx[12](.*)$:匹配/nginx[12]开头的完整路径,$1表示后面的所有内容
        # break:重写后不再匹配其他rewrite规则
        rewrite ^/nginx[12](.*)$ $1 break;
        # proxy_pass不带URI(无末尾的/),配合rewrite实现路径替换
        proxy_pass http://nginx2.jhl.cloud;
        index index.html;
    }
}
bash 复制代码
[root@proxy ~]# nginx -s reload
bash 复制代码
[root@nginx-client ~]# curl http://www.jhl.cloud/nginx1/
Welcome to nginx2.jhl.cloud
# 正则匹配优先级更高,被代理到nginx2

[root@nginx-client ~]# curl http://www.jhl.cloud/nginx2/
Welcome to nginx2.jhl.cloud
# 同样被正则匹配,代理到nginx2

实验结果:正则表达式匹配优先级高于无符号匹配。


实践3:精确匹配(代理到远端nginx1)

bash 复制代码
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
nginx 复制代码
server {
    listen     80;
    server_name www.jhl.cloud;
    location / {
        root /var/nginx;
        index index.html;
    }
    location /nginx1/ {
        proxy_pass http://nginx1.jhl.cloud/;
        index index.html;
    }
    location ~ /nginx[12].* {
        rewrite ^/nginx[12](.*)$ $1 break;
        proxy_pass http://nginx2.jhl.cloud;
        index index.html;
    }
    # 精确匹配 = /nginx1/(优先级最高)
    location = /nginx1/ {
        proxy_pass http://nginx1.jhl.cloud/;
        index index.html;
    }
}
bash 复制代码
[root@proxy ~]# nginx -s reload
bash 复制代码
[root@nginx-client ~]# curl http://www.jhl.cloud/nginx1/
Welcome to nginx1.jhl.cloud
# 精确匹配命中,代理到nginx1

[root@nginx-client ~]# curl http://www.jhl.cloud/nginx2/
Welcome to nginx2.jhl.cloud
# 正则匹配命中,代理到nginx2

实验结果:精确匹配优先级高于正则表达式匹配。


⚖️ 第十部分:实验七 七层负载均衡(upstream)

🤔 为什么要做这个实验?运维作用

单台后端服务器性能有限,高并发时会成为瓶颈。通过Nginx的upstream模块将流量分发到多台后端服务器,实现集群扩容、故障自动摘除。这是企业高并发网站的标配架构。

💡 实验思路

  1. 在proxy上配置upstream块,定义后端服务器池(nginx1、nginx2、nginx3);
  2. location中用proxy_pass指向upstream名称;
  3. 分别测试不同调度算法:轮询、权重、ip_hash、通用哈希、最少连接;
  4. 用for循环批量请求,统计各后端被访问的次数。

🔧 步骤1:配置七层负载均衡

bash 复制代码
[root@proxy ~]# vim /etc/nginx/conf.d/proxy.conf
nginx 复制代码
server {
    listen     80;
    server_name www.jhl.cloud;
    location / {
        proxy_pass http://backends/;  # 转发到upstream集群
    }
}

# upstream定义后端服务器池
upstream backends {
    server nginx1.jhl.cloud:80;
    server nginx2.jhl.cloud:80;
    server nginx3.jhl.cloud:80;
}
bash 复制代码
[root@proxy ~]# nginx -s reload

# 防火墙设置
[root@proxy ~]# firewall-cmd --add-service=http --permanent
[root@proxy ~]# firewall-cmd --add-service=http

测试轮询(默认算法)

bash 复制代码
# ============================================================
# for n in {1..90}; do curl http://www.jhl.cloud -s; done | sort | uniq -c
#   循环90次请求,排序后统计每个结果出现次数
#   -s:静默模式,不输出进度信息
#   sort | uniq -c:排序并统计每行出现次数
# ============================================================
[root@client ~]# for n in {1..90}; do curl http://www.jhl.cloud -s; done | sort | uniq -c
      30 Welcome to nginx1.jhl.cloud
      30 Welcome to nginx2.jhl.cloud
      30 Welcome to nginx3.jhl.cloud

实验现象:90次请求平均分配到3台后端,每台30次,轮询算法正常工作。


📊 upstream模块详解

upstream语法

nginx 复制代码
upstream name {
    server address [parameters];
}

server指令常用参数

参数 说明 默认值
weight=N 权重,数值越大分到请求越多 1
max_fails=N 最大失败连接次数 1
fail_timeout=时间 失败后暂停服务的时长 10s
backup 备份节点,其他全部故障才启用 -
down 手动标记下线,不处理请求 -

示例

nginx 复制代码
upstream backends {
    keepalive 32;  # 每个worker进程缓存到upstream的连接数
    server nginx1.jhl.cloud:80 max_fails=3 fail_timeout=30s;
    server nginx2.jhl.cloud:80 max_fails=3 fail_timeout=30s weight=2;
    server nginx3.jhl.cloud:80 max_fails=3 fail_timeout=30s backup;
    server nginx4.jhl.cloud:80 max_fails=3 fail_timeout=30s down;
}

🔧 步骤2:六大调度算法详解与测试

算法1:轮询(round-robin,默认)

按客户端请求顺序逐一分配到不同后端。后端宕机自动剔除。

nginx 复制代码
upstream backends {
    server nginx1.jhl.cloud:80;
    server nginx2.jhl.cloud:80;
    server nginx3.jhl.cloud:80;
}
bash 复制代码
[root@client ~]# for i in {1..60}; do curl http://www.jhl.cloud -s; done | sort | uniq -c
      20 Welcome to nginx1.jhl.cloud
      20 Welcome to nginx2.jhl.cloud
      20 Welcome to nginx3.jhl.cloud

算法2:权重(weight)

在轮询基础上加权重,权重和访问量成正比。解决新旧服务器性能不均问题。

nginx 复制代码
upstream backends {
    server nginx1.jhl.cloud:80 weight=10;
    server nginx2.jhl.cloud:80 weight=20;
    server nginx3.jhl.cloud:80 weight=30;
}
bash 复制代码
[root@proxy ~]# nginx -s reload
[root@client ~]# for i in {1..60}; do curl http://www.jhl.cloud -s; done | sort | uniq -c
      10 Welcome to nginx1.jhl.cloud
      20 Welcome to nginx2.jhl.cloud
      30 Welcome to nginx3.jhl.cloud

实验现象:60次请求按1:2:3分配,权重越高分到请求越多。

算法3:IP哈希(ip_hash)

每个请求按客户端IP的哈希结果分配。同一客户端IP永远落到同一台后端,解决session会话共享问题。

nginx 复制代码
upstream backends {
    ip_hash;
    server nginx1.jhl.cloud:80;
    server nginx2.jhl.cloud:80;
    server nginx3.jhl.cloud:80;
}
bash 复制代码
[root@proxy ~]# nginx -s reload
[root@client ~]# for i in {1..60}; do curl http://www.jhl.cloud -s; done | sort | uniq -c
      60 Welcome to nginx2.jhl.cloud

实验现象:60次请求全部落到同一台后端(因为客户端IP固定,哈希结果相同)。

⚠️ 注意:国内大多数公司是NAT上网,多个客户端对应一个外部IP,会导致请求分配不均。ip_hash模式下weight参数无效,也不支持backup节点。

算法4:通用哈希(generic hash)

请求发送到的服务器由用户定义的键确定,可以是文本字符串、变量或组合(如URI、cookie、header)。

nginx 复制代码
upstream backends {
    hash $request_uri;      # 按请求URI哈希
    #hash_method crc32;     # 哈希算法(Nginx不支持url_hash,需安装hash模块)
    server nginx1.jhl.cloud:80;
    server nginx2.jhl.cloud:80;
    server nginx3.jhl.cloud:80;
}
bash 复制代码
[root@proxy ~]# nginx -s reload
[root@client ~]# for i in {1..60}; do curl http://www.jhl.cloud -s; done | sort | uniq -c
      60 Welcome to nginx3.jhl.cloud

实验现象 :同一URI哈希结果固定,全部落到同一台后端。加 consistent 参数可开启一致性哈希,后端上下线时流量抖动更小。

算法5:最少连接数(least_conn)

将请求分发给当前活跃连接数最少的后端。适合后端处理请求耗时差异大、长连接场景。

nginx 复制代码
upstream backends {
    least_conn;
    server nginx1.jhl.cloud:80;
    server nginx2.jhl.cloud:80;
    server nginx3.jhl.cloud:80;
}
bash 复制代码
[root@proxy ~]# nginx -s reload
[root@client ~]# for i in {1..60}; do curl http://www.jhl.cloud -s; done | sort | uniq -c
      20 Welcome to nginx1.jhl.cloud
      20 Welcome to nginx2.jhl.cloud
      20 Welcome to nginx3.jhl.cloud

实验现象:测试环境下后端响应快,连接数都差不多,所以平均分配。生产环境长连接场景下差异明显。least_conn也支持weight权重。

算法6:最少时间(least_time,仅限Nginx Plus商业版)

分配给响应时间最短的后端。开源Nginx没有此功能。

nginx 复制代码
upstream backends {
    least_time header;  # header:接收第一个字节的时间;last_byte:接收完整响应时间
    server nginx1.jhl.cloud:80;
    server nginx2.jhl.cloud:80;
    server nginx3.jhl.cloud:80;
}

📋 六大调度算法总结表

算法 配置写法 核心逻辑 使用场景 特点
轮询round-robin(默认) 不写任何策略 请求依次分配给后端 后端性能差不多,无会话保持需求 默认策略,故障自动剔除,不做会话绑定
权重weight server x weight=N; 按权重比例分配流量 后端机器性能不一样,性能好的多承担 权重越大分到请求越多;仅轮询模式生效;ip_hash模式weight无效
ip_hash ip_hash; 根据客户端TCP源IP哈希,同一IP永远落到同一台 需要会话保持,无前置代理 基于TCP源IP,不读HTTP头;前面有SLB/CDN会全部打到同一台;不支持backup节点
通用哈希generic hash hash $变量 [consistent]; 自定义变量做哈希(ip/cookie/header/url等) 需要基于cookie、url做会话绑定;前置代理环境 Nginx1.7.2+;加consistent开启一致性哈希,后端上下线流量抖动变小
最少连接least_conn least_conn; 把请求分给当前活跃连接数最少的后端 后端处理请求耗时差异大,长连接场景 优先找连接数少的机器;weight权重仍然生效
最少时间least_time least_time header; 分配给响应时间最短的后端 Nginx Plus商业版,根据历史响应速度 开源Nginx没有,根据后端历史响应速度择优分配

🎯 快速记忆口诀

  • 轮询:挨个来(默认)
  • weight:能力强多干活
  • ip_hash:同一个IP锁一台后端(TCP源IP)
  • hash:想拿什么就哈希什么(cookie/header/url),consistent保稳定
  • least_conn:谁闲分给谁(看活跃连接)
  • least_time:谁响应快分给谁(商业版)

🐛 第十一部分:Nginx常见问题与日志

📋 Nginx常见日志

1. access.log(访问日志)

记录每一次HTTP请求。

nginx 复制代码
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;
字段 含义
$remote_addr 客户端IP
$remote_user 远程用户(Basic认证时)
$time_local 访问时间
$request 请求行(方法+URI+协议)
$status 响应状态码
$body_bytes_sent 响应体字节数
$http_referer 来源页面
$http_user_agent 浏览器UA
$http_x_forwarded_for 代理IP链

2. error.log(错误日志)

502、配置错误、连接失败都在这里排查。

bash 复制代码
# 实时查看错误日志
tail -f /var/log/nginx/error.log

🚨 生产常见问题

问题 原因
502 Bad Gateway Nginx无法连接后端服务,后端挂了、端口不对、防火墙拦截
504 Gateway Timeout 后端处理请求太慢,代理超时
499 客户端主动断开连接
403 Forbidden 权限不足、目录不存在、没有index文件
并发上不去 检查worker_processes、worker_connections、系统文件句柄数ulimit

📝 文末总结

🎯 核心知识点回顾

模块 核心要点
Nginx架构 master-worker多进程,异步非阻塞IO,热重载不中断服务
配置结构 全局块→events→http→server→location,五层嵌套
location优先级 精确(=) > 前缀(^~) > 正则(~/~*) > 普通前缀 > 兜底(/)
虚拟主机 基于域名(最常用)、基于端口、基于IP
HTTPS openssl生成证书,443端口配置ssl_certificate/key,80端口301跳转
PHP站点 php-fpm监听9000,location ~ .php$ 用fastcgi_pass转发
反向代理 proxy_pass末尾带/剔除前缀,不带/保留前缀;必加proxy_set_header传真实IP
负载均衡 upstream定义后端池,六大算法:轮询/权重/ip_hash/hash/least_conn/least_time

💡 生产环境最佳实践

  1. 改配置必校验nginx -t 检查语法,没问题再 nginx -s reload
  2. 热重载不重启:更新配置用reload,不要restart,避免业务中断;
  3. 代理必传真实IPproxy_set_header X-Real-IP $remote_addr; 否则后端日志全是代理IP;
  4. upstream加健康检查max_failsfail_timeout 配置故障自动摘除;
  5. 日志分割:access.log和error.log要做logrotate轮转,避免占满磁盘;
  6. 静态资源缓存:图片、CSS、JS配置expires缓存,减轻后端压力。

💬 互动话题

你们线上Nginx用的什么负载均衡算法?反向代理踩过proxy_pass斜杠的坑吗?

欢迎在评论区交流~

如果这篇文章对你有帮助,别忘了 点赞👍 收藏⭐ 关注👀 三连支持!

我们下篇文章见~拜拜!👋


相关推荐
Rsingstarzengjx1 小时前
stm32m157 U-boot 测试
linux·运维·服务器
ShineWinsu2 小时前
对于C++:缓冲区管理的详细解析
linux·c++·面试·编程·笔试·io·缓冲区
张小姐的猫3 小时前
【Linux】网络编程 —— 传输层协议 TCP(下)
linux·运维·服务器·网络·tcp/ip·http·php
程序员AlbertTu3 小时前
第2章 上手 Linux:环境与文件操作
linux·运维·服务器
☆凡尘清心☆4 小时前
CentOS Stream 9 源码编译搭建 Zabbix7.0.29 完整部署方案(部署成功)
linux·运维·centos
Escalating_xu4 小时前
【Linux】进程间通信:从匿名管道、FIFO 到共享内存、消息队列与信号量
java·linux·面试
予昊4 小时前
Linux 资源控制实战分析:用 LXC 亲手造一个 “迷你虚拟机“
linux·运维·服务器
allforgood4 小时前
管理网络安全
linux
灵晔君4 小时前
【Linux】进程控制(一)——进程创建、进程终止与进程等待
linux·c语言·算法