课堂笔记 & 面试题(详细版)
课程:Web安全环境搭建(LNMP + DVWA)
系统环境:Windows + Ubuntu(VMware虚拟机)
一、课堂笔记(详细版)
第1部分:基础环境问题
1.1 PHPStudy启动问题
-
现象:很多同学的PHPStudy无法正常启动
-
根本原因 :之前安装过MongoDB等数据库导致参数冲突
-
关键操作 :
查看日志 → 发现系统反复报错某个参数问题 → 非真正的启动失败 -
解决方案 :
- 查看PHPStudy日志定位具体报错参数
- 使用cloud环境规避本地配置冲突(推荐)
- 卸载冲突的数据库软件
-
重点:这类问题常见于之前安装过其他数据库的电脑上,查看日志是准确定位的关键
1.2 Windows管理员权限
- 核心原则 :Windows系统中以管理员身份运行程序至关重要
- 具体场景 :
- 普通cmd运行可能受限
- 使用管理员权限的PowerShell 才能顺利执行像
open code等命令 - 因为这些命令可能需要修改注册表等关键系统参数
- 实际案例 :有同学和Claude AI纠缠两个多月的问题,本质上就是权限问题
- 延伸:PHPStudy中运行MySQL时,本质上也是通过管理员命令来启动的
1.3 MySQL服务启动失败
-
主要病因 :参数格式错误
- 配置文件出现多余参数(非标准的
"--参数"格式) - 系统因无法识别而报错
- 这种错误比端口冲突更隐蔽
- 配置文件出现多余参数(非标准的
-
特别注意 :
- 不要轻信某些免费AI工具的诊断结果(如把PHPStudy配置问题误判为模型问题)
- 建议切换更可靠的模型来分析,比如使用GLM模型
-
提问模板 :
"分析我的phpstudy中MySQL服务异常启动的原因,是否由于以下问题..." -
关键点:参数规范性和诊断工具的选择
1.4 MySQL环境混乱
- 现状:很多同学电脑上同时安装了多个版本的MySQL(5.7、8.0)甚至MongoDB
- 后果:端口冲突 + 配置混乱
- 建议:保留一个主要版本,其他冗余数据库软件卸载
1.5 DVWA访问问题
- 问题 :直接用
http://dvwa无法访问 - 替代方案 :尝试
http://127.0.0.1:81 - 原因:DVWA默认运行在81端口;火狐浏览器安全设置限制
- 解决方案:调整火狐浏览器配置
1.6 AI工具推荐
- 推荐工具 :
- Kimi:可用于搜索技术问题解决方案
- GLM:coding plan效果不错(但需要抢购;5.2版本开始收费)
- 注意事项 :
- 充值后可能很快就欠费下线
- 有些工具可能给出需要付费的无关建议,可直接忽略
- 个别同学遇到浏览器兼容性问题
1.7 问题描述规范
-
核心原则:把问题描述得清晰完整
-
示例 (火狐浏览器无法访问DVWA):
1. 其他浏览器(如Edge)可以正常访问 2. 通过 http://dvwa 域名无法访问 3. 通过 127.0.0.1:81 本地地址可以访问 -
好处:避免对方反复询问基础配置问题,直接锁定是浏览器与域名的兼容性问题
1.8 MD文档乱码
- 原因:没装专业笔记软件
- 推荐软件 :Typora(收费,可找替代/破解版)
第2部分:DVWA环境搭建与数据库
2.1 DVWA初始化操作
-
关键操作路径 :
浏览器访问 http://localhost/dvwa/login.php → 进入 setup.php 页面 → 点击 "Create/Reset Database" 按钮进行初始化
2.2 DVWA报错分析
- 误区:有同学认为报错是MySQL版本过低导致的
- 事实:即使将MySQL升级到8.0.12高版本,同样的报错仍然存在
- 根本原因 :DVWA官方推荐使用的是MongoDB数据库 而非MySQL
- 报错本质是MongoDB的查询语法不兼容MySQL
- 当遇到类似 "is not" 这样的语法报错时,说明语句不兼容
- 常见错误类型 :
is not此类语法错误提示 → MongoDB语法用在MySQL里
2.3 配置文件修改原则
-
不建议:让系统自动修改(可能有风险)
-
建议 :手动查找问题文件,特别是根目录下的MySQL相关文件
手动检查报错提示 → 定位到具体文件 → 修正语法问题 -
核心原则:手动修改更安全,尤其涉及系统权限或关键配置时
-
备选方案:把报错信息反馈给工具或社区
第3部分:Ubuntu系统基础
3.1 MySQL版本兼容性
- 当前版本:8.0.12
- 问题:不支持某些需要8.0.29及以上版本的功能
- 解决方案 :
- 升级MySQL版本
- 修改对应的配置文件
3.2 Ubuntu登录方式
- 重要区别:与红帽系统不同
- 特点:Ubuntu安装时默认不会设置root密码
- 常见错误:习惯性用红帽的操作方式来登录Ubuntu
- 正确做法:使用安装时创建的普通用户先登录
3.3 root密码设置
-
背景:默认安装时系统不会引导设置root密码
-
操作步骤 :
sudo passwd root- 需要通过终端用sudo提权才能修改
Ctrl+Shift放大终端界面
-
密码复杂度 :
"123456"被拒(过于简单)"openlab123"才成功
-
注意事项 :如果安装时跳过了root密码设置,后期只能通过
sudo passwd root命令强制修改,但必须提权操作 -
权限管理:系统会反复要求验证,说明权限管理很严格
3.4 远程连接工具
-
场景:在虚拟机环境中直接操作不太方便
-
推荐工具:Xshell、MobaXterm等
-
关键步骤 :
① 新建一个主机连接 ② 输入正确的IP地址(如 192.168.50.158) ③ 保持默认的SSH 22端口 ④ 使用root用户名和对应密码登录 -
原理:大多数远程连接工具操作逻辑相通
第4部分:SSH远程连接与排查
4.1 SSH连接失败排查步骤
-
第一步:确认网络连通性
ping 192.168.50.158 # 测试主机到虚拟机 ping 192.168.50.1 # 测试虚拟机到主机(网关) -
第二步:检查sshd服务是否开启
systemctl status sshd -
常见误区:以为是root用户权限问题
-
事实 :服务未启动才是常见原因 比喻:你有了钥匙(账号密码),但门锁根本没安装(服务未开启)
-
两个基础条件:网络通畅 + 服务运行
4.2 apt更新与权限
-
普通用户 :执行
apt update会遇到权限不足 -
解决方案 :
su root # 先切换到root用户 输入密码 apt update # 顺利更新软件包列表 -
安装软件 :
apt install <软件包名>- 注意软件包名称拼写,输入错误会提示"无法定位"
- 可尝试安装其他已知软件包来测试网络连接是否正常
-
对比:与yum的使用很相似(先更新再安装)
4.3 SSH安装与启动
-
安装 :
apt install ssh -
问题:默认sshd服务没有启动
-
排查 :
- 可能是防火墙问题
- 可能是SELinux问题
- 端口被占用(22端口)
4.4 Ubuntu防火墙(ufw)
-
服务名 :
ufw.service -
关闭命令 :
systemctl stop ufw # 临时关闭 systemctl disable ufw # 永久关闭 -
日志查看:发现有关于22端口的报错信息,"fail to start"
-
对比 :
- Ubuntu → ufw
- 红帽系 → firewalld
-
排查顺序:服务启动失败 → 防火墙 → SELinux → 端口占用
4.5 SELinux
-
设置宽松模式 :
setenforce 0 -
注意事项:如果命令缺失,系统会提示安装命令,直接运行给出的安装命令即可
-
验证SSH:检查SSH服务是否能正常启动
4.6 最小化安装问题
- 特点:U盘库属于最小化安装,很多组件需要手动下载
- 操作:刚才只是进行了更新,所以会报错
- 粘贴问题:发现无法粘贴内容
- 变通方案:改用OpenSSH,先确保能连上服务器
- 关键点:最小化安装需手动补全组件
第5部分:SSH root登录配置
5.1 家目录区别
- 普通用户 :家目录
/home/用户名 - root用户 :家目录
/root - 重要:要先切换到root用户家目录再运行程序
- 验证:SSH显示 "active running" 状态时服务已正常
5.2 SSH允许root登录
-
配置文件 :
/etc/ssh/sshd_config -
要修改的参数 :
PermitRootLogin(注意P是大写) -
操作步骤 :
① vim /etc/ssh/sshd_config ② 找到 PermitRootLogin 这一行 ③ 默认是 "no",改成 "yes" ④ :wq 保存退出 ⑤ systemctl restart sshd # 必须重启服务 -
注意事项 :
- 配置文件路径要找准
- 改完必须重启服务(很多同学会忘记)
- 默认不允许root远程登录是出于安全考虑
- 生产环境要谨慎修改
5.3 源码安装 vs 包管理器安装
- 源码安装:可自定义路径和参数,灵活但维护成本高
- 包管理器(apt install):自动处理依赖但默认路径不直观
- 适用场景:需要深度定制时选择源码安装
5.4 Vim操作小贴士
- 保存退出:
:wq - 服务名太长时可以修改(如 "White House" 的例子)
- 重启服务是配置生效的必要步骤
第6部分:文件传输与解压缩
6.1 文件传输方式
-
方式一:U盘 → 直接拷贝到目标目录(如
/opt) -
方式二:FTP工具(sftp)
sftp root@192.168.50.158 -
重点:文件存放路径要清晰,便于后续查找
6.2 tar解压缩
-
常用命令 :
bash# 解压 gzip 格式 tar -xzvf 文件名.tar.gz # 解压 bzip2 格式 tar -xjvf 文件名.tar.bz2 # 解压 zip 格式(需先安装 unzip) unzip 文件名.zip
6.3 参数详解
| 参数 | 作用 | 说明 |
|---|---|---|
-x |
extract(解压) | |
-z |
gzip格式 | 对应 .tar.gz |
-j |
bzip2格式 | 对应 .tar.bz2 |
-v |
verbose(显示详情) | |
-f |
file(指定文件名) | 必须是最后一个参数 |
-G(大写) |
gzip旧版本 | 注意大小写区别 |
-g(小写) |
旧版格式 | 容易混淆 |
- 建议:虽然系统有时能自动识别压缩格式,但最好显式指定参数,避免意外错误
第7部分:Nginx源码安装
7.1 准备工作
-
解压安装包 :
bashtar -xvf nginx.tar.gz cd nginx-版本号/ -
安装编译工具 :
bashapt install gcc make wget- gcc:C语言编译器
- make:编译管理工具
- wget:下载工具(可选但推荐)
7.2 configure(配置检查)
-
作用:检查系统环境,确认依赖包是否齐全、环境是否匹配
-
自定义安装目录 :
bash./configure --prefix=/usr/local/nginx -
默认路径 :
/usr/local/ -
执行后:观察终端输出,出现类似列表的配置摘要信息时表示检测完成
7.3 依赖处理
-
常见缺失 :pcre库
bashapt install pcre* -
原则:不确定具体缺哪个版本,可以直接安装通配版本
-
快速方法:遇到不认识的报错信息,直接复制错误内容去搜索
7.4 编译与安装(核心三步)
bash
./configure # 第一步:配置检查
make # 第二步:编译(把源码变成可执行文件)
make install # 第三步:安装到指定目录
7.5 验证安装
bash
cd /usr/local/nginx
ls # 查看是否有 sbin/ 等关键目录
cd sbin
./nginx # 启动Nginx
curl 127.0.0.1 # 验证:看到"thank you for using nginx"即成功
7.6 启动与重载
-
启动 :必须手动到安装目录启动(源码安装没有系统服务配置)
bash/usr/local/nginx/sbin/nginx -
重载配置 :
bash/usr/local/nginx/sbin/nginx -s reload -
比喻:验证环节像打电话,听到对方"喂"的回应就知道线路接通了
第8部分:PHP环境与PHP-FPM
8.1 PHP安装
-
组件:PHP解析器 + php-fpm + php-pm等相关组件
-
特别注意 :
- 如果命令显示为多行,需要手动调整成一行才能正确执行
- MySQL数据库其实更推荐使用MariaDB替代
-
sudo提权 :
bashsudo make install sudo apt install 包名
8.2 多版本PHP管理
-
问题:安装php-fpm后发现实际运行版本是php8.5-fpm,但系统默认寻找php8.3
-
解决方法 :用完整服务名指定版本
bashsystemctl status php8.5-fpm -
比喻:同时拥有多个遥控器,必须拿对对应的设备
8.3 Nginx根目录
- 默认:html文件夹(不是常见的www目录)
- 验证:创建a.html并访问
- 注意:文件编码要用UTF-8,否则出现乱码
8.4 Nginx与PHP-FPM协同
-
核心原理 :Nginx默认不能解析PHP文件
- 遇到.php请求时直接返回源码文件
- 浏览器误以为要下载
-
解决方案 :把PHP文件交给php-fpm处理
Nginx → fastcgi_pass 127.0.0.1:9000 → php-fpm -
定位php-fpm :查看
www.conf配置文件bashfind / -name "www.conf"
8.5 端口监听配置
-
修改php-fpm配置文件 :
listen = 127.0.0.1:9000 -
关键细节 :
- 端口号9000类似快递柜编号,准确定位php-fpm服务
- 修改后必须
restart生效 - 注意配置格式(冒号必须是英文符号)
-
注释符号 :该配置文件用
;分号注释,不能用#井号 -
检查端口 :
bashss -antulp | grep 9000
8.6 grep查找配置文件
-
场景:知道文件内容但不确定路径
-
命令 :
bashgrep -r "fastcgi_pass" /etc/ -
参数说明 :
-r:递归搜索- 搜索内容放在命令最后(易错点:很多人会把路径放在-r后面)
-n:显示匹配行号
-
加速技巧 :缩小搜索范围到具体目录,如
/usr/local/
8.7 Vim批量操作
vim
:set nu " 显示行号,方便定位
:65,71s/#//g " 批量删除65到71行的#号
s表示替换#//表示把#替换为空g确保每行所有匹配项都被处理
8.8 FastCGI路径配置
-
原配置:路径有误
-
修正 :
$document_root$fastcgi_script_name -
特别注意:源码安装重启nginx需要用sbin下的启动文件,不能用systemctl
8.9 验证PHP解析
bash
# 检查9000端口
lsof -i :9000
# 创建测试文件 test.php
echo "<?php phpinfo(); ?>" > /usr/local/nginx/html/test.php
# 浏览器访问 test.php
# 正常:显示PHP执行结果
# 异常:出现下载提示(说明php-fpm和nginx未联通)
第9部分:MariaDB数据库
9.1 安装与启动
bash
# 安装
apt install mariadb-server mariadb-client
# 检查状态
systemctl status mariadb
# 显示 "active" 说明数据库正在运行
# 进入数据库(初始root无密码)
mariadb
# 或
mysql -u root -p
9.2 设置root密码
sql
-- 进入MySQL/MariaDB后
ALTER USER 'root'@'localhost' IDENTIFIED BY 'openweb123';
FLUSH PRIVILEGES; -- 刷新配置(必须执行)
- 注意:修改后必须刷新配置才能生效,不能只看系统提示"重置成功"
- 比喻:改了手机密码后,需要重启手机才能确保新密码真正生效
9.3 root无密码特性
-
现象:即使输入错误密码也能登录成功
-
原因:这是MariaDB/MySQL超级用户的设计特性
-
验证方法 (反向验证密码是否生效):
① 重启mariadb服务 ② 退出到普通用户 ③ 用错误密码尝试登录 mysql -u root -p - 被拒绝 → 密码设置成功 ④ 用正确密码登录验证 -
普通用户:必须正确输入密码才能访问数据库
9.4 数据库权限原则
-
root:最高权限,生产环境避免直接使用
-
生产环境 :遵循最小权限原则,创建专用用户
sqlCREATE USER 'webuser'@'localhost' IDENTIFIED BY 'password'; GRANT SELECT, INSERT, UPDATE ON dvwa.* TO 'webuser'@'localhost'; -
操作 → 验证:Linux系统管理的典型闭环思路
第10部分:权限问题与DVWA部署
10.1 403错误排查
-
原因一 :文件权限不足
- 检查:
ls -l login.php - 修复:
chmod 755 login.php
- 检查:
-
原因二 :文件所有者不匹配
-
nginx运行用户:nobody(通过
ps -aux | grep nginx查看) -
php运行用户:www-data
-
修复:
bashchown www-data:www-data login.php chmod 777 login.php # 临时测试用
-
-
原因三:缺少索引文件
10.2 500错误
- 含义:服务端配置问题
- 常见原因:Nginx配置错误、PHP-FPM未运行、.htaccess语法错误
10.3 DVWA部署步骤
bash
# 1. 将DVWA文件夹移动到html目录
mv DVWA-master /usr/local/nginx/html/dvwa
# 2. 复制配置文件
cd dvwa/config
cp config.inc.php.dist config.inc.php
# 3. 编辑配置文件
vim config.inc.php
# 修改数据库密码部分
# 4. 浏览器访问
# http://localhost/dvwa/setup.php
# 点击 Create/Reset Database
- 特别注意:实际部署时不要用root账户连接数据库,权限过高很危险
- 配置前备份 :
cp config.inc.php.dist config.inc.php.bak
10.4 数据库不存在问题
- 原因:代码里尝试连接名为"dvwa"的数据库,但这个数据库并不存在
- 解决 :需要先运行
setup.php文件进行初始化 - 注意:DVWA系统推荐使用MongoDB,MySQL虽然能运行但需调整命令
第11部分:PHP版本与Docker
11.1 多PHP版本管理
-
场景 :不同靶场对PHP版本要求不同
- 有些需要高版本
- 有些漏洞复现必须用低版本(如PHP5.6)
-
旧版本安装 :需要手动添加特殊源
- 常规源只提供新版本
- 404报错说明当前源不可用
- 需搜索解决方案(通过Ubuntu系统添加特定源)
-
update-alternatives :
bashupdate-alternatives --config php # 交互式选择要使用的PHP版本
11.2 Docker容器技术
-
核心价值:解决"在我机器上能跑,在你机器上就报错"的环境差异问题
-
本质:打包好的环境"盒子",把所有依赖装在一起
-
基础命令 :
bashdocker pull 镜像名 # 拉取镜像 docker images # 查看本地镜像 docker run 镜像名 # 运行容器 -
比喻:像网购一样搜索想要的镜像,找到就直接pull使用
-
适用场景:渗透测试不需要深入理解Docker底层原理,掌握基本命令即可
11.3 国内Docker使用
-
障碍:访问外网受限
-
解决方案一 :配置国内镜像加速器(阿里云、网易云等)
bash# 修改 /etc/docker/daemon.json { "registry-mirrors": ["https://你的加速器地址.mirror.aliyuncs.com"] } -
解决方案二 :设置VPN代理
- 单独给Docker配置VPN
- 或给整个Ubuntu系统设置永久VPN代理(修改
~/.bashrc)
11.4 源码编译Nginx与Systemd
- 直接运行 :
./nginx就行,不一定需要Systemd管理 - 如果需要systemctl控制 :需要准备对应的服务单元文件
.service - 操作建议:不要全盘照搬参考材料,有选择地参考
第12部分:网络配置与排错
12.1 NAT模式配置
-
核心要求 :虚拟机IP必须和主机VMnet8在同一网段
主机VMnet8: 192.168.x.x 虚拟机: 192.168.x.x(同一网段) -
后果:不在同一网段则网络完全不通
12.2 DNS设置
-
常见错误:设为 127.0.0.1(本地回环地址)
-
后果:apt update失败(解析不了域名)
-
正确做法 :
bash# 编辑 /etc/resolv.conf nameserver 8.8.8.8 nameserver 114.114.114.114
12.3 桥接模式
- 问题:桥接模式下使用手机热点上网需要特殊设置
- 排查步骤 :
- 确认连接方式(桥接/NAT)
- 检查IP地址配置
- 检查DNS设置
12.4 系统快照
- 重要性:操作前先建立快照,像给电脑拍个照片存档
- 好处:万一后续操作出问题,可以快速恢复到之前正常工作的状态
- 线上同学:也要遵循这个操作步骤
12.5 密码管理
- 常见混淆:把数据库密码当成系统密码
- 建议:不同系统的密码分开管理
- root账户:初始是没有密码的,需要自己后续设置
12.6 sudo su root
-
场景:普通用户登录后无法直接切换到root(因为root没密码)
-
命令 :
bashsudo su root # 输入当前普通用户的密码 -
前提:普通用户必须有sudo权限
二、面试题(详细版)
基础篇
Q1: Ubuntu系统安装后默认能直接用root登录吗?为什么?详细说明正确的登录流程。
A: 不能直接使用root登录。
原因 :
Ubuntu与红帽系Linux不同,安装时默认不会设置root密码,也没有引导用户设置root密码的环节。系统仅创建一个具有sudo权限的普通用户。
正确登录流程:
① 使用安装时创建的普通用户登录系统
② 打开终端,执行 sudo passwd root
③ 输入当前普通用户的密码(提权验证)
④ 设置root密码(需满足复杂度要求,如 openlab123)
⑤ 确认密码
⑥ 此后即可使用 su root 切换到root,或直接用root登录
注意事项:
Ctrl+Shift可以放大终端界面- 密码太简单(如 123456)会被系统拒绝
- 如果安装时跳过了root密码设置,后期只能通过
sudo passwd root强制修改
Q2: Ubuntu和红帽系Linux的防火墙管理命令有何不同?遇到服务启动失败时,应该按什么顺序排查?
A:
防火墙区别:
| 项目 | Ubuntu | 红帽系(CentOS/RHEL) |
|---|---|---|
| 管理工具 | ufw |
firewalld |
| 关闭命令 | systemctl stop ufw |
systemctl stop firewalld |
| 禁用命令 | systemctl disable ufw |
systemctl disable firewalld |
服务启动失败排查顺序(由外到内):
① 服务状态检查 → systemctl status 服务名
② 日志查看 → journalctl -xe 或查看 /var/log/
③ 防火墙检查 → 是否拦截了服务端口
④ SELinux检查 → getenforce / setenforce 0
⑤ 端口占用检查 → ss -antulp | grep 端口号
⑥ 配置文件检查 → 参数格式、语法错误、注释符号
Q3: 如何修改SSH配置允许root远程登录?请写出完整的操作步骤和每个步骤的注意事项。
A:
操作步骤:
bash
# 步骤1:编辑SSH配置文件
vim /etc/ssh/sshd_config
-
注意:P大写!是
PermitRootLogin不是Permitrootlogin步骤2:找到参数并修改
默认内容:PermitRootLogin no
修改为:PermitRootLogin yes
-
在vim中可以用
:/PermitRootLogin快速查找步骤3:保存退出
:wq
-
如果修改出错,用
:q!强制不保存退出
bash
# 步骤4:重启SSH服务使配置生效
systemctl restart sshd
- 这是最关键也最容易遗漏的步骤!
bash
# 步骤5:验证配置
systemctl status sshd
# 查看状态应为 active (running)
注意事项:
- 默认不允许root远程登录是出于安全考虑
- 生产环境要谨慎修改此配置
- 如果修改后仍无法登录,检查防火墙是否放行了22端口
- 普通用户能远程连接不代表root用户也能连,需要单独测试
Q4: 请完整写出源码安装Nginx的全流程,包括验证步骤和常见问题的解决方法。
A:
完整流程(三步走):
bash
# ---- 第一步:准备工作 ----
tar -xvf nginx-1.24.0.tar.gz # 解压
cd nginx-1.24.0 # 进入目录
apt install gcc make wget # 安装编译工具
# ---- 第二步:配置(检查环境)----
./configure --prefix=/usr/local/nginx
执行后观察终端输出,出现配置摘要信息才表示检测完成。如果提示缺少pcre库:
bash
apt install pcre* libpcre3 libpcre3-dev
apt install zlib1g-dev # 可能还需要zlib
重新执行 ./configure 直到没有error。
bash
# ---- 第三步:编译与安装 ----
make # 编译(不报错即可继续)
make install # 安装到指定目录
验证步骤:
bash
cd /usr/local/nginx/sbin
./nginx
curl 127.0.0.1
看到包含 "thank you for using nginx" 的HTML响应即成功。
常见问题:
| 问题 | 原因 | 解决方法 |
|---|---|---|
| configure报错 | 缺少依赖 | apt install 对应库 |
| make报错 | 环境问题或版本不兼容 | 检查gcc版本,清理重新编译 |
| nginx启动失败 | 端口被占用 | `ss -antulp |
| curl无响应 | nginx未启动或防火墙拦截 | 检查nginx进程和防火墙状态 |
Q5: tar命令解压不同压缩格式时参数有何区别?请列举常用组合并说明参数含义。
A:
常用命令组合:
bash
tar -xzvf 文件名.tar.gz # 解压 gzip 格式 (.tar.gz / .tgz)
tar -xjvf 文件名.tar.bz2 # 解压 bzip2 格式 (.tar.bz2)
tar -xJvf 文件名.tar.xz # 解压 xz 格式 (.tar.xz)
tar -xvf 文件名.tar # 解压普通 tar 包(无压缩)
参数含义:
| 参数 | 含义 | 说明 |
|---|---|---|
-x |
extract | 解压模式 |
-z |
gzip | 处理 .gz 格式(对应gzip压缩) |
-j |
bzip2 | 处理 .bz2 格式(对应bzip2压缩) |
-J |
xz | 处理 .xz 格式 |
-v |
verbose | 显示解压过程 |
-f |
file | 指定文件名(必须放在最后一个参数) |
创建压缩包:
bash
tar -czvf 归档名.tar.gz /要压缩的目录 # 创建gzip压缩
tar -cjvf 归档名.tar.bz2 /要压缩的目录 # 创建bzip2压缩
易混淆点:
-G(大写)用于gzip旧版本,而不是普通的gzip解压-g(小写)是处理旧版格式,完全不同- 虽然系统有时能自动识别,但显式指定参数更可靠
Q6: Nginx为何无法直接解析PHP文件?请详细说明LNMP架构下一次PHP请求的完整处理流程。
A:
原因 :
Nginx本身是一个Web服务器和反向代理服务器,它只擅长处理静态文件(HTML、CSS、JS、图片等)。它不包含PHP解析器 ,所以遇到 .php 文件时不知道如何执行,只能直接返回源码,导致浏览器误以为要下载文件。
完整处理流程:
① 用户在浏览器输入 http://服务器IP/index.php
② 请求到达Nginx
③ Nginx根据配置文件(nginx.conf)检查请求的文件类型
④ 发现是 .php 文件 → 根据 location ~ \.php$ 配置段进行处理
⑤ Nginx通过 fastcgi_pass 指令将请求转发给 php-fpm(默认 127.0.0.1:9000)
⑥ php-fpm 接收到请求,启动PHP解析器执行PHP代码
⑦ PHP代码中如果包含数据库操作,通过MySQL/MariaDB扩展连接数据库
⑧ PHP执行完成,将结果(HTML内容)返回给Nginx
⑨ Nginx将最终响应返回给客户端浏览器
配置要点(nginx.conf中):
nginx
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
关键 :$document_root$fastcgi_script_name 路径配置必须正确,否则找不到PHP文件。
进阶篇
Q7: MariaDB中设置root密码后如何确认密码已生效?请详细说明"反向验证法"的原理和步骤。
A:
问题背景:MariaDB的root用户有特殊权限,即使输入错误密码有时也能登录,所以普通的"设置后立刻登录验证"不可靠。
反向验证法:
步骤1:重启MariaDB服务
systemctl restart mariadb
步骤2:退出root用户,切换到普通用户
exit # 退出数据库
su - 普通用户名
步骤3:用错误密码尝试登录
mysql -u root -p
输入错误密码(如 wrongpassword)
结果分析:
- 被拒绝(Access denied)→ ✅ 密码设置成功
- 成功登录 → ❌ 密码未生效,需要重新设置
步骤4:用正确密码登录验证
mysql -u root -p
输入正确密码
看到 MariaDB [(none)]> 提示符 → ✅ 一切正常
核心原理:
- root用户有绕过密码验证的设计特性
- 重启服务可以刷新认证缓存
- 普通用户没有绕过密码的特权
- 用错误密码测试,如果被拒说明安全机制正常启用
注意事项:
sql
-- 正确的密码设置命令
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
FLUSH PRIVILEGES; -- 必须执行刷新!
Q8: 当Linux系统中的一个服务无法启动时,请写出完整的系统性排查思路和对应的命令。
A:
系统性排查流程(从易到难):
bash
# 第1步:查看服务状态
systemctl status 服务名
# 关注:active/exited/failed,以及最后几行日志
# 第2步:查看详细日志
journalctl -xe # 最近的系统日志
journalctl -u 服务名 # 该服务的所有日志
journalctl -u 服务名 --no-pager # 不分页显示全部
tail -f /var/log/syslog # 实时查看系统日志
# 第3步:检查网络端口
ss -antulp | grep 端口号 # 端口是否被占用
lsof -i :端口号 # 哪个进程占用了端口
# 第4步:检查防火墙
# Ubuntu
systemctl status ufw
ufw status
# 红帽系
systemctl status firewalld
firewall-cmd --list-all
# 第5步:检查SELinux(红帽系)
getenforce # 查看SELinux状态
setenforce 0 # 临时关闭(测试用)
# 查看SELinux是否阻止了服务
grep "SELinux" /var/log/messages
audit2why < /var/log/audit/audit.log
# 第6步:检查配置文件语法
nginx -t # 检查nginx配置
sshd -t # 检查ssh配置
php-fpm -t # 检查php-fpm配置
# 第7步:检查依赖和权限
ldd /usr/sbin/服务名 # 检查动态库依赖
ls -l /etc/服务名/配置文件 # 检查文件权限
ps -aux | grep 服务名 # 查看运行用户身份
经典案例:
- SSH启动失败 → 检查22端口是否被占用,防火墙是否拦截
- Nginx启动失败 →
nginx -t检查配置语法 - MySQL启动失败 → 检查
/var/log/mysql/error.log
Q9: 源码安装的Nginx和apt安装的Nginx在管理方式上有何不同?如何重载配置?为什么存在差异?
A:
管理方式对比:
| 操作 | 源码安装 | apt安装 |
|---|---|---|
| 启动 | /usr/local/nginx/sbin/nginx |
systemctl start nginx |
| 停止 | /usr/local/nginx/sbin/nginx -s stop |
systemctl stop nginx |
| 重载 | /usr/local/nginx/sbin/nginx -s reload |
systemctl reload nginx |
| 查看状态 | `ps -aux | grep nginx` |
| 配置文件路径 | /usr/local/nginx/conf/nginx.conf |
/etc/nginx/nginx.conf |
| 网站根目录 | /usr/local/nginx/html |
/var/www/html |
为什么存在差异:
- 源码安装的本质是手动编译并复制文件到指定目录,不会注册到systemd
- apt安装的包在安装时会自动创建
.service单元文件到/lib/systemd/system/ - systemd管理的服务可以用
systemctl统一控制 - 源码安装更灵活但需要手动管理
给源码安装配置systemd服务(可选):
bash
vim /etc/systemd/system/nginx.service
写入:
[Unit]
Description=nginx service
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s quit
PrivateTmp=true
[Install]
WantedBy=multi-user.target
bash
systemctl daemon-reload # 重新加载systemd
systemctl enable nginx # 设为开机自启
Q10: Nginx返回403 Forbidden错误的可能原因有哪些?请逐一说明排查方法和解决命令。
A:
| 可能原因 | 排查方法 | 解决命令 |
|---|---|---|
| 1. 文件权限不足 | ls -l 文件路径 查看权限 |
chmod 755 文件路径 |
| 2. 目录权限不足 | Nginx需要目录有执行权限 | chmod 755 目录路径 |
| 3. 索引文件缺失 | 检查 nginx.conf 的 index 配置 | index index.php index.html; 或创建文件 |
| 4. 用户身份不匹配 | `ps -aux | grep nginx` 看运行用户 |
| 5. SELinux限制 | getenforce 查看状态 |
setenforce 0 或配置安全上下文 |
| 6. .htaccess限制 | 检查目录下是否有.htaccess | 删除或修改.htaccess内容 |
| 7. 根目录配置错误 | 检查 nginx.conf 的 root 路径 | 修正 root 指向真实存在的目录 |
详细排查示例:
bash
# 查看nginx运行用户
ps -aux | grep nginx
# 输出类似: nobody 1234 ... nginx: worker process
# 检查文件属主
ls -l /usr/local/nginx/html/index.php
# 如果显示 -rw-r--r-- root root,而nginx用nobody运行 → 权限不匹配
# 修复
chown -R nobody:nobody /usr/local/nginx/html/
chmod -R 755 /usr/local/nginx/html/
# 测试配置
nginx -t
# 重载
./nginx -s reload
Q11: 在Vim编辑器中,如何批量删除多行注释符号?请写出完整的操作步骤并解释每个命令的含义。
A:
场景 :在nginx.conf或php-fpm配置文件中,有很多被 # 注释掉的行需要批量取消注释。
操作步骤:
vim
# 步骤1:显示行号,方便定位
:set number
" 或简写 :set nu
" 文件左侧会显示行号
# 步骤2:定位到需要操作的行
" 用 :65 跳转到第65行
# 步骤3:批量删除指定范围的注释
:65,71s/#//g
命令解析:
: 进入命令行模式
65,71 范围(从65行到71行)
s 替换命令(substitute)
/ 分隔符
# 要查找的字符(#号)
/ 分隔符
替换为空(两个斜杠之间为空,即删除)
g 全局(global),一行中所有匹配都替换
更多Vim批量操作:
vim
# 删除整个文件的#号
:%s/#//g
# 删除每行开头的#号(只删第一个)
:%s/^#//
# 删除每行开头的#号和后面的空格
:%s/^#\s*//
# 在行首添加注释
:65,71s/^/#
# 批量替换端口号
:%s/9000/9001/g
注意事项:
- 有些配置文件(如php-fpm的www.conf)用
;分号注释,不是# - 操作前最好先备份原文件:
:w 文件名.bak - 如果替换错误,用
u撤销
Q12: 当你记得配置文件中包含某个关键词(如"9000"),但忘记了文件的具体路径时,应该如何快速定位?
A:
最佳方法:使用 grep 递归搜索
bash
# 基础命令
grep -r "9000" /etc/
# 显示行号,便于查看上下文
grep -rn "9000" /etc/
# 显示匹配内容前后各2行
grep -r -B2 -A2 "9000" /etc/
# 只搜索 .conf 文件
grep -rn "9000" /etc/ --include="*.conf"
# 排除二进制文件
grep -rn "9000" /etc/ --exclude="*.log"
参数解释:
| 参数 | 作用 |
|---|---|
-r |
递归搜索子目录 |
-n |
显示匹配行号 |
-B2 |
显示匹配行前2行(before) |
-A2 |
显示匹配行后2行(after) |
--include |
只搜索指定类型文件 |
--exclude |
排除指定类型文件 |
加速技巧:
bash
# 如果知道大概范围,缩小搜索目录
grep -rn "fastcgi_pass" /usr/local/
# 多关键词搜索
grep -rn "9000" /etc/ | grep -i php
# 结合find使用
find /etc/ -name "*.conf" -exec grep -l "9000" {} \;
常见易错点:
- 搜索内容必须在命令最后(容易犯的错误是把路径写在-r后面)
- 用双引号包裹搜索内容,防止特殊字符被shell解释
Q13: PHPStudy中MySQL服务启动失败的可能原因有哪些?请逐一分析并提供排查方法。
A:
| 序号 | 原因 | 现象 | 排查与解决 |
|---|---|---|---|
| 1 | 参数格式错误 | 服务反复启停 | 检查配置文件中的参数是否为标准 "--参数名" 格式 |
| 2 | 多数据库冲突 | 启动报错参数冲突 | 之前是否装过MongoDB或其他版本MySQL?卸载冲突软件 |
| 3 | 端口被占用 | 提示端口已使用 | `netstat -ano |
| 4 | 配置文件语法错误 | 提示配置项不认识 | 检查my.ini/my.cnf是否有拼写错误 |
| 5 | 日志文件过大 | 启动失败日志满 | 清空或删除日志文件 |
| 6 | 权限不足 | 提示拒绝访问 | 以管理员身份运行PHPStudy |
| 7 | 数据文件损坏 | 启动后立即崩溃 | 查看错误日志,修复或重建表 |
核心排查思路:
① 查看PHPStudy的错误日志(最关键!)
② 日志中会明确提示"参数问题"还是"端口问题"
③ 不要轻信免费AI工具的诊断(可能误判)
④ 推荐使用GLM等可靠工具,结构化提问
提问模板(使用AI工具时):
"分析我的PHPStudy中MySQL服务异常启动的原因,是否由于以下问题:......(描述你的具体情况)"
Q14: 用普通用户SSH登录Linux服务器后,为什么即使su切换到root也无法向/opt等目录上传文件?
A:
原因分析 :
SSH会话的文件传输权限取决于初始登录用户的身份,而不是当前切换到的用户。
初始SSH登录:普通用户(如 ubuntu)
↓
执行 su root 切换到root(当前shell用户变了)
↓
尝试 sftp/scp 上传文件到 /opt
↓
失败!因为sftp/scp使用的是原始SSH连接的用户身份
本质原因:
- SSH服务(sshd)在建立连接时,会根据登录用户创建对应的sftp子系统
- 即使当前shell切换到root,sftp传输通道仍然使用初始用户的权限
/opt目录需要root权限才能写入,普通用户无权限
解决方案:
bash
# 方案1:直接用root远程登录(需要先配置ssh允许root登录)
ssh root@服务器IP
# 方案2:使用sftp配合正确的用户
sftp root@服务器IP
# 方案3:上传到有权限的目录,再通过sudo移动
scp 文件 ubuntu@服务器IP:/home/ubuntu/
ssh ubuntu@服务器IP
sudo mv /home/ubuntu/文件 /opt/
# 方案4:修改目标目录权限(不推荐)
sudo chmod 777 /opt
Q15: 在Ubuntu上安装旧版本PHP(如PHP 5.6)时通常会遇到什么问题?如何解决多PHP版本共存的问题?
A:
常见问题:
- 404报错:默认软件源已移除旧版本,找不到对应包
- 依赖冲突:旧版本与已安装的新版本依赖库冲突
- 源配置错误:手动添加的特殊源不可用或地址已变更
解决方案:
bash
# 步骤1:添加旧版PHP的PPA源
apt install software-properties-common
add-apt-repository ppa:ondrej/php
apt update
# 步骤2:搜索可用版本
apt list | grep php5.6
# 步骤3:安装指定版本
apt install php5.6 php5.6-fpm php5.6-mysql
# 步骤4:使用update-alternatives切换版本
update-alternatives --config php
# 交互式选择默认使用的PHP版本
# 手动切换php-fpm
systemctl stop php8.1-fpm
systemctl start php5.6-fpm
多版本管理:
bash
# 查看已安装的PHP版本
ls /usr/bin/php*
# 查看当前PHP版本
php -v
# 为不同网站指定不同PHP版本(在nginx配置中)
fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;
# 或
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
注意事项:
- AI给出的源配置方法可能不准确,需要自己验证
- 不同靶场对PHP版本要求可能截然相反
- 安装旧版本前确认是否有安全风险
原理篇
Q16: 什么是源码安装?与包管理器安装相比各有何优缺点?请从灵活性、依赖性、管理难度三个维度对比。
A:
源码安装 :下载软件的源代码(通常是 .tar.gz 压缩包),在本地编译后安装的过程。
三维度对比:
| 维度 | 源码安装 | 包管理器安装(apt/yum) |
|---|---|---|
| 灵活性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
可自定义安装路径(--prefix) |
安装路径固定 | |
| 可选择开启/关闭特定模块 | 通常为默认模块集合 | |
| 可指定编译参数优化性能 | 按发行版预设参数编译 | |
| 依赖性 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 手动解决每个依赖 | 自动下载并安装所有依赖 | |
| 需了解底层依赖关系 | 依赖关系由包管理器维护 | |
| 报错需自行排查 | 报错极少(仓库已验证) | |
| 管理难度 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 无统一管理命令 | apt update/install/remove 统一管理 |
|
| 需手动卸载、清理 | 一键卸载并清理配置 | |
| 需要知道安装目录 | 文件分散在系统标准位置 | |
| 升级需重新编译 | apt upgrade 一键升级 |
适用场景:
源码安装 → 需要深度定制、优化性能、特殊路径
包管理器 → 常规使用、快速部署、新手友好
Q17: MariaDB/MySQL中,root用户作为最高权限管理员,为什么有时即使输入错误密码也能登录?如何确保生产环境的数据库安全?
A:
root密码验证绕过的原因:
sql
# MariaDB默认认证插件
SHOW VARIABLES LIKE 'default_authentication_plugin';
-- 可能输出 unix_socket 或 mysql_native_password
# 当使用 unix_socket 插件时:
-- root用户通过操作系统用户身份验证
-- 只要当前Linux用户是root,就可以直接登录
-- 不需要输入密码(或任意密码都可以)
bash
# 演示
sudo mysql -u root # 不需要 -p 参数就能登录
生产环境数据库安全配置:
sql
-- 1. 修改root认证方式为密码认证
ALTER USER 'root'@'localhost'
IDENTIFIED WITH mysql_native_password BY '强密码';
-- 2. 创建专属应用用户(最小权限原则)
CREATE USER 'webapp'@'localhost' IDENTIFIED BY '应用密码';
GRANT SELECT, INSERT, UPDATE, DELETE ON 数据库名.* TO 'webapp'@'localhost';
FLUSH PRIVILEGES;
-- 3. 远程访问限制
-- 只允许本地连接,禁止root远程登录
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1');
-- 4. 删除默认数据库
DROP DATABASE IF EXISTS test;
-- 5. 设置密码策略
SET GLOBAL validate_password_length = 12;
SET GLOBAL validate_password_policy = STRONG;
安全原则总结:
- root仅限本地管理使用
- 每个应用创建独立数据库用户
- 权限最小化(只给需要的权限)
- 定期更换密码
- 开启日志审计
Q18: Docker是如何解决"在我机器上能跑,在你机器上报错"这一经典问题的?请从镜像原理和隔离机制两个角度解释。
A:
问题本质:应用程序的运行依赖操作系统、运行环境、库文件、配置等,不同机器的环境差异(如操作系统版本不同、依赖库缺失、配置不一致)导致程序行为不同。
Docker的解决方案:
一、镜像原理(打包一切)
传统部署:
源代码 + 依赖说明文档 → 部署人员手动配置环境 → ❌ 容易出错
Docker部署:
源代码 + 所有依赖(库/配置文件/环境变量) → 打包成镜像 → 直接运行
Docker镜像是一个分层构建的只读模板:
┌─────────────────────────┐
│ 应用层(你的PHP代码) │ ← 可写层
├─────────────────────────┤
│ PHP 8.0 + 扩展 │ ← 基础镜像层
├─────────────────────────┤
│ Ubuntu 22.04 │ ← 操作系统层
├─────────────────────────┤
│ Linux Kernel(宿主机) │ ← 共享宿主内核
└─────────────────────────┘
二、隔离机制(互不干扰)
Docker使用Linux内核的命名空间(Namespace)技术实现隔离:
进程隔离:PID Namespace → 容器内看不到宿主机其他进程
网络隔离:Network Namespace → 容器有独立IP和端口空间
文件隔离:Mount Namespace → 容器有独立文件系统
用户隔离:User Namespace → 容器内root ≠ 宿主机root
核心优势:
bash
# 在任何机器上,只需三步
docker pull nginx:1.24 # 拉取镜像
docker run -d -p 80:80 nginx # 运行容器
# 环境完全一致,不会报错
# 查看本地镜像
docker images
对比传统VM:
| 特性 | Docker | 虚拟机 |
|---|---|---|
| 启动速度 | 秒级 | 分钟级 |
| 资源占用 | 小(共享内核) | 大(完整OS) |
| 镜像大小 | MB级 | GB级 |
| 环境一致性 | 高(镜像不可变) | 中(可修改) |
Q19: 在国内使用Docker拉取镜像时常遇到什么问题?请给出所有可行的解决方案并比较优劣。
A:
核心问题 :Docker Hub官方仓库位于国外,国内网络访问受限,导致 docker pull 超时或极慢。
解决方案对比:
| 方案 | 操作难度 | 稳定性 | 速度 | 适用场景 |
|---|---|---|---|---|
| ① 配置镜像加速器 | ⭐ 低 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 推荐首选 |
| ② 设置VPN代理 | ⭐⭐⭐ 中 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 长期使用 |
| ③ 手动导出导入 | ⭐⭐⭐⭐ 高 | ⭐⭐⭐⭐⭐ | 取决于传输 | 离线环境 |
| ④ 使用替代仓库 | ⭐⭐ 中 | ⭐⭐⭐ | ⭐⭐⭐ | 特定镜像 |
方案一:配置镜像加速器(推荐)
bash
# 编辑 /etc/docker/daemon.json
{
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://mirror.ccs.tencentyun.com",
"https://你的阿里云加速器地址.mirror.aliyuncs.com"
]
}
# 重启Docker
systemctl daemon-reload
systemctl restart docker
# 验证
docker info | grep Mirrors
方案二:设置VPN代理
bash
# 方法A:Docker客户端代理(仅影响docker pull)
mkdir -p ~/.docker
vim ~/.docker/config.json
{
"proxies": {
"default": {
"httpProxy": "http://代理IP:端口",
"httpsProxy": "http://代理IP:端口",
"noProxy": "localhost,127.0.0.1"
}
}
}
# 方法B:系统级代理(全局生效)
vim ~/.bashrc
export http_proxy="http://代理IP:端口"
export https_proxy="http://代理IP:端口"
source ~/.bashrc
方案三:离线传输
bash
# 在有网络的机器上
docker pull nginx
docker save nginx -o nginx.tar
# 传输到目标机器
scp nginx.tar root@目标IP:/root/
# 在目标机器上
docker load -i nginx.tar
Q20: 请详细描述LNMP架构中,从用户在浏览器输入URL到页面完全加载的完整请求处理流程,要求说明每个环节的作用和涉及的协议/组件。
A:
架构总览:
用户浏览器 ←→ Nginx(Web服务器)←→ PHP-FPM(PHP解析器)←→ MariaDB/MySQL(数据库)
完整流程(7个环节):
第1步:DNS解析
用户输入 http://example.com/index.php
→ 浏览器向DNS服务器查询域名对应的IP地址
→ DNS返回服务器IP(如 192.168.50.158)
→ 协议:DNS(UDP/53)
第2步:建立TCP连接
→ 浏览器与服务器IP:80 建立TCP三次握手
→ 协议:TCP/IP
→ 如果使用HTTPS,还需要TLS握手
第3步:发送HTTP请求
→ 浏览器发送HTTP GET请求
→ 请求头包含:Host、User-Agent、Accept等
→ 协议:HTTP/1.1 或 HTTP/2
第4步:Nginx接收请求
→ Nginx监听80端口,接收HTTP请求
→ 根据server_name匹配虚拟主机
→ 根据请求URI匹配location规则
→ 发现是 .php 文件,进入 PHP 处理流程
第5步:Nginx转发给PHP-FPM
→ Nginx通过 fastcgi_pass 将请求转发到 127.0.0.1:9000
→ 传递参数:SCRIPT_FILENAME、QUERY_STRING等
→ 协议:FastCGI(基于TCP或Unix Socket)
第6步:PHP-FPM执行PHP代码
→ PHP-FPM的worker进程接收FastCGI请求
→ 加载PHP文件并执行
→ 如果代码中有数据库操作:
a. PHP通过mysqli/pdo_mysql扩展连接MariaDB (127.0.0.1:3306)
b. 发送SQL查询语句
c. MariaDB执行查询并返回结果集
d. PHP处理结果并生成HTML
→ PHP执行完毕,将生成的HTML返回给Nginx
第7步:Nginx返回响应
→ Nginx接收PHP-FPM返回的HTML内容
→ 加上HTTP响应头(Content-Type、Content-Length等)
→ 通过TCP连接返回给浏览器
→ 浏览器解析HTML,加载CSS/JS/图片等资源
→ 页面渲染完成
流程图解:
┌──────┐ HTTP ┌────────┐ FastCGI ┌─────────┐ SQL ┌─────────┐
│ 用户 │ ←───────→ │ Nginx │ ←───────→ │ PHP-FPM │ ←───→ │ MariaDB │
│ 浏览器 │ │ :80 │ │ :9000 │ │ :3306 │
└──────┘ └────────┘ └─────────┘ └─────────┘
↓
静态文件(HTML/CSS/JS)
直接返回,不经PHP
性能优化关键点:
- Nginx开启FastCGI缓存,减少PHP请求
- PHP-FPM调整进程数(pm.max_children)
- MariaDB开启查询缓存
- 静态文件使用CDN或浏览器缓存