Nginx 性能优化之三大法宝
动静分离
Web应用中的资源可分为两类:
☆ 动态内容
需后端程序实时生成的数据(如PHP/Java接口返回的JSON、用户登录状态页),通常由应用服务器(如Tomcat、Node.js)处理。
☆ 静态内容
无需后端计算、可直接返回的文件(如图片、CSS/JS、字体文件),由Nginx直接高效处理。
经典配置
server {
listen 80;
server_name example.com;
# 动态请求:转发到后端应用服务器(如Tomcat/Node.js)
location /api/ {
proxy_pass http://backend_server:8080/; # 指向后端服务地址
proxy_set_header Host $host; # 传递原始请求头
}
# 静态资源:直接由Nginx从本地目录返回
location ~* \.(jpg|jpeg|png|gif|css|js|woff|woff2|ico)$ {
root /var/www/static; # 静态资源存放目录
expires 30d; # 缓存30天(可选优化)
}
# 默认动态请求(如PHP/HTML模板)
location / {
proxy_pass http://app_server:3000/; # 指向应用服务器
}
}
客户端缓存
告知浏览器获取的信息是在某个区间时间段是有效的,基本格式:
expires 30s; //表示把数据缓存30秒 expires 30m; //表示把数据缓存30分 expires 10h; //表示把数据缓存10小时 expires 3d; //表示把数据缓存3天
禁止缓存配置说明
add_header Cache-Control no-store;
案例:缓存图片/js/css文件,缓存时间为1天
location ~* \.(jpg|jpeg|gif|png|js|css)$ {
expires 1d;
#add_header Cache-Control no-store;
}
开启 Gzip 压缩
压缩文件大小变小了,传输更快了,目前市场上大部分浏览器是支持GZIP的。
IE6以下支持不好,会出现乱码情况。
http://nginx.org/en/docs/http/ngx_http_gzip_module.html
gzip on; # 第1行:开启Gzip压缩功能
gzip_min_length 1k; # 第2行:仅压缩大于1KB的文件(小于1KB的压缩后可能更大,不处理)
gzip_buffers 4 16k; # 第3行:压缩时使用的缓冲区数量(4个)和大小(每个16KB)
gzip_http_version 1.1; # 第4行:兼容HTTP/1.1协议(主流浏览器均支持)
gzip_comp_level 5; # 第5行:压缩级别(1-10),数字越大压缩率越高但CPU消耗越大(推荐5~6)
gzip_types text/plain
text/css
text/javascript
application/javascript
application/x-javascript
image/jpeg
image/gif
image/png
image/x-ms-bmp; # 第6行:指定要压缩的文件类型(优先压缩文本和图片)
gzip_vary on; # 第7行:在响应头中添加Vary: Accept-Encoding,帮助缓存服务器区分压缩/未压缩版本
gzip_disable "MSIE [1-6]\."; # 第8行:禁用对IE6及以下版本的Gzip(兼容性问题)
vary 是差异,多样化的意思。
gzip_vary 是 Nginx 配置中的一条指令,它用于控制是否在响应头中设置 Vary: Accept-Encoding 头部。具体来说:
gzip_vary on;:启用时,Nginx 会在响应头中加入 Vary: Accept-Encoding,表示不同的客户端可能会根据是否支持 gzip 压缩来收到不同的响应内容。这有助于缓存服务器(如 CDN)缓存压缩和未压缩的内容。
gzip_vary off;:禁用时,Nginx 不会在响应头中加入 Vary: Accept-Encoding,这意味着缓存服务器不会区分压缩与未压缩的内容。这样做通常会减少缓存的复杂性,但可能会导致某些情况缓存不一致。
| 指令 | 作用 | 推荐值/说明 |
| gzip on; | 开关Gzip功能 | 必须为 on才生效 |
| gzip_min_length 1k; | 最小压缩文件大小 | 避免小文件压缩后体积反而增大(默认20B~1k,建议1k~10k) |
| gzip_buffers 4 16k; | 压缩缓冲区配置 | 4个16KB的缓冲区(根据服务器内存调整) |
| gzip_http_version 1.1; | 兼容的HTTP协议版本 | 现代浏览器均支持1.1 |
| gzip_comp_level 5; | 压缩级别 | 1(最快但压缩率低)~10(最慢但压缩率高),推荐5~6平衡性能与效果 |
| gzip_types | 指定压缩的文件MIME类型 | 优先压缩文本(如HTML/CSS/JS)、常用图片(如JPEG/PNG) |
| gzip_vary on; | 是否添加Vary头 | 帮助CDN/代理服务器正确缓存压缩与未压缩版本 |
| gzip_disable "MSIE [1-6]\."; | 禁用低版本IE的Gzip | IE6对Gzip支持差,可能引发乱码 |
常见压缩类型:
文本类(.html/.css/.js)
矢量图(.svg)
部分图片(.png/.jpg,但已压缩的图片效果有限)
总结
| 优化方向 | 核心目标 | 关键技术 | 适用场景 |
| 动静分离 | 提升资源处理效率,降低后端压力 | Nginx路由分离(动态→后端,静态→本地/CDN) | 所有Web应用(尤其是高并发场景) |
| 客户端缓存 | 减少重复传输,加速二次访问 | expires/Cache-Control控制缓存时间 | 图片、CSS/JS等长期不变的静态资源 |
| Gzip压缩 | 减小传输体积,降低带宽消耗 | gzip模块压缩文本/图片 | 文本类资源(HTML/CSS/JS)、未高度压缩的图片 |
Nginx 日志分析
日志分类
| 日志类型 | 默认文件名 | 核心记录内容 | 默认存储路径(不同安装方式) |
| 访问日志 | access.log |
1、$remote_addr $upstream_status $request_time等变量组合(格式可自定义) 2、查看统计用户的访问信息与流量 |
源码安装:/usr/local/nginx/logs yum/dnf/apt 安装:/var/log/nginx |
| 错误日志 | error.log |
1、配置语法错误、进程异常、连接超时等信息,含行号与错误码(如[emerg] bind() failed) 2、错误信息以及重写信息 |
同上 |
access 访问日志
cat /var/log/nginx/access.log 或者 cat /usr/local/nginx/logs/access.log
日志参数详解
|
参数 |
意义 |
|
$remote_addr |
客户端的ip地址(代理服务器,显示代理服务ip) |
|
$remote_user |
用于记录远程客户端的用户名称(一般为“-”) |
|
$time_local |
用于记录访问时间和时区 |
|
$request |
用于记录请求的url以及请求方法 |
|
$status |
响应状态码,例如:200成功、404页面找不到等 |
|
$body_bytes_sent |
给客户端发送的文件主体内容字节数 |
|
$http_referer |
可以记录用户是从哪个链接访问过来的 |
|
$http_user_agent |
用户所使用的代理(一般为浏览器) |
|
$http_xforwarded_for |
可以记录客户端IP,通过代理服务器来记录客户端的IP地址 |
设置access.log访问日志输出格式与文件路径:
vim /etc/nginx/nginx.conf 或者 vim /usr/local/nginx/conf/nginx.conf
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;
配置完成后,重载Nginx,访问站点,查看access.log日志,可以统计分析用户的流量的相关情况。
nginx -s reload
error 错误日志
作用:用于Nginx排错
error.log,默认记录配置启动错误信息和访问请求错误信息。
cat /var/log/nginx/error.log 或者 cat /usr/local/nginx/logs/error.log
配置error_log:
vim /etc/nginx/nginx.conf 或者 vim /usr/local/nginx/conf/nginx.conf
在配置nginx.conf 的时候,有一项是指定错误日志的,默认情况下你不指定也没有关系。
但有时出现问题时,是有必要记录一下错误日志的,方便我们排查问题。
参考地址:https://nginx.org/en/docs/ngx_core_module.html#error_log
error_log 级别分为 debug, info, notice, warn, error, crit(从低到高)。
| 级别 | 含义 | 适用场景 |
| debug | 调试信息(最详细) | 开发/排查复杂问题 |
| info | 一般性事件记录 | 跟踪运行状态 |
| notice | 重要但非错误事件 | 生产环境常规监控 |
| warn | 警告事件(不影响服务) | 潜在问题预警 |
| error | 默认级别,错误事件 | 服务异常排查 |
| crit | Critical,严重错误 | 紧急问题(如权限拒绝) |
如果配置 error,会怎么样呢?
Nginx 只会记录 error级别及以上(即 error和 crit)的日志,而更低级别的日志(如 warn、notice、info、debug)将被忽略。
举例如下
cat /var/log/nginx/error.log 或者 cat /usr/local/nginx/logs/error.log
注意:
crit 记录的日志最少,而debug记录的日志最多。
有些模块突破了默认的error级别限制,也会记录一些日志,比如进程启动的一些notice通知。
小结:
错误日志的作用:用来查看错误信息,通过提示的错误信息,排除错误。
GoAccess 轻量级日志分析
作用:针对Apache/Nginx访问日志进行分析,优点:轻量级、开源、带图形化界面!
什么是GoAccess?
GoAccess 是一款开源的且具有交互视图界面的 实时 Web 日志分析工具,通过你的 Web 浏览器或者 Linux 系统下的 终端程序 即可访问。
能为系统管理员提供快速且有价值的 HTTP 统计,并以在线可视化服务器的方式呈现。
安装GoAccess:
安装 GoAccess dnf install goaccess -y 如果安装GoAccess不成功,可以先完善一下 EPEL 仓库 安装 EPEL 仓库(Extra Packages for Enterprise Linux) dnf install epel-release -y
说明:
EPEL 是 RedHat/CentOS 官方维护的扩展软件源,提供大量常用但非默认包含的工具(如 GoAccess、htop 等)。
Nginx 默认访问日志通常位于
/usr/local/nginx/logs/access.log(若编译安装时未修改路径)
或
/var/log/nginx/access.log(若通过包管理器安装)
本例以 Nginx 源码编译安装到 /usr/local/nginx/ 为例
cd /usr/local/nginx/
注意:GoAccess分析的结果往往是一个html网页,如果想直接预览,建议直接把内容放置于Nginx访问目录
① 离线分析
离线分析,会生成静态 HTML 报告(推荐生产环境)
通过以下命令对访问日志进行分析,并将结果输出为 HTML 文件(便于通过浏览器查看)
goaccess -f /usr/local/nginx/logs/access.log --log-format=COMBINED > /usr/local/nginx/html/itheimadevops/report.html
或者
goaccess -f /usr/local/nginx/logs/access.log --log-format=COMBINED > report.html
或者
goaccess -f /var/log/nginx/access.log --log-format=COMBINED > report.html
-f:指定文件
--log-format:分析的文件格式
COMBINED代表组合日志格式(XLF/ELF) Apache | Nginx
COMMON代表通用日志格式(CLF) Apache
Nginx server 配置参考:
vi /usr/local/nginx/conf/nginx.conf
...
server {
# 监听端口
listen 80;
# 配置域名
server_name www.itheimadevops.com;
# 配置目录
root html/itheimadevops;
access_log logs/www.itheimadevops.com.access.log main;
error_log logs/www.itheimadevops.com.error.log;
# 配置uri匹配规则
location / {
index index.html index.htm;
}
location ~ \.(jpg|jpeg|gif|png|js|css)$ {
add_header Cache-Control no-store;
}
}
...
查看 report.html
goaccess -f /var/log/nginx/access.log --log-format=COMBINED > report.html ls -hl report.html goaccess -f /usr/local/nginx/logs/access.log --log-format=COMBINED > report.html ls -hl report.html
-
server1(dnf 版 Nginx)日志路径:
/var/log/nginx/access.log -
server2(源码版 Nginx)日志路径:
/usr/local/nginx/logs/access.log -
作用:用 goaccess 解析 Nginx 访问日志,生成可视化报表
report.html
② 实时分析
除生成静态 HTML 外,GoAccess 还支持 终端实时动态展示(适合快速排查问题)
goaccess /usr/local/nginx/logs/access.log \ --no-global-config \ --log-format='%h %^ %^ [%d:%t %^] "%r" %s %b "%R" "%u"' \ --date-format='%d/%b/%Y' \ --time-format='%H:%M:%S' 或者 goaccess /var/log/nginx/access.log \ --no-global-config \ --log-format='%h %^ %^ [%d:%t %^] "%r" %s %b "%R" "%u"' \ --date-format='%d/%b/%Y' \ --time-format='%H:%M:%S'
更多参考:https://www.goaccess.cc/?mod=man
Nginx 企业级日志分析实战经典案例
GoAccess 不仅能生成基础的可视化报告,更能通过灵活的命令行参数与日志分析,帮助企业快速定位关键问题(如高频攻击 IP、异常 404 请求、热门业务路径)。
本章聚焦三大典型企业级场景,结合实战命令与结果解读,助你掌握日志分析的“进阶用法”。
统计访问量最高的IP地址
在生成日志分析报告时,GoAccess 默认会统计并展示 “Top IPs”(访问量最高的 IP 地址列表)。
☆ 场景背景
企业的 Web 服务可能面临两类与 IP 相关的风险:
- 正常高频访问:如内部员工频繁调用 API、爬虫程序抓取公开数据(需评估是否合理)。
- 恶意行为:如 DDoS 攻击(大量 IP 短时间内发起请求)、暴力破解(针对登录接口的重复尝试)、爬虫违规采集(超出正常频率)。
通过统计访问量最高的 IP,可以快速锁定 “谁在频繁访问我的服务”,进而判断是否需要封禁、限流或进一步分析其行为
☆ 脚本实现
# 提取日志中的 IP(假设为每行第一个字段,符合 Nginx 默认日志格式)并统计频次,按次数降序排序,取前 10
awk '{print $1}' /usr/local/nginx/logs/access.log | sort | uniq -c | sort -nr | head -n 10
说明:
awk '{print $1}':提取日志每行的第一个字段(通常是客户端 IP,Nginx 默认日志格式中 $1为 IP)。
sort:对 IP 列表进行排序(uniq -c要求输入已排序)。
uniq -c:统计每个唯一 IP 的出现次数(-c表示计数)。
sort -nr:按计数结果降序排序(-n数值排序,-r逆序)。
head -n 10:仅显示前 10 条结果。
统计404错误的请求
☆ 场景背景
HTTP 404 状态码表示 “请求的资源不存在”,可能由以下原因导致:
- 用户侧问题:用户手动输入了错误的 URL、点击了过期的书签或外链。
- 业务侧问题:前端页面链接配置错误(如前端代码中的 API 地址拼写错误)、后端服务删除了文件但未更新前端引用、CDN 缓存了旧版本的无效链接。
- 攻击行为:扫描器尝试访问常见的敏感路径(如 /admin.php、/config.json),试图探测系统漏洞。
通过统计 404 错误请求,可以快速定位 “哪些资源被频繁访问但不存在”,进而修复业务逻辑或加固安全防护。
☆ 脚本实现
# grep 查找关键状态码 404 grep '404' /usr/local/nginx/logs/access.log 或者 grep '404' /var/log/nginx/access.log # 提取所有状态码为 404 的日志行(Nginx 默认日志格式中状态码是第9个字段) awk '$9 == 404' /usr/local/nginx/logs/access.log 或者 awk '$9 == 404' /var/log/nginx/access.log
如果Nginx站点很正常,一般来讲就没有404,可以考虑查找一下200
awk '$9 == 200' /usr/local/nginx/logs/access.log|more
进阶实现
# 进阶:提取 404 请求的路径(第7个字段),统计频次并排序
awk '$9 == 404 {print $7}' /usr/local/nginx/logs/access.log | sort | uniq -c | sort -nr | head -n 10
或者
awk '$9 == 404 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -n 10
或者
awk '$9 == 404' /usr/local/nginx/logs/access.log | awk '{ print $7}' | sort | uniq -c | sort -nr | head -n 10
或者
awk '$9 == 404' /var/log/nginx/access.log | awk '{ print $7}' | sort | uniq -c | sort -nr | head -n 10
统计最热门的URL
☆ 场景背景
“最热门的 URL” 反映了用户最常访问的页面或接口,是企业分析 “用户关注什么” 和 “业务重点在哪里” 的关键指标。通过统计热门 URL,可以:
- 优化资源配置:为高流量页面分配更多服务器资源(如 CDN 加速、数据库缓存)。
- 改进用户体验:分析热门页面的加载速度、跳出率(需结合其他工具),针对性优化交互设计。
- 验证业务策略:检查推广活动链接(如营销页 /promotion/2025)是否达到预期流量,或核心功能(如支付页 /checkout)是否易用。
☆ 脚本实现
# 提取日志中的请求路径(第11个字段),统计频次并排序,取前 10
awk '{print $11}' /usr/local/nginx/logs/access.log | sort | uniq -c | sort -nr | head -n 10
或者
awk '{print $11}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -n 10
日志轮转
作用:利用Shell脚本对日志进行切割,把大的访问日志切割为一个一个小日志,方便后期存储以及查看分析
☆脚本实现
mkdir /scripts cd /scripts vim logrotate.sh ------------------分割线------------------- #!/bin/bash date_info=$(date +%F-%H-%M) mv /usr/local/nginx/logs/access.log /usr/local/nginx/logs/access.log.$date_info /usr/local/nginx/sbin/nginx -s reload ------------------分割线------------------- chmod +x /scripts/logrotate.sh
☆配置 crontab
crontab -e * * * * * /bin/bash /scripts/logrotate.sh &>/dev/null 或者 0 */6 * * * /bin/bash /scripts/logrotate.sh &>/dev/null 或者 0 * * * * /bin/bash /scripts/logrotate.sh &>/dev/null 30 2 * * * /bin/bash /scripts/logrotate.sh &>/dev/null
改进版
mv /usr/local/nginx/logs/access.log /usr/local/nginx/logs/access.log.$(date +%F_%H-%M-%S) && /usr/local/nginx/sbin/nginx -s reopen
nginx -s reload 与 nginx -s reopen 对比表
|
对比项 |
reload |
reopen |
|
主要用途 |
重新加载配置文件 |
重新打开日志文件 |
|
是否创建新日志文件 |
❌ 否 |
✅ 是 |
|
是否重启工作进程 |
✅ 是(平滑重启) |
❌ 否(继续使用原进程) |
|
是否重新加载配置 |
✅ 是 |
❌ 否 |
|
是否中断现有连接 |
❌ 否(优雅关闭) |
❌ 否 |
|
配置文件语法检查 |
✅ 会进行检查 |
❌ 不会检查 |
|
典型使用场景 |
nginx.conf 配置变更后生效 |
日志切割/轮转(配合 logrotate) |
|
执行命令示例 |
|
|
工作原理简述
reload:
- 主进程检查新配置语法
- 启动新工作进程(加载新配置)
- 优雅关闭旧工作进程
reopen:
- 主进程通知工作进程关闭当前日志文件
- 工作进程重新打开日志文件(按配置路径)
- 若文件不存在则自动创建
总结
日志轮转的本质就是把一个大的日志切割为若干个小的日志,防止文件过大。
Nginx 反向代理
反向代理(Reverse Proxy)是位于 客户端与后端服务器之间 的中间设备(或服务),客户端直接访问代理服务器,代理服务器再将请求转发给内部的后端服务器,并将后端服务器的响应返回给客户端。
反向代理的好处:
- 隐藏后端架构:客户端只与代理服务器交互,后端服务的IP、端口、部署细节(如多台服务器集群)对客户端不可见。
- 负载均衡:将客户端请求分发到多台后端服务器,提升整体处理能力(后续章节会深入讲解)。
- 安全防护:代理服务器可过滤恶意请求(如SQL注入、XSS)、限制访问IP、提供SSL加密(HTTPS终止)。
- 统一入口:通过一个域名/端口(如 http://example.com)访问多个后端服务(如API、静态资源、管理后台)。
环境准备
准备虚拟机
|
角色 |
IP |
主机名 |
功能 |
|
nginx1 |
192.168.88.101 |
nginx1.itcast.cn |
代理服务器 |
|
nginx2 |
192.168.88.102 |
nginx2.itcast.cn |
后端服务器 |
修改主机名和 hosts
hostnamectl set-hostname nginx1.itcast.cn && bash hostnamectl set-hostname nginx2.itcast.cn && bash cat >/etc/hosts<<EOF 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.88.101 nginx1 nginx1.itcast.cn 192.168.88.102 nginx2 nginx2.itcast.cn EOF
关闭防火墙与 SELinux
iptables -F systemctl stop firewalld systemctl disable firewalld setenforce 0 sed -i '/SELINUX=enforcing/cSELINUX=disabled' /etc/selinux/config
安装依赖包以及时间同步
# 安装依赖包
yum install vim wget rsync net-tools epel-release -y
# 更新安装ntp时间服务器(可选)
yum install ntpsec -y
ntpdate cn.ntp.org.cn
说明:
ntpsec:是 NTP (Network Time Protocol) 的一个安全增强分支版本,用于系统时间同步;
cn.ntp.org.cn:是中国国家授时中心维护的 NTP 服务器地址
# 如果Linux服务器通不了外网,可以考虑配置一下DNS解析地址
cat >/etc/resolv.conf<<EOF
nameserver 192.168.88.2
nameserver 114.114.114.114
EOF
部署实战
配置后端服务器
在后端服务器nginx2上执行
dnf安装的nginx
[root@nginx2 ~]# dnf install nginx -y
修改nginx服务运行端口为8080
[root@nginx2 ~]# vim /etc/nginx/nginx.conf
...
server {
listen 8080;
listen [::]:8080;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
...
[root@nginx2 ~]# cat /etc/nginx/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
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;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 8080;
listen [::]:8080;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers PROFILE=SYSTEM;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
[root@nginx2 ~]# cat >/usr/share/nginx/html/index.html <<EOF
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>后端Web服务器</title>
</head>
<body>
这是后端Web服务器
</body>
</html>
EOF
[root@nginx2 ~]# cat /usr/share/nginx/html/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>后端Web服务器</title>
</head>
<body>
这是后端Web服务器
</body>
</html>
[root@nginx2 ~]#
检查nginx配置文件是否正确
[root@nginx2 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx2 ~]# systemctl restart nginx
[root@nginx2 ~]# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; preset: disabled)
Active: active (running) since Thu 2025-12-11 11:34:51 CST; 4s ago
Process: 29371 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
Process: 29373 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
Process: 29374 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
Main PID: 29375 (nginx)
Tasks: 3 (limit: 22927)
Memory: 3.0M
CPU: 25ms
CGroup: /system.slice/nginx.service
├─29375 "nginx: master process /usr/sbin/nginx"
├─29376 "nginx: worker process"
└─29377 "nginx: worker process"
Dec 11 11:34:51 nginx2.itcast.cn systemd[1]: Starting The nginx HTTP and reverse proxy server...
Dec 11 11:34:51 nginx2.itcast.cn nginx[29373]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Dec 11 11:34:51 nginx2.itcast.cn nginx[29373]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Dec 11 11:34:51 nginx2.itcast.cn systemd[1]: Started The nginx HTTP and reverse proxy server.
[root@nginx2 ~]# systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
[root@nginx2 ~]# netstat -pantul|grep nginx
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 30551/nginx: master
tcp6 0 0 :::8080 :::* LISTEN 30551/nginx: master
[root@nginx2 ~]#
源码安装的nginx
[root@nginx2 ~]# ls /usr/local/nginx/
client_body_temp fastcgi_temp logs sbin uwsgi_temp
conf html proxy_temp scgi_temp
[root@nginx2 ~]# ls /usr/local/nginx/conf/
fastcgi.conf mime.types scgi_params.default
fastcgi.conf.default mime.types.default uwsgi_params
fastcgi_params nginx.conf uwsgi_params.default
fastcgi_params.default nginx.conf.bak win-utf
koi-utf nginx.conf.default
koi-win scgi_params
[root@nginx2 ~]# vim /usr/local/nginx/conf/nginx.conf
[root@nginx2 ~]# cat /usr/local/nginx/conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8080;
server_name 192.168.88.102;
root /usr/local/nginx/html;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
[root@nginx2 ~]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@nginx2 ~]# nginx -s reload
[root@nginx2 ~]# cat >/usr/local/nginx/html/index.html <<EOF
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>后端Web服务器</title>
</head>
<body>
这是后端Web服务器
</body>
</html>
EOF
[root@nginx2 ~]# cat /usr/local/nginx/html/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>后端Web服务器</title>
</head>
<body>
这是后端Web服务器
</body>
</html>
[root@nginx2 ~]# systemctl restart nginx
[root@nginx2 ~]# systemctl status nginx
● nginx.service - Nginx Web Server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: d>
Active: active (running) since Tue 2026-03-24 09:40:53 CST; 5s ago
Process: 4706 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, sta>
Process: 4708 ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/co>
Main PID: 4709 (nginx)
Tasks: 2 (limit: 22927)
Memory: 2.1M
CPU: 17ms
CGroup: /system.slice/nginx.service
├─4709 "nginx: master process /usr/local/nginx/sbin/nginx -c /usr>
└─4710 "nginx: worker process"
Mar 24 09:40:53 nginx2.itcast.cn systemd[1]: Starting Nginx Web Server...
Mar 24 09:40:53 nginx2.itcast.cn systemd[1]: Started Nginx Web Server.
[root@nginx2 ~]# netstat -pantul|grep nginx
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 4709/nginx: master
[root@nginx2 ~]#
测试后端服务器的Web服务
[root@nginx2 ~]# curl 192.168.88.102:8080
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>后端Web服务器</title>
</head>
<body>
这是后端Web服务器
</body>
</html>
[root@nginx2 ~]#
http://192.168.88.102:8080/
配置代理服务器
在前端服务器nginx1上执行
dnf安装的nginx
[root@nginx1 ~]# dnf install nginx -y
修改nginx1配置文件,对接nginx2
[root@nginx1 ~]# find / -name nginx.conf
/etc/nginx/nginx.conf
/usr/lib/sysusers.d/nginx.conf
[root@nginx1 ~]# vim /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name _;
# root /usr/share/nginx/html;
location / {
proxy_pass http://192.168.88.102:8080; # 关键!指定后端服务器的IP和端口
proxy_set_header Host $host; # 传递原始请求的Host头(重要!)
proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实IP(后端可通过此头获取)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递完整的代理链路IP
}
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
# root html;
}
}
}
[root@nginx1 ~]# cat /etc/nginx/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
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;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
listen [::]:80;
server_name _;
# root /usr/share/nginx/html;
location / {
proxy_pass http://192.168.88.102:8080; # 关键!指定后端服务器的IP和端口
proxy_set_header Host $host; # 传递原始请求的Host头(重要!)
proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实IP(后端可通过此头获取)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递完整的代理链路IP
}
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers PROFILE=SYSTEM;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
[root@nginx1 ~]#
源码安装的nginx
[root@nginx1 ~]# vim /usr/local/nginx/conf/nginx.conf
[root@nginx1 ~]# cat /usr/local/nginx/conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name _;
# root /usr/local/nginx/html;
location / {
proxy_pass http://192.168.88.102:8080; # 关键!指定后端服务器的IP和端口
proxy_set_header Host $host; # 传递原始请求的Host头(重要!)
proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实IP(后端可通过此头获取)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递完整的代理链路IP
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
[root@nginx1 ~]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@nginx1 ~]# nginx -s reload
[root@nginx1 ~]#
检查Nginx配置文件并启动Nginx服务
[root@nginx1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx1 ~]# systemctl restart nginx
[root@nginx1 ~]# systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
[root@nginx1 ~]# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: d>
Active: active (running) since Sat 2025-12-13 12:07:24 CST; 7s ago
Main PID: 30749 (nginx)
Tasks: 3 (limit: 22926)
Memory: 3.0M
CPU: 37ms
CGroup: /system.slice/nginx.service
├─30749 "nginx: master process /usr/sbin/nginx"
├─30750 "nginx: worker process"
└─30751 "nginx: worker process"
Dec 13 12:07:24 nginx1.itcast.cn systemd[1]: Starting The nginx HTTP and rever>
Dec 13 12:07:24 nginx1.itcast.cn nginx[30747]: nginx: the configuration file />
Dec 13 12:07:24 nginx1.itcast.cn nginx[30747]: nginx: configuration file /etc/>
Dec 13 12:07:24 nginx1.itcast.cn systemd[1]: Started The nginx HTTP and revers>
# nginx -s reload # 可选
验证测试
http://192.168.88.101/
http://192.168.88.102:8080/
Nginx代理服务器暴力broken测试
server {
listen 80;
server_name _;
location / {
return 500 "broken\n";
}
}
[root@nginx1 ~]# cd /etc/nginx
[root@nginx1 nginx]# pwd
/etc/nginx
[root@nginx1 nginx]# vim nginx.conf
[root@nginx1 nginx]# cat nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
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;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
#include /etc/nginx/conf.d/*.conf;
server {
listen 80;
server_name _;
location / {
return 500 "broken\n";
}
#root /usr/share/nginx/html;
# location / {
# proxy_pass http://192.168.88.102:8080; # 关键!指定后端服务器的IP和端口
# proxy_set_header Host $host; # 传递原始请求的Host头(重要!)
# proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实IP(后端可通过此头获取)
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递完整的代理链路IP
# }
#include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
[root@nginx1 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx1 nginx]# nginx -s reload
[root@nginx1 nginx]# curl 127.0.0.1
broken
[root@nginx1 nginx]#
http://192.168.88.101/
结论1:
Nginx 在没有配置
location和root时,会使用默认 root/usr/share/nginx/html提供静态资源。
结论2:
只要定义了
location /,就会覆盖默认行为。
结论3:
return指令优先级非常高,可以直接终止请求处理流程。
Nginx 的配置是具备兜底机制的,即使没有显式配置 root 和 location,也会使用默认 root 提供服务。因此在排查问题时,如果发现配置改了但结果没变,要考虑是否命中了默认行为或者其他 location。
HTTP/1.0与HTTP/1.1
HTTP/1.1 和 HTTP/1.0 是 Web 协议演进中的两个重要版本,主要区别如下:
主要区别对比表
| 特性 | HTTP/1.0 | HTTP/1.1 |
| 连接方式 | 默认短连接,每个请求建立新TCP连接 | 默认长连接(Keep-Alive),连接可复用 |
| Host头 | 可选,不支持虚拟主机 | 必需,支持多域名共享IP |
| 缓存控制 | 简单的 Expires、Pragma | 强大的 Cache-Control、ETag、Last-Modified |
| 状态码 | 基本状态码 | 新增 100 Continue, 206 Partial Content 等 |
| 分块传输 | 不支持 | 支持 Transfer-Encoding: chunked |
| 管道化 | 不支持 | 支持(但有限制) |
| 带宽优化 | 不支持范围请求 | 支持 Range 和 Accept-Ranges |
| 错误处理 | 简单 | 更完善的错误处理和恢复机制 |
| 请求方法 | GET, POST, HEAD | 新增 OPTIONS, PUT, DELETE, TRACE, CONNECT |
[root@nginx1 ~]# vim /etc/nginx/nginx.conf
[root@nginx1 ~]# cat /etc/nginx/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
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;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
listen [::]:80;
server_name _;
# root /usr/share/nginx/html;
location / {
proxy_http_version 1.1;
proxy_pass http://192.168.88.102:8080; # 关键!指定后端服务器的IP和端口
proxy_set_header Host $host; # 传递原始请求的Host头(重要!)
proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实IP(后端可通过此头获取)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递完整的代理链路IP
proxy_set_header X-Original-Protocol $server_protocol;
}
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2;
# listen [::]:443 ssl http2;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers PROFILE=SYSTEM;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
}
[root@nginx1 ~]#
[root@nginx1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx1 ~]# nginx -s reload
访问代理服务器地址
http://192.168.88.101/
总结
代理一共有两种:(正向代理) + (反向代理)
1、正向代理用户可以感知到,比较典型应用(科学上网)
2、反向代理用户无感知,比较典型的应用(请求转发,更多应用在于负载均衡技术)
Nginx 负载均衡
四层负载 vs 七层负载
① 底层实现 => 四层负载均衡基于网络层与传输层,也就是IP + Port(套接字 socket)实现请求转发;七层负载基于应用层,通过URL地址请求转发
② 性能不同 => 四层相当于转发器,效率更高;七层需要通过URL判断才能实现转发,需要做额外的处理
③ 安全性不同 => 七层需要对用户URL请求,判断可以屏蔽异常请求,相对而言更加安全
环境准备
|
角色 |
IP |
主机名 |
功能 |
|
lb1 |
192.168.88.100 |
lb1.itcast.cn |
负载均衡 |
|
web1 |
192.168.88.101 |
web1.itcast.cn |
Web服务 |
|
web2 |
192.168.88.102 |
web2.itcast.cn |
Web服务 |
修改IP、主机名和域名解析
hostnamectl set-hostname lb1.itcast.cn && bash hostnamectl set-hostname web1.itcast.cn && bash hostnamectl set-hostname web2.itcast.cn && bash cat >/etc/hosts<<EOF 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.88.100 lb1 lb1.itcast.cn 192.168.88.101 web1 web1.itcast.cn 192.168.88.102 web2 web2.itcast.cn EOF
关闭防火墙与 SELinux
iptables -F systemctl stop firewalld systemctl disable firewalld setenforce 0 sed -i '/SELINUX=enforcing/cSELINUX=disabled' /etc/selinux/config
安装依赖包时间同步
yum install vim wget rsync net-tools epel-release -y yum install ntpsec -y ntpdate cn.ntp.org.cn cat >/etc/resolv.conf<<EOF nameserver 192.168.88.2 nameserver 114.114.114.114 EOF
NTPsec vs Chrony
| 特性 | NTPsec | Chrony |
| 起源 | 从经典 NTP(ntpd)分支而来,由 NTPsec 团队维护 | 独立开发,最初为嵌入式系统设计 |
| 设计目标 | 增强安全性和性能,修复 ntpd 的历史问题 | 快速同步、低延迟,适合不稳定网络环境 |
| 社区活跃度 | 活跃,但用户基数小于 Chrony | 广泛采用,尤其在云环境和现代 Linux 发行版 |
安装nginx
三个服务器都要按照nginx
如果网络有问题,请执行以下命令
cat >/etc/resolv.conf<<EOF nameserver 192.168.88.2 nameserver 114.114.114.114 EOF
systemctl status nginx --no-pager
配置 Web1 & Web2
这节课我们聚焦 Nginx 负载均衡,关于 backend 服务,用 html 简单内容代替。
# 在LB1上执行,统一 一下三台的nginx配置文件(可选) scp /etc/nginx/nginx.conf 192.168.88.101:/etc/nginx/ scp /etc/nginx/nginx.conf 192.168.88.102:/etc/nginx/ # 在 Web1 上执行 echo "This is Web Server1" > /usr/share/nginx/html/index.html 或者 echo "This is Web Server1" > /usr/local/nginx/html/index.html # 在 Web2 上执行 echo "This is Web Server2" > /usr/share/nginx/html/index.html 或者 echo "This is Web Server2" > /usr/local/nginx/html/index.html
验证测试
curl 127.0.0.1
配置 LB1
下面的操作,都是在 LB1 上操作
第一步:查看 nginx.cnf
在 LB1 上,备份配置文件nginx.conf,然后删除注释与空行
第一步,备份
[root@lb1 ~]# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak # 这是 dnf/yum 安装的 Nginx
第二步,去掉注释,空行
[root@lb1 ~]# grep -Ev '#|^$' /etc/nginx/nginx.conf.bak > /etc/nginx/nginx.conf
第三步,简单查看配置
[root@lb1 ~]# cat /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
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;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
[root@lb1 ~]#
第二步:配置负载均衡
Nginx 在 http 块中实现七层负载均衡,默认使用轮询算法;同时也支持通过 stream 块实现四层负载均衡
在 LB1 上操作
vim /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
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;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# include /etc/nginx/conf.d/*.conf;
#################### 配置开始 ######################
upstream my_web_service {
server 192.168.88.101:80;
server 192.168.88.102:80;
}
#################### 配置结束 ######################
server {
listen 80;
listen [::]:80;
#################### 配置开始 ######################
server_name 192.168.88.100; # 替换为实际域名或 IP
location / {
proxy_pass http://my_web_service; # 将请求转发到负载均衡组
proxy_set_header HOST $host;
}
#################### 配置结束 ######################
# server_name _;
# root /usr/share/nginx/html;
# include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
第三步:重载配置,验证测试第三步:重载配置,验证测试
在 LB1 上操作
nginx -t nginx -s reload [root@lb1 ~]# curl 192.168.88.100 This is Web Server1 [root@lb1 ~]# curl 192.168.88.100 This is Web Server2 [root@lb1 ~]# curl 192.168.88.100 This is Web Server1 [root@lb1 ~]# curl 192.168.88.100 This is Web Server2
注意:如果无法访问Nginx Web服务,请在所有Linux服务器上执行以下命令!
sed -i -r 's/SELINUX=[ep].*/SELINUX=disabled/g' /etc/selinux/config setenforce 0 systemctl stop firewalld &> /dev/null systemctl disable firewalld &> /dev/null iptables -F iptables -t nat -F iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT
回到浏览器,多次访问,会发现
页面在 Web1 和 Web2 之间来回切换(这是为了方便验证而设计的内容),从而验证负载均衡配置成功。
炫酷技能(拓展)
旋转星空
cat >index.html<<EOF
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<style>
body {
background: #060e1b;
overflow: hidden;
}
</style>
</HEAD>
<BODY>
<canvas id="canvas"></canvas>
<script>
"use strict";
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
w = canvas.width = window.innerWidth,
h = canvas.height = window.innerHeight,
hue = 217,
stars = [],
count = 0,
maxStars = 1400;
// Thanks @jackrugile for the performance tip! https://codepen.io/jackrugile/pen/BjBGoM
// Cache gradient
var canvas2 = document.createElement('canvas'),
ctx2 = canvas2.getContext('2d');
canvas2.width = 100;
canvas2.height = 100;
var half = canvas2.width/2,
gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
gradient2.addColorStop(0.025, '#fff');
gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');
gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');
gradient2.addColorStop(1, 'transparent');
ctx2.fillStyle = gradient2;
ctx2.beginPath();
ctx2.arc(half, half, half, 0, Math.PI * 2);
ctx2.fill();
// End cache
function random(min, max) {
if (arguments.length < 2) {
max = min;
min = 0;
}
if (min > max) {
var hold = max;
max = min;
min = hold;
}
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function maxOrbit(x,y) {
var max = Math.max(x,y),
diameter = Math.round(Math.sqrt(max*max + max*max));
return diameter/2;
}
var Star = function() {
this.orbitRadius = random(maxOrbit(w,h));
this.radius = random(60, this.orbitRadius) / 12;
this.orbitX = w / 2;
this.orbitY = h / 2;
this.timePassed = random(0, maxStars);
this.speed = random(this.orbitRadius) / 50000;
this.alpha = random(2, 10) / 10;
count++;
stars[count] = this;
}
Star.prototype.draw = function() {
var x = Math.sin(this.timePassed) * this.orbitRadius + this.orbitX,
y = Math.cos(this.timePassed) * this.orbitRadius + this.orbitY,
twinkle = random(10);
if (twinkle === 1 && this.alpha > 0) {
this.alpha -= 0.05;
} else if (twinkle === 2 && this.alpha < 1) {
this.alpha += 0.05;
}
ctx.globalAlpha = this.alpha;
ctx.drawImage(canvas2, x - this.radius / 2, y - this.radius / 2, this.radius, this.radius);
this.timePassed += this.speed;
}
for (var i = 0; i < maxStars; i++) {
new Star();
}
function animation() {
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 0.8;
ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 1)';
ctx.fillRect(0, 0, w, h)
ctx.globalCompositeOperation = 'lighter';
for (var i = 1, l = stars.length; i < l; i++) {
stars[i].draw();
};
window.requestAnimationFrame(animation);
}
animation();
</script>
</BODY>
</HTML>
EOF
黑客数字雨
cat >index.html<<EOF
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<style>
/*Twitter @locoalien*/
/*Sitio web www.locoaliensoft.com*/
/*www.facebook.com/CulturaInformatica*/
* {margin: 0; padding: 0;}
canvas {display: block;}
body {background: black;}
</style>
</HEAD>
<BODY>
<html>
<head>
<title>Hacking locoalien Matrix console</title>
<meta charset="UTF-8">
</head>
<body>
<canvas id="locoalien"></canvas>
<script type="text/javascript">
</script>
</body>
</html>
<script>
//*--------------------------------------*
//* Desarrollado por Locoalien *
//* Twitter @locoalien *
//* Sitio web: www.locoaliensoft.com *
//*--------------------------------------*
//+++++++++++++++++++++++++++++++++++++
// El objetivo de este ejemplo es aprender a dar animacion y utilizar las propiedades
// Mas comunes de JavaScript. Veremos el poder que tiene HTML5 implementando el Canvas
// Espero les guste este ejemplo
// Para mas informacion visitar nuestra pagina de Facebook: https://www.facebook.com/CulturaInformatica
//+++++++++++++++++++++++++++++++++++++
window.onload = hacking;//Llamamos a la funcion despues de que el documento ha sido cargado completamente
function hacking(){
var c = document.getElementById("locoalien");
c.height = window.innerHeight; //innerHeight se utiliza para saber la altura de la pantalla
c.width = window.innerWidth; //innerHeight se utiliza para saber la altura de la pantalla
var letraTam=12; //Tamaño de la letras por pixel
var columnas=c.width/letraTam; //El ancho dividido por el tamano que tendra las letras
var Texto="0"; //El testo que aparecera en pantalla
Texto=Texto.split("");//La función split() permite dividir una cadena de caracteres (string) en varios bloques y crear un array con estos
var Texto2="1";
Texto2=Texto2.split("");
var letras=[];
for(var i=0; i<columnas;i++){
letras[i]=1;//Siver para saber la cantidad de letras que tendra en la pantalla
}
contexto= c.getContext('2d');//Muy importante especificar el contexto en el cual vamos a trabajar
function dibujar(){
contexto.fillStyle="rgba(0,0,0,0.05)";//Damos el color que tendra el recuadro en el que estara la animacion. en este caso sera transparente 0.05
contexto.fillRect(0,0,c.width,c.height);//Damos las dimensiones alto y ancho que tendra el cuadrado, que en este caso es de toda la pantalla
contexto.fillStyle= "#0f0";//Color de las letras
contexto.font= letraTam+"px arial";//Tamaño de la letra
for(var i=0;i<letras.length;i++){
text=Texto; //Le asigno el texto que definimos en la parte de arriba
//El ciclo for me permite darle las coordenadas correctas para posicionar el text x, y
text2=Texto2;//El texto dos que mostrara solo el 1
if(i%2==1){contexto.fillText(text,i*letraTam, letras[i]*letraTam);//Para imprimir texto disponesmos de fillText(texto,x,y)
}else{
contexto.fillText(text2,i*letraTam, letras[i]*letraTam);//Para imprimir texto disponesmos de fillText(texto,x,y)
}
if(letras[i]*letraTam > c.height && Math.random()>0.975){
letras[i]=0;
}
letras[i]++;
}
}
setInterval(dibujar,120);//velocidad a la que se ejecuta la funcion en milisegundos
}
</script>
</BODY>
</HTML>
EOF
扩展: 解决无法显示真实IP的问题
我们观察 Web1 和 Web2 的 access日志,会发现
# 在 Web1 和 Web2 上分别执行 tail /var/log/nginx/access.log
为了解决 Web1/Web2 访问日志的显示问题(无法获取客户端真实的IP地址)
回到 LB1 服务器上,找到配置文件
vi /etc/nginx/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#################### 配置开始 ######################
upstream my_web_service {
server 192.168.88.101:80;
server 192.168.88.102:80;
}
#################### 配置结束 ######################
server {
listen 80;
listen [::]:80;
#################### 配置开始 ######################
server_name 192.168.88.100; # 替换为实际域名或 IP
location / {
proxy_pass http://my_web_service; # 将请求转发到负载均衡组
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr; # 添加这两行
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
#################### 配置结束 ######################
server_name _;
root /usr/share/nginx/html;
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
/usr/sbin/nginx -s reload
Nginx 变量:
$remote_addr:Nginx 变量,表示直接连接到当前服务器的客户端 IP。
X-Real-IP:记录原始客户端 IP,适用于单级代理场景。
X-Forwarded-For:记录完整代理链,适用于多级代理和日志分析。
最佳实践:两者同时设置,兼顾简单性和可追溯性。
在Web01和Web02服务器上,打开配置文件(默认就是配置好的),定制日志显示格式
在Web01和Web02服务器上
# vi /etc/nginx/nginx.conf
...
http {
...
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;
...
}
在Web01和Web02服务器上,分别重启
# /usr/sbin/nginx -s reload
在 Web1 上和web2 上,都验证测试
tail -3 /var/log/nginx/access.log
验证宿主机 IP
# 在宿主机(笔记本 Windows 电脑)上,执行 ipconfig
分发请求关键字
backup关键字:其他的没有backup标识的服务器都无响应,才分发到backup服务器。
# vim conf/nginx.conf
http {
...
upstream my_web_service {
server 192.168.88.101:80 backup; # 优先访问其他的服务器
server 192.168.88.103:80;
}
...
}
down关键字:任何时候,请求都不分发给配置了down关键字的服务器
# vim conf/nginx.conf
http {
...
upstream my_web_service {
server 192.168.88.101:80;
server 192.168.88.103:80 down; # 下线了
}
...
}
用的最多的还是backup,关键时刻起到热备作用!
负载均衡的3种调度算法(请求规则)
Nginx 官方默认3种负载均衡的算法:
① Round-Robin RR轮询(默认): 一次一个的来(理论上的,实际实验可能会有间隔)
② Weight 权重: 权重高多分发一些,服务器硬件更好的设置权重更高一些
比如,当我们设置成 1:9,会发现大部分情况,都是访问的 Web2
# vim conf/nginx.conf
http {
...
upstream my_web_service {
server 192.168.88.101:80 weight=4;
server 192.168.88.103:80 weight=6;
}
...
}
③ IP_HASH:代表把同一个IP来源的请求分到到同一个后端服务器
# vim conf/nginx.conf
http {
...
upstream my_web_service {
ip_hash; # 加上这个 IP Hash 就可以
server 192.168.88.101:80;
server 192.168.88.103:80;
}
...
}
小结:
Round-Robin:rr轮询算法,请求均分
weight:weight=8
ip_hash:淘宝、京东 => 同一个IP所有请求都由同一个服务器处理
Session共享解决方案(调度算法)
① http协议,http协议是一个无状态协议,无法记录用户的浏览轨迹。
② cookie技术,可以把用户的信息记录在浏览器的缓存中(缓存存在过期时间)
③ session技术,可以把用户的浏览轨迹保存在服务器端(默认为/tmp目录)
验证码也是Session文件,其产生的验证码会保存在这个文件中。
模拟负载均衡与Session共享问题:
第一步:配置负载均衡(默认算法使用轮询算法)
第二步:使用账号密码登录功能,登录后台管理界面(admin,123456)
我们发现了一个问题,无论我们这么输入这个验证码,始终提示验证失败,主要原因:由于使用轮询算法,所以生成验证码时,相当于一次请求,验证验证码时也是一次请求。两次请求所在的服务器不同,所以最终验证总是失败。
解决办法:想办法让同一个IP的请求,分发到同一个Web服务器。
第三步:使用IP_HASH算法,问题解决
# vim conf/nginx.conf
http {
...
upstream my_web_service { # 加上这个 IP Hash 就可以
ip_hash;
server 192.168.88.101:80;
server 192.168.88.103:80;
}
...
}
注:其实Session共享的解决方案,非常多,不仅仅只有IP_HASH一种算法,还可以基于MySQL或Redis实现Session共享













