news 2026/9/14 18:00:20

LNMP架构详解:Nginx与PHP-FPM动静分离配置实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LNMP架构详解:Nginx与PHP-FPM动静分离配置实战

作为Nginx系列文章的第三篇,这篇我打算把LNMP从零到能跑完整拆一遍。前两篇聊过Nginx的基础配置和虚拟主机玩法,但很多朋友在真正部署PHP项目时还是卡壳:要么是PHP-FPM与Nginx对接不上,返回502;要么是静态图片和JS请求全部打到动态解析上,服务器CPU直接飘高。这些问题归根结底,其实就两件事没想明白——LNMP各组件之间到底怎么协作,以及动静分离究竟在分什么。

这篇文章会以一套生产可用的LNMP环境为例,从组件选型、安装配置、站点搭建到动静分离规则逐一讲解。文中的所有配置我都实际跑过,适合已经熟悉Nginx基本指令、准备部署PHP站点的读者,也适合那些照抄过网上配置但不知道为什么要这么写的朋友。看完之后,你能独立完成一套LNMP环境搭建,并搞清楚Nginx、PHP-FPM、MySQL三者之间的请求流转逻辑。

1. LNMP的整体架构设计与选型思路

1.1 为什么是LNMP而不是LAMP

LNMP指的是Linux、Nginx、MySQL、PHP这套组合,和传统的LAMP(Apache替代Nginx)相比,最大的区别在PHP的执行方式上。

Apache时代最常见的PHP运行方式是mod_php,直接把PHP解释器以模块形式嵌入Apache进程内部。这种方式的好处是配置简单,但缺点也很明显:Apache进程为了处理一个PHP请求,必须常驻一个完整的PHP解释器,内存占用高,并发一上来就容易把机器拖垮。

Nginx天生是事件驱动的异步架构,处理静态文件和反向代理非常高效,但它自己并不直接执行PHP代码。Nginx遇到PHP请求时,会把请求通过FastCGI协议转交给PHP-FPM进程管理器,由PHP-FPM启动PHP子进程来执行脚本,再把结果返回给Nginx。这个模型下,Nginx只负责流量分发和静态资源响应,PHP-FPM按需启动固定数量的子进程,资源利用率比mod_php高得多。

另一个现实原因是动静分离的天然契合。Nginx对静态文件的处理效率极高,而PHP-FPM专注于动态脚本,两者各司其职。你在Nginx里通过不同location规则,把静态请求和动态请求分流,这就是动静分离的核心思想。后面我会专门讲配置实现,这里先建立这个整体认知。

1.2 组件版本选择的几个关键考虑

组件版本选择直接影响后续维护成本,我的建议是“能用系统源就用系统源,追求新版本再编译”。

操作系统方面,以Debian/Ubuntu或CentOS系为主流。我在生产环境用得最多的是Ubuntu Server LTS和Debian稳定版,apt源里的Nginx、PHP、MySQL版本虽然不一定最新,但经过了发行版测试,依赖关系完整,升级路径清晰。CentOS系的yum源同理。除非你确实需要Nginx最新主线版或者PHP 8.3以上的特殊特性,否则没必要一上来就编译安装。

Nginx版本选择上,稳定版(stable)和主线版(mainline)的区别在于新功能推出速度。生产环境我习惯用主线版,因为Nginx主线版的稳定性实际上已经足够好,而且修复安全漏洞更及时。Ubuntu源默认版本可能略旧,但用于学习完全没问题。

MySQL方面,建议直接上MySQL 8.x或者MariaDB 10.x。MySQL 8默认字符集是utf8mb4,对中文支持更友好,身份认证插件和缓存策略也做了很多优化。如果公司有Oracle授权顾虑,MariaDB作为完全兼容的替代品也很成熟,LNMP组合里两者都可以用。

PHP版本建议PHP 7.4以上,目前主流的PHP 8.x在性能和类型安全上有明显提升。如果你只是学习搭建,apt安装默认版本即可;如果要跑老项目,注意PHP版本的兼容性,特别是旧框架对PHP 8的语法支持可能存在问题。

1.3 动静分离的工作模型

动静分离本质上是一种基于请求类型的路由策略。以最常见的PHP站点为例,用户的浏览器发起请求,Nginx收到之后会做一次分类:

  • 如果请求的是静态资源,比如图片、CSS、JavaScript、字体文件,Nginx直接从磁盘读取文件返回,不经过PHP-FPM。
  • 如果请求的是PHP脚本,比如访问index.php、api.php,Nginx通过FastCGI协议转发给PHP-FPM,PHP执行完再把HTML或JSON返回给浏览器。

这个分类过程由Nginx配置文件中的location匹配规则完成。动态请求通常是匹配以.php结尾的URI,静态请求则是匹配常见的静态文件扩展名。

理解动静分离的好处得从反向代理的角度看。Nginx在这里扮演的是一个反向代理服务器的角色,它屏蔽了后端多台应用服务器的细节,对外只暴露一个入口。这样做不仅能让静态资源响应更快,更关键的是减轻了PHP-FPM的压力。我见过不少运维事故,明明站点访问量不大,但PHP-FPM进程全部被占满,查下来发现是几万个图片请求全部打到了动态解析上,每个图片请求都白白消耗了一个PHP子进程的CPU和内存。动静分离合理配置之后,这类问题基本不会出现。

2. 核心组件安装:从零把三件套跑起来

2.1 Nginx的安装与最小配置

我用Ubuntu 22.04为例演示,其他发行版命令类似。先更新软件源并安装Nginx:

sudo apt update sudo apt install nginx -y

安装完成后,Nginx的配置文件目录结构是:

  • /etc/nginx/nginx.conf:主配置文件
  • /etc/nginx/sites-available/:站点配置(可用)
  • /etc/nginx/sites-enabled/:站点配置(启用)
  • /etc/nginx/conf.d/:额外配置片段
  • /var/log/nginx/access.log 和 error.log:日志

主配置里有几个参数需要关注。worker_processes建议设为CPU核心数,可以通过lscpu查看;worker_connections表示每个worker进程能同时保持的最大连接数,默认1024,并发大的场景可以适当调高。静态文件的高效处理依赖sendfile on、tcp_nopush on这两个指令,配置里默认就带,不要去掉。

创建一个站点配置前,先确认你的网站根目录存在并且权限正确。我习惯把站点根目录放在/var/www下,比如/var/www/example:

sudo mkdir -p /var/www/example sudo chown -R $USER:$USER /var/www/example

最小的server块长这样:

server { listen 80; server_name example.com www.example.com; root /var/www/example; index index.php index.html; location / { try_files $uri $uri/ =404; } }

用nginx -t检查配置语法,没问题就systemctl reload nginx。

如果你需要编译安装,核心参数大概是这样(注意这只是关键参数的示意,并非完整命令):

./configure --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_gzip_static_module \ --with-http_v2_module \ --with-http_realip_module

编译安装的优势是版本可控、模块可裁,但对大多数场景来说,系统源安装已经够用,不必额外折腾。

2.2 MySQL的安装与初始化

MySQL安装同样简单:

sudo apt install mysql-server -y

安装完成后MySQL服务会自动启动,但默认的root账号几乎没什么密码策略,建议立即执行安全初始化脚本:

sudo mysql_secure_installation

这个脚本会引导你设置root密码、删除匿名用户、禁止root远程登录、删除测试数据库。生产环境建议全部选是。

接下来创建一个给PHP站点使用的业务数据库和用户。以数据库名appdb、用户名appuser为例:

CREATE DATABASE appdb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'appuser'@'localhost' IDENTIFIED BY '这里写一个强密码'; GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost'; FLUSH PRIVILEGES;

我用utf8mb4而不用老的utf8,是因为utf8mb4是完整的Unicode实现,能存emoji和生僻字;老utf8在MySQL里其实是utf8mb3,遇到四字节字符会报错。这个坑在早期项目里太常见了。

MySQL 8默认的认证插件是caching_sha2_password,PHP的mysqli和PDO扩展在PHP 7.4以上版本都支持,不用担心兼容问题。如果遇到老版本PHP连不上MySQL 8,可以考虑在CREATE USER时指定mysql_native_password,但更推荐升级PHP版本而不是降低安全标准。

2.3 PHP与PHP-FPM的安装与配置

PHP本身只是一个命令行解释器,真正和Nginx协作的是PHP-FPM。安装命令:

sudo apt install php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip -y

我安装的扩展基本覆盖了绝大多数Web项目的需求:php-mysql负责连库,php-gd处理图片,php-mbstring处理多字节字符串,php-xml和php-zip在Composer安装依赖时基本是必需品。

安装完成后,PHP-FPM的配置文件在/etc/php/版本号/fpm/目录下,核心是php.ini和pool.d/www.conf。php.ini里有几个参数建议调整:

upload_max_filesize = 64M post_max_size = 68M memory_limit = 256M max_execution_time = 60

这些参数的关系是:post_max_size必须大于upload_max_filesize,否则大文件上传会被截断;memory_limit要大于脚本实际内存峰值,否则会报Allowed memory size exhausted。

再说pool配置,也就是www.conf,这里面的listen参数决定了Nginx如何找到PHP-FPM:

listen = /run/php/php8.1-fpm.sock listen.owner = www-data listen.group = www-data listen.mode = 0660 user = www-data group = www-data

关键点在于listen用的是Unix Socket而不是127.0.0.1:9000。两者都能工作,但同机部署时我强烈推荐Unix Socket:它走的是内核进程间通信,没有TCP协议栈的开销,延迟更低,也避免了端口被外部扫描的风险。使用Socket时,必须要保证Nginx的worker进程(通常是www-data用户)有权限访问这个Socket文件,这就是listen.owner和listen.group要设成和Nginx一致的原因。

进程管理模式用pm = dynamic即可,max_children的数值需要根据服务器内存估算。一个PHP-FPM子进程大约占用30-60MB内存,2GB内存的机器建议max_children设为20-30,别贪多,进程数超过物理内存反而会因为swap导致性能雪崩。

3. 动静分离的配置实战:Nginx站点配置全拆解

3.1 一个完整的server配置

组件全都装好之后,就到了最关键的一步——写Nginx站点配置,把动静分离落地。下面这个配置是我在生产环境使用过的一个完整示例:

server { listen 80; server_name example.com; root /var/www/example; index index.php index.html; # 动态请求:所有以 .php 结尾的URI交给PHP-FPM location ~ \.php$ { include fastcgi_params; fastcgi_pass unix:/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_index index.php; fastcgi_read_timeout 60; } # 静态资源:图片、CSS、JS等直接由Nginx处理 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?|ttf|eot)$ { expires 30d; add_header Cache-Control "public, no-transform"; access_log off; } # 默认规则:处理无后缀的请求 location / { try_files $uri $uri/ /index.php?$query_string; } }

这个配置里一共有三组location规则,分别对应动态请求、静态资源和根路径请求。Nginx在收到请求后,会按照location的匹配规则决定走哪一组。以https://example.com/api/user.php为例,它匹配第一组,被转发给PHP-FPM;以https://example.com/static/js/app.js为例,它匹配第二组,直接读取/var/www/example/static/js/app.js返回给浏览器,完全不会占用PHP进程。

这里的fastcgi_pass参数就是Nginx与PHP-FPM之间的连接通道,用的是安装PHP时生成的Socket文件路径。每次改完配置都记得执行nginx -t再reload,避免语法错误导致Nginx直接拒绝启动。

3.2 location匹配规则的优先级与陷阱

很多新手栽在location上,是因为没搞懂Nginx的匹配优先级。Nginx的location规则按优先级从高到低排列:

  1. 精确匹配:location = /path
  2. 前缀匹配且带^~:location ^~ /static/
  3. 正则匹配:location ~ .php$
  4. 普通前缀匹配:location /static/
  5. 默认匹配:location /

正则匹配(用~或~*开头)有个特点是按照顺序匹配,一旦命中就停止。所以如果你写了多个正则location,一定要把更具体的规则写在前面。

动静分离配置里最需要注意的坑是:不要用正则location去匹配所有静态文件之后再套一层动态解析。比如有人这样写:

location ~* \.(jpg|png|css|js)$ { root /var/www/example; fastcgi_pass unix:/run/php/php8.1-fpm.sock; }

这等于把所有静态请求都转发给了PHP-FPM,完全失去了动静分离的意义。静态资源就应该由Nginx直接处理,这个定位不能搞混。

另外一个安全陷阱是.htaccess文件和.user.ini这类隐藏文件。如果你不加保护,Nginx可能把以点开头的文件内容直接返回给浏览器,而这些文件往往包含敏感配置。建议在server块里加一条拒绝规则:

location ~ /\. { deny all; }

还有PHP脚本解析的安全问题。如果没有对请求做合法性校验,攻击者可以构造一个不存在的PHP文件路径,比如/var/www/example/upload/nonexistent.php,如果Nginx把它也交给PHP-FPM解析,就可能触发代码执行漏洞。官方推荐的安全写法是:

location ~ \.php$ { try_files $uri =404; include fastcgi_params; fastcgi_pass unix:/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; }

try_files $uri =404的作用是:只有文件真实存在才进入后面的FastCGI处理,否则直接返回404。这一行能堵住绝大多数PHP文件包含攻击。

3.3 Rewrite规则与常见框架的伪静态配置

PHP框架普遍采用单一入口模式,比如ThinkPHP、Laravel,所有请求都先进入index.php,再由框架内部路由分发。这种模式要求Nginx把所有不存在的文件请求重写到入口文件。

我经常用的通用规则是:

location / { try_files $uri $uri/ /index.php?$query_string; }

这样配置之后,访问https://example.com/home/index,如果磁盘上不存在对应的home目录或index文件,Nginx就会把请求转交给index.php处理,query_string原样保留,框架通过PATH_INFO或路由参数就能解析出真实的控制器和方法。

有些老教程会用if判断再rewrite,写法是:

if (!-e $request_filename) { rewrite ^/(.*)$ /index.php/$1 last; }

这种写法也能工作,但官方文档明确建议优先使用try_files,因为if在Nginx里是“邪恶指令”,容易出现意想不到的副作用。try_files的语义更清晰,性能也更好。

WordPress的伪静态则是对固定链接的支持:

location / { try_files $uri $uri/ /index.php?$args; }

基本上,现代PHP项目的伪静态规则都可以抽象成一句话:文件存在就返回文件,文件不存在就进入index.php。

需要特别注意的是location /和location ~ .php$的协作关系。当一个PHP请求经过try_files重写为/index.php后,Nginx会再次执行location匹配规则,此时URI变成了/index.php,匹配到php正则location,于是转发给PHP-FPM。这个“二次匹配”机制是理解Nginx配置的关键,很多配置看着没错但不生效,就是没搞懂重写后的请求会重新匹配location。

3.4 静态资源的缓存策略与性能调优

动静分离配置完成后,下一步是优化静态资源的响应性能。浏览器缓存是成本最低的优化手段,通过Cache-Control和Expires响应头告诉浏览器“这个文件多久之内不用再问服务器要”。

我在配置里用的expires 30d就是Nginx提供的快捷指令,等价于给静态资源设置了30天的过期时间。实际使用中建议根据资源类型区别对待:

资源类型缓存时间建议
带哈希指纹的文件(app.a1b2c3.js)365d文件名变了才需要重新拉取
CSS/JS(无指纹)7d避免更新后浏览器还缓存老版本
图片/字体30d一般不会频繁变化
HTML页面不缓存保证更新即时生效

实现方式可以拆成两个location块,或者在一个location里用map变量根据文件扩展名区分。简单场景下,直接按扩展名写两个规则即可:

location ~* \.(js|css)$ { expires 7d; access_log off; } location ~* \.(png|jpg|jpeg|gif|ico|svg|woff2?)$ { expires 30d; access_log off; }

同时建议开一下gzip压缩,对CSS、JS、SVG这类文本资源的体积削减非常明显:

gzip on; gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml; gzip_min_length 1024;

gzip_min_length 1024的意思是小于1KB的文件不压缩,因为压缩小文件带来的CPU开销可能大于传输节省的时间。

生产环境里还有一个细节:静态资源请求不写访问日志。像图片、CSS这类请求量很大,每条都记日志会白白消耗磁盘IO。我在静态location里写了access_log off,真实请求量大的站点,这个配置能让日志文件增长慢好几倍。

3.5 动静分离的另一种形态:反向代理到Java应用

LNMP里的动静分离是最经典的一种,但动静分离的思想不局限在PHP场景。现在很多系统是前后端分离架构,前端是Nginx托管的静态页面,后端是Java、Go等语言写的微服务接口。Nginx仍然承担“静态直接返回、动态转发到后端应用”的角色,只不过fastcgi_pass换成了proxy_pass。

以若依微服务这类项目为例,常见的部署方式是前端打包后的dist目录放到Nginx站点根目录,接口请求转发到后端的Gateway网关:

server { listen 80; server_name admin.example.com; root /var/www/ruoyi/dist; index index.html; # 前端路由支持 location / { try_files $uri $uri/ /index.html; } # 接口反向代理 location /prod-api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # 静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 30d; access_log off; } }

这段配置里,/prod-api/前缀的请求被转发到本机8080端口的后端服务,其他请求优先找静态文件,找不到就回退到index.html,由前端路由接管。从本质上说,这依然是动静分离——静态页面交给Nginx,动态接口交给应用服务器,只不过代理协议从FastCGI换成了HTTP。

理解这一点很重要。Nginx在架构里的角色就是流量入口和分发器,不管后端是PHP-FPM、Tomcat、Node.js还是Go服务,对Nginx来说都是上游服务器。理解了这个模型,你就能灵活应对各种部署架构,而不是死记某一种配置模板。

4. 日志、开机启动与线上问题排查实录

4.1 访问日志与错误日志的合理配置

日志是排查问题最重要的线索。Nginx默认的访问日志格式比较简单,建议自定义一个包含耗时信息的格式:

log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" ' 'rt=$request_time uct=$upstream_connect_time ' 'uht=$upstream_header_time urt=$upstream_response_time';

这个格式多了三类关键信息:request_time是Nginx处理完整请求的总耗时,upstream_response_time是上游PHP-FPM或后端服务的处理耗时。如果发现request_time很大但upstream_response_time很小,说明瓶颈在网络传输或Nginx本身,而不是后端应用。

在站点配置里指定这个格式:

access_log /var/log/nginx/example_access.log main; error_log /var/log/nginx/example_error.log warn;

静态资源的访问日志用access_log off关掉,前面已经提到。错误日志级别用warn即可,debug级别会记录海量信息,反向坑到自己。

PHP-FPM本身的错误日志也要关注,配置文件里有个catchworkers_output和php_admin_flag[log_errors]参数。如果PHP脚本出错,Nginx错误日志只会显示“Primary script unknown”或者“Connection reset by peer”,真正的原因要到PHP-FPM日志里看。

4.2 开机启动与systemd管理

生产环境千万不要直接用nginx二进制启动服务,而是要用systemd管理,这样能实现开机自启、崩溃自动拉起、统一日志管理。Debian/Ubuntu安装时已经自动注册了服务,只需要启用开机自启:

sudo systemctl enable nginx sudo systemctl enable php8.1-fpm sudo systemctl enable mysql

用systemctl管理服务的日常命令:

sudo systemctl start nginx sudo systemctl restart php8.1-fpm sudo systemctl status mysql

每次修改配置文件后,先执行nginx -t检查语法,再执行systemctl reload nginx实现平滑生效。reload会重新加载配置并逐步替换worker进程,不会中断当前请求,这是nginx命令做不到的。

PHP-FPM和MySQL同理,改完配置后也需要重启或reload。PHP-FPM没有独立的reload命令,只能restart,重启会中断正在处理的请求,所以尽量在低峰期操作。

4.3 常见问题与排查技巧速查

以下是我在实际排障中遇到过最多的问题,整理成一张速查表:

现象可能原因排查命令/解决方式
访问PHP页面返回502 Bad GatewayPHP-FPM未启动、Socket路径不对、权限错误systemctl status php8.1-fpm;检查www.conf的listen路径与Nginx的fastcgi_pass是否一致
返回504 Gateway TimeoutPHP执行时间超过fastcgi_read_timeout增大fastcgi_read_timeout,同时排查PHP脚本是否有死循环或慢查询
返回403 Forbiddenindex指令缺失、目录无权限、被deny规则拦截检查站点的index.php是否存在;检查nginx worker用户对目录是否有读权限
返回404 Not Foundroot路径不对、try_files规则没生效、SCRIOT_FILENAME错误确认请求的真实URI;检查SCRIPT_FILENAME是否指向正确文件
返回空白页,状态码200PHP脚本有语法错误或异常被静默处理查看/var/log/php8.1-fpm.log,打开display_errors临时排查
静态文件更新后浏览器还是老文件浏览器缓存未过期开发环境把expires设置为off,生产环境用带哈希的文件名
Nginx启动失败配置文件语法错误、端口被占用nginx -t定位语法问题;netstat -tlnp看看80端口是否被其他进程占用

排查问题时我习惯的路径是:先确认进程状态,systemctl status确认三件套都在运行;再看Nginx错误日志,tail -f /var/log/nginx/error.log;然后看PHP-FPM日志;最后才怀疑代码问题。按照这个顺序,大多数问题能在五分钟内定位。

有一个特别容易踩的坑是Socket文件权限问题。Nginx的worker进程以www-data用户运行,PHP-FPM创建的Socket也在tmpfs或/run目录下,如果listen.mode设置不当,Nginx会报Permission denied。我遇到过完全相同的LNMP配置,在一台机器上正常,换一台机器就502,最后发现是PHP-FPM版本升级后Socket文件的默认权限变了。

5. 生产环境LNMP的部分性能参数优化

5.1 Nginx的进程与连接数调优

如果站点并发请求量上来了,Nginx默认的worker_processes和worker_connections可能需要调整。我的经验值是:worker_processes等于CPU物理核心数,worker_connections设到10240左右,公式上最大并发数约等于worker_processes乘以worker_connections,但实际还要考虑内存占用和文件描述符限制。

worker_processes auto; worker_rlimit_nofile 65535; events { worker_connections 10240; use epoll; }

use epoll是Linux下的高性能事件模型,默认一般就是epoll,显式写上也无妨。调完这个之后,检查系统的文件描述符限制,ulimit -n如果小于65535,需要调整/etc/security/limits.conf。

5.2 FastCGI缓冲与超时的取舍

PHP-FPM返回的响应内容较大时,Nginx默认会做缓冲。缓冲的好处是:PHP-FPM可以快速写完响应并释放进程,Nginx再慢慢把内容发给客户端,这样避免大量慢速客户端拖住PHP进程。

fastcgi_buffers 8 16k; fastcgi_buffer_size 32k; fastcgi_read_timeout 120; fastcgi_connect_timeout 30;

如果某个接口需要实时推送,比如SSE(Server-Sent Events)之类的流式响应,缓冲反而会拦截数据推送,这种情况下需要关闭缓冲:

fastcgi_buffering off;

具体业务具体分析,但默认开启缓冲对大多数Web应用是更优选择。

5.3 HTTPS与安全加固的补充建议

现代站点必须开通HTTPS,Nginx里配置SSL证书的核心配置片段:

listen 443 ssl http2; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.pem; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_session_cache shared:SSL:10m;

HTTP请求强制跳转到HTTPS,在80端口的server块里加一行:

return 301 https://$host$request_uri;

关于安全,日常最容易被忽略的是Nginx版本更新。apt源里的版本有安全补丁时记得及时升级,日常运维至少要保证:隐藏Nginx版本号(server_tokens off),限制上传目录的PHP执行权限,定期检查访问日志中的异常扫描请求。

在Linux系统中用rm -rf这类危险操作前,一定要再三确认目录路径。我见过有人把整台服务器的文件删光,原因就是在root目录下多敲了一个斜杠。教训很惨痛,操作之前多看一眼路径没有坏处。

我个人在实际操作中还有一个习惯:每完成一步配置,就用curl测一下响应头和相关页面状态。比如配置完动静分离后,分别curl静态文件路径和PHP路径,对比响应结果的耗时和处理方式。curl -I可以查看响应头,能看到Nginx直接返回静态文件时,响应头里会有Accept-Ranges和明确的Content-Type,而动态请求会经过FastCGI。多观察这些细节,你对整个请求链路的理解会越来越清晰。

LNMP这套东西,说难不难,说简单也不简单,核心就是把每个组件的职责边界搞清楚。Nginx负责流量分发和静态资源,PHP-FPM负责动态脚本执行,MySQL负责数据存储,动静分离只是这种职责分工在配置层面的自然体现。按照文章里的方式一步一步搭下来,中间再踩几次坑,你就能把这些配置从“背下来的”变成“真正理解的”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 17:59:00

PHP多进程信号处理与优雅关闭实践

1. 多进程PHP环境中的信号处理挑战在构建高并发的PHP服务时,多进程架构是常见的解决方案。当主进程fork出多个子进程后,一个经常被忽视但至关重要的问题是:如何精确控制不同子进程对系统信号的响应行为?特别是在需要优雅关闭服务时…

作者头像 李华
网站建设 2026/9/14 17:56:57

【C 数据结构】 树 二叉树 堆 (链式二叉树模拟实现篇)

目录 链式二叉树的模拟实现 二叉树的数据结构 基本功能实现 树初始化和销毁 遍历方式 遍历方式的概念解释: 遍历方式的代码模拟实现: 层序遍历 计算树的节点个数 二叉树叶子结点个数 二叉树k层结点个数 二叉数的最大深度 查找元素 判断是否…

作者头像 李华
网站建设 2026/9/14 17:54:19

yq Pipe 管道操作符:把一个表达式接进下一个表达式

yq Pipe 管道操作符:把一个表达式接进下一个表达式 【免费下载链接】yq yq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor 项目地址: https://gitcode.com/GitHub_Trending/yq/yq yq 是一款可移植的 YAML、JSON、XM…

作者头像 李华
网站建设 2026/9/14 17:52:49

闲鱼90元戴尔准系统改造NAS:1800元配置单与实战

上个月我蹲闲鱼的时候又刷到一台戴尔OptiPlex 7010 USFF,卖家标价90块,裸机,不带电源适配器,侧面还缺一颗螺丝。我犹豫了大概十秒钟,拍了。这种老准系统改NAS的玩法,是我这两年折腾下来觉得最划算的方案。整…

作者头像 李华