Debian 9 + LEMP 部署 WordPress:稳定、安全、高性能的生产级实践
1. 这不是“装个博客”那么简单为什么 Debian 9 LEMP 是 WordPress 部署的黄金组合你点开这个标题大概率不是想学一句“apt install wordpress”就完事。你可能刚买了一台 VPS看着控制台里干净的 Debian 9 命令行发愣也可能正被客户催着三天内上线一个企业官网而对方明确要求“必须是 WordPress但不能用共享主机那种慢得像蜗牛的环境”又或者你刚在安全通报里看到“120万 WordPress 站点被植入后门”的标题手心冒汗开始琢磨我自己的站是不是也裸奔在默认配置上——这些场景恰恰就是 Debian 9 搭配 LEMPLinux Nginx MySQL PHP这套组合拳真正发力的地方。它解决的从来不是“能不能跑起来”的问题而是“跑得稳不稳、快不快、安不安全、好不好管”的一整套生产级诉求。Debian 9代号 Stretch在 2017 年发布其核心价值在于长达五年的长期支持LTS这意味着它的内核、基础库和关键组件都经过了海量服务器环境的锤炼稳定性远超那些追求新特性的滚动发行版。而 LEMP 中的 Nginx不是 Apache 的平替它是为高并发、低内存占用而生的反向代理与 Web 服务引擎。当你面对一个日均 5000 UV 的企业站或者一个需要承载会员系统、在线表单提交反馈的 WooCommerce 商城时Nginx 的事件驱动模型能让你用更少的服务器资源扛住更大的流量洪峰。MySQL 5.7 提供了成熟的事务支持和查询优化能力PHP 7.0 则是 WordPress 性能跃升的关键——它比 PHP 5.6 快了近两倍这对一个插件动辄二三十个、主题功能堆叠的现代 WordPress 站点来说意味着首屏加载时间能从 3 秒压到 1.2 秒。这不是参数游戏这是真实影响用户跳出率、SEO 排名和转化率的硬指标。所以当你选择这个方案你选的不是一个安装教程而是一套面向真实业务场景的、可审计、可监控、可扩展的基础设施底座。它天然适配那些对建站有基本技术认知、不愿被托管服务商锁死、同时又不想把精力耗在无休止的服务器调优上的中小团队或独立开发者。你不需要成为 Linux 内核专家但你需要理解每个命令背后在做什么——这正是我们接下来要拆解清楚的。2. 为什么是 LEMP而不是 LAMP 或一键包架构选型背后的硬逻辑2.1 Nginx vs Apache不只是“换了个名字”的性能博弈很多人第一次接触 LEMP下意识会觉得“不就是把 Apache 换成 Nginx 吗反正都是跑 PHP。” 这个想法会直接把你带进坑里。Apache 和 Nginx 的底层设计哲学完全不同。Apache 采用的是“进程/线程驱动模型”每个 HTTP 请求都会分配一个独立的进程或线程。好处是模块丰富、.htaccess 规则灵活坏处是当并发连接数上来时内存消耗呈线性甚至指数级增长。我曾经维护过一台 2 核 4G 的 VPS上面跑着一个带 WooCommerce 的 WordPress 站用 Apache 默认配置在一次促销活动期间仅 800 个并发用户就让服务器内存使用率冲到 95%MySQL 开始频繁报错整个站直接“假死”。换成 Nginx 后同样的硬件轻松扛住了 2500 并发内存占用稳定在 60% 以下。Nginx 用的是“事件驱动、异步非阻塞”模型。它用一个主进程管理多个工作进程worker process每个工作进程又能通过 epollLinux 下的高效 I/O 多路复用机制同时处理成千上万个连接。它不为每个连接创建新进程而是把所有连接都挂在事件循环里哪个连接有数据可读、可写就去处理哪个。这就解释了为什么 Nginx 在静态文件图片、CSS、JS分发上天生就比 Apache 快也解释了为什么 WordPress 的伪静态规则比如将/post-name/这种友好 URL 映射回index.php在 Nginx 里必须用try_files指令来写而不是像 Apache 那样靠.htaccess文件层层递归解析——因为 Nginx 的配置是“编译时加载、运行时只读”的它拒绝在请求过程中动态读取和解析文件这本身就是一种性能保障和安全加固。提示WordPress 官方文档里那句“Nginx is not officially supported”其实是个历史遗留的误解。它的真实含义是“WordPress 核心团队不提供 Nginx 配置文件的官方维护”而不是“Nginx 跑不了 WordPress”。恰恰相反全球 Top 1000 的高流量 WordPress 站中超过 65% 使用 Nginx 作为前端 Web 服务器其中绝大多数都部署在 Debian/Ubuntu 这类稳定发行版上。2.2 Debian 9稳定压倒一切的“老派”智慧为什么不是更新的 Debian 10Buster或 11Bullseye这里有个关键的时间窗口问题。Debian 9 Stretch 的生命周期是 2017 年 6 月到 2022 年 6 月LTS 延长至 2024 年。这意味着截至 2023 年底大量仍在服役的企业级服务器、云主机镜像、甚至是某些嵌入式设备的管理后台其默认操作系统仍是 Debian 9。它的软件源里PHP 是 7.0MySQL 是 5.7Nginx 是 1.10这些版本与 WordPress 5.x 系列尤其是 5.0 到 5.6 这个主流稳定期的兼容性经过了数年实战检验。而 Debian 10 引入的 PHP 7.3 虽然更新但早期版本存在一些与特定 WordPress 插件比如某些老版本的 WP Super Cache的兼容性问题Debian 11 的 PHP 8.0 则对很多未及时更新的商业主题构成了“兼容性断崖”。更重要的是Debian 9 的apt包管理系统极其成熟。它的依赖解析算法以“保守”著称不会为了装一个新包而强行升级一堆底层库从而避免了“升级一个包崩掉整个系统”的灾难。我在给一家本地律所部署官网时客户明确要求“服务器不能有任何意外重启律师们随时要查案例”。我选择了 Debian 9全程只执行了apt update apt upgrade --dry-run来预览变更确认没有涉及内核或关键服务的升级后才进行实际更新。这种可控性是很多追求“最新”的发行版无法提供的。它不是落后而是在特定场景下对“确定性”的极致追求。2.3 为什么坚决不用“一键安装包”网络上充斥着各种“WordPress 一键安装脚本”它们确实能在 3 分钟内给你一个能访问的首页。但代价是什么是根目录下多出几十个权限为777的缓存文件夹是数据库密码明文写在/var/www/html/wp-config.php里且该文件的属主是www-dataWeb 服务用户是 Nginx 配置里开着autoindex on让整个网站目录结构一览无余是 PHP 的display_errors被设为On任何代码错误都会把数据库用户名、路径等敏感信息直接打印在网页上。这些都是“120 万站点被植入后门”的温床。LEMP 手动部署的核心价值就在于“过程即安全”。每一个chmod命令每一次chown操作每一条location配置都是你亲手为系统筑起的一道墙。你知道wp-content目录为什么必须是755而不是777你知道wp-config.php文件必须600且属主是root这样即使 Web 服务被攻破攻击者也无法直接读取它你知道 Nginx 的location ~ \.php$块里fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;这一行是为了防止“路径遍历”攻击确保 PHP 只能执行DOCUMENT_ROOT下的文件而不是/etc/passwd这样的系统文件。这些细节没有一个一键包会为你解释它们只会用最“省事”的方式把你推向风险的边缘。3. 从零开始LEMP 环境搭建与 WordPress 部署全流程实操3.1 环境初始化与系统加固5 分钟在你敲下第一个apt命令之前请先完成三件小事它们能帮你省下未来 80% 的排查时间。第一更新系统时间并启用 NTP。Debian 9 默认不开启时间同步而 SSL 证书、日志分析、甚至某些插件的授权验证都极度依赖准确的时间。执行sudo timedatectl set-ntp on sudo systemctl restart systemd-timesyncd然后用timedatectl status确认状态是active (running)且System clock synchronized: yes。别小看这一步我见过太多次因为服务器时间比标准时间快了 5 分钟导致 Lets Encrypt 申请 SSL 证书时反复失败错误提示却是“域名验证超时”让人一头雾水。第二创建一个非 root 的管理用户并禁用 root 密码登录。这是 Linux 服务器安全的基石。sudo adduser deployer sudo usermod -aG sudo deployer # 编辑 SSH 配置 sudo nano /etc/ssh/sshd_config找到PermitRootLogin这一行将其改为PermitRootLogin no保存退出后务必执行sudo systemctl restart ssh。然后立刻用新用户deployer登录一次确认一切正常再回到 root 用户下执行sudo passwd -l root来锁定 root 密码。这一步看似繁琐但它能有效阻止 99% 的暴力破解攻击——黑客的扫描器扫到 22 端口发现 root 登录被禁往往就会转向下一个目标。第三配置基础防火墙。Debian 9 自带iptables但我们用更友好的ufwUncomplicated Firewall来管理。sudo apt install ufw sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow OpenSSH sudo ufw allow Nginx Full # 这会同时放行 80 和 443 端口 sudo ufw enable执行sudo ufw status verbose你会看到一个清晰的规则列表。记住防火墙不是“装上就完事”它是一个活的策略。比如如果你后续要加 Redis 缓存就需要sudo ufw allow 6379如果要用 Fail2ban 防爆破它会自动在 ufw 里添加规则。现在你的服务器已经从“完全裸奔”变成了“穿着防弹衣的战士”可以开始真正的安装了。3.2 安装与配置 LEMP 栈15 分钟安装 Nginxsudo apt update sudo apt install nginx安装完成后Nginx 会自动启动。用sudo systemctl status nginx确认状态是active (running)。此时用浏览器访问你的服务器 IP应该能看到 Nginx 的欢迎页。如果看不到请检查 ufw 是否放行了 80 端口以及云服务商的安全组是否开放了该端口。安装 MySQLsudo apt install mysql-server安装过程中MySQL 5.7 会自动生成一个随机 root 密码并存储在/etc/mysql/debian.cnf文件里。但这个密码是给系统内部脚本用的我们不建议直接用它。更好的做法是安装完后立即运行sudo mysql_secure_installation。这个向导会引导你设置 root 用户的强密码请务必记下来删除匿名用户Remove anonymous users? [Y/n] Y禁止 root 远程登录Disallow root login remotely? [Y/n] Y删除测试数据库Remove test database and access to it? [Y/n] Y重载权限表Reload privilege tables now? [Y/n] Y这五步做完你的 MySQL 就从“实验室玩具”变成了“生产级数据库”。特别注意第二步和第三步它们直接堵死了两个最常见的入侵入口。安装 PHP 及其扩展sudo apt install php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-xmlrpc php-soap php-intl php-zip这里的关键是php-fpmFastCGI Process Manager。它不是 PHP 的一个“插件”而是 PHP 与 Nginx 通信的桥梁。Nginx 本身不解析 PHP它把.php请求转发给php-fpm进程由php-fpm去执行并返回结果。php-mysql是连接 MySQL 的驱动php-curl是很多主题和插件如社交媒体分享、远程 API 调用的必备项php-gd是图像处理库没有它WordPress 的缩略图生成、图片裁剪功能会全部失效。php-mbstring和php-xml则是 WordPress 核心的硬性依赖缺少它们后台根本打不开。安装完后需要修改php-fpm的默认配置让它更安全sudo nano /etc/php/7.0/fpm/pool.d/www.conf找到以下几行并修改; 修改监听方式从 TCP 改为 Unix Socket更快更安全 listen /run/php/php7.0-fpm.sock ; 修改权限确保只有 Nginx 的 worker 进程能访问 listen.owner www-data listen.group www-data listen.mode 0660 ; 修改 PHP 进程的用户和组避免以 root 身份运行 user www-data group www-data ; 关键禁止 PHP 访问根目录以外的文件防止路径遍历 php_admin_value[open_basedir] /var/www/html/:/tmp/改完保存然后重启服务sudo systemctl restart php7.0-fpm。3.3 配置 Nginx 虚拟主机与 WordPress 伪静态10 分钟现在Nginx、MySQL、PHP 都已就位但它们还只是散落的零件。我们需要一个“蓝图”把它们组装成一个能跑 WordPress 的整体。这个蓝图就是 Nginx 的虚拟主机Server Block配置。首先创建网站根目录并设置权限sudo mkdir -p /var/www/html/example.com sudo chown -R $USER:$USER /var/www/html/example.com sudo chmod -R 755 /var/www/html注意这里chown的是$USER即你当前登录的用户比如deployer而不是www-data。这是为了后续你用 SFTP 上传文件时不会因为权限问题而失败。www-data用户只需要有读取权限即可。然后创建一个全新的配置文件sudo nano /etc/nginx/sites-available/example.com将以下内容粘贴进去请务必将example.com替换为你自己的域名server { listen 80; listen [::]:80; root /var/www/html/example.com; index index.php index.html index.htm; server_name example.com www.example.com; # WordPress 伪静态核心规则 location / { try_files $uri $uri/ /index.php?$args; } # 禁止访问敏感文件 location ~ /\.ht { deny all; } location ~ ^/wp-content/.\.php$ { deny all; } location ~ ^/wp-includes/.\.php$ { deny all; } location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } # PHP 处理块 location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.0-fpm.sock; # 关键安全补丁防止 CVE-2019-11043 fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; } # 禁止访问 .log 文件 location ~ \.log$ { deny all; } }这段配置里location /块里的try_files指令就是 WordPress 伪静态的灵魂。它告诉 Nginx“当用户请求/about/时先看看/var/www/html/example.com/about/这个目录是否存在不存在就看看/var/www/html/example.com/about/index.html存不存在还不存在那就把请求交给/var/www/html/example.com/index.php并把原始请求的参数$args一起传过去。” 这样WordPress 的rewrite模块才能根据这些参数从数据库里找出正确的文章内容。配置完后需要启用它sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/ sudo nginx -t # 测试配置语法是否正确 sudo systemctl reload nginxnginx -t是神命令每次修改配置后必敲。它会告诉你哪一行错了错在哪里。我曾因为一个漏掉的分号花了 40 分钟在日志里大海捞针后来养成习惯改完就t再也没为语法错误浪费过时间。3.4 下载、配置与安装 WordPress10 分钟现在Web 服务器已经准备好接收请求了我们可以把 WordPress “放”进去了。进入网站根目录cd /var/www/html/example.com下载并解压 WordPress使用官方最新稳定版sudo wget https://wordpress.org/latest.tar.gz sudo tar -xzf latest.tar.gz sudo mv wordpress/* ./ sudo rmdir wordpress sudo rm latest.tar.gz注意mv wordpress/* ./这条命令是关键。它把wordpress文件夹里的所有文件包括wp-admin,wp-includes,wp-config.php等都移动到当前目录即/var/www/html/example.com而不是把整个wordpress文件夹放进去。否则你的网站 URL 就会变成example.com/wordpress/这显然不是我们想要的。接下来配置数据库。登录 MySQLsudo mysql -u root -p输入你之前设置的 root 密码然后创建一个专门给 WordPress 用的数据库和用户CREATE DATABASE wordpress_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER wp_userlocalhost IDENTIFIED BY your_strong_password_here; GRANT ALL PRIVILEGES ON wordpress_db.* TO wp_userlocalhost; FLUSH PRIVILEGES; EXIT;这里用了utf8mb4字符集而不是旧的utf8。因为utf8mb4才能完整支持 Emoji 表情、中文四字节生僻字等这是现代网站的标配。GRANT ALL PRIVILEGES看似很宽泛但因为我们指定了wp_userlocalhost这个用户只能从本机连接安全性是有保障的。最后配置 WordPress 的wp-config.php文件sudo cp wp-config-sample.php wp-config.php sudo nano wp-config.php找到数据库配置部分填入你刚才创建的信息define(DB_NAME, wordpress_db); define(DB_USER, wp_user); define(DB_PASSWORD, your_strong_password_here); define(DB_HOST, localhost);然后强烈建议在文件末尾添加以下几行它们是 WordPress 安全的“定海神针”// 禁用文件编辑功能防止后台被黑后直接改代码 define(DISALLOW_FILE_EDIT, true); // 启用自动更新核心小版本 define(WP_AUTO_UPDATE_CORE, minor); // 设置密钥去 https://api.wordpress.org/secret-key/1.1/salt/ 获取 define(AUTH_KEY, put your unique phrase here); // ... 其他密钥同理DISALLOW_FILE_EDIT这一行能直接让 90% 的“后台挂马”攻击失效。因为攻击者即使拿到了管理员账号也无法在后台的“外观 编辑”里修改主题或插件的 PHP 文件。保存退出现在用浏览器访问http://example.com就应该能看到熟悉的 WordPress 安装向导了。填写站点标题、管理员邮箱、用户名和密码点击“安装 WordPress”大功告成。4. 部署之后的“真功夫”安全加固、性能调优与日常运维4.1 WordPress 安全加固不止于“改密码”安装完成只是起点真正的安全防护才刚刚开始。WordPress 的安全是一个“纵深防御”体系需要在多个层面布防。第一层文件系统权限。这是最容易被忽视也是最基础的一环。执行以下命令sudo find /var/www/html/example.com -type d -exec chmod 755 {} \; sudo find /var/www/html/example.com -type f -exec chmod 644 {} \; sudo chmod 600 /var/www/html/example.com/wp-config.php sudo chown -R www-data:www-data /var/www/html/example.com解释一下所有目录设为755所有者可读写执行组和其他人只可读执行所有文件设为644所有者可读写组和其他人只可读。wp-config.php是皇冠上的明珠必须600只有所有者可读写并且它的所有者必须是root而不是www-data。但上面的chown命令又把它设回了www-data没错这是一个精妙的平衡。wp-config.php的内容数据库密码必须对www-data用户可读否则 WordPress 无法连接数据库但它的文件本身不能让www-data用户有写权限否则一旦 Web 服务被攻破攻击者就能直接修改它。所以我们用chown把它设为www-data:www-data但用chmod 600剥夺了组和其他人的所有权限只留下www-data用户自己能读。这是一种“最小权限原则”的实践。第二层禁用 XML-RPC。XML-RPC 是 WordPress 早期为移动 App 和第三方客户端提供的远程调用接口。但现在它几乎成了暴力破解和 DDoS 放大攻击的“高速公路”。在wp-config.php文件顶部添加add_filter(xmlrpc_enabled, __return_false);或者更彻底地在 Nginx 配置的server块里添加location ~ ^/xmlrpc\.php$ { deny all; }重启 Nginx 即可。这能瞬间关闭一个巨大的攻击面。第三层强制 HTTPS。即使你暂时没申请 SSL 证书也应该为未来铺路。在 Nginx 配置中将listen 80的server块改为一个 301 重定向server { listen 80; listen [::]:80; server_name example.com www.example.com; return 301 https://$server_name$request_uri; }然后再新建一个listen 443 ssl http2的server块来处理 HTTPS 请求。这样所有 HTTP 流量都会被强制跳转到 HTTPS既安全又为 SEO 加分。4.2 性能调优让 WordPress “飞”起来一个未经优化的 WordPress 站点就像一辆没调校过的赛车。硬件再好也跑不出应有的速度。PHP-FPM 进程管理调优。默认的www.conf配置是为通用场景设计的。对于一台 2 核 4G 的 VPS我推荐这样修改pm dynamic pm.max_children 50 pm.start_servers 10 pm.min_spare_servers 5 pm.max_spare_servers 15 pm.max_requests 500pm.max_children是最大子进程数它决定了服务器能同时处理多少个 PHP 请求。计算公式是总内存 / 每个 PHP 进程平均内存。一个典型的 WordPress 页面PHP 进程平均占用 30-40MB 内存。4G 内存留出 1G 给系统和 MySQL剩下 3G除以 40MB约等于 75。我们设为 50是留出了充足的余量。pm.max_requests 500是关键它表示每个子进程处理完 500 个请求后就自动重启这能有效防止内存泄漏导致的性能衰减。Nginx 缓存配置。在server块里添加# 启用 FastCGI 缓存 fastcgi_cache_path /var/run/nginx-cache levels1:2 keys_zoneWORDPRESS:100m inactive60m; fastcgi_cache_key $scheme$request_method$host$request_uri; fastcgi_cache_use_stale error timeout updating http_500 http_503; fastcgi_cache_valid 200 301 302 10m; fastcgi_cache_valid 404 1m;然后在location ~ \.php$块里加入fastcgi_cache WORDPRESS; fastcgi_cache_bypass $skip_cache; fastcgi_no_cache $skip_cache; fastcgi_cache_valid 200 301 302 10m;这相当于给 PHP 的输出结果建了一个“速食仓库”。当用户第二次访问同一个页面时Nginx 直接从内存缓存里把 HTML 返回完全不经过 PHP 解析和 MySQL 查询响应时间从 300ms 降到 20ms。这是我给客户做性能报告时最常被惊叹的一点。WordPress 层面的轻量化。主题和插件是性能杀手。我有一个铁律一个新站上线前必须做到“三无”——无未启用的主题、无未启用的插件、无未使用的页面模板。在wp-content/themes和wp-content/plugins目录下只保留一个正在用的主题和必需的插件比如一个缓存插件、一个安全插件、一个 SEO 插件。其他全部删除。不要想着“以后可能用得上”它们不仅占用磁盘空间更会在 WordPress 启动时被扫描、加载拖慢整个系统。4.3 日常运维备份、更新与监控一个健康的 WordPress 站点离不开一套可靠的日常运维流程。自动化备份。手动备份是不可靠的。我用一个简单的 Bash 脚本来实现每日全量备份#!/bin/bash DATE$(date %Y%m%d) BACKUP_DIR/backup SITE_DIR/var/www/html/example.com DB_NAMEwordpress_db DB_USERwp_user DB_PASSyour_password # 备份数据库 mysqldump -u $DB_USER -p$DB_PASS $DB_NAME | gzip $BACKUP_DIR/db-$DATE.sql.gz # 备份网站文件 tar -czf $BACKUP_DIR/files-$DATE.tar.gz -C /var/www/html example.com # 清理 7 天前的备份 find $BACKUP_DIR -name db-*.sql.gz -mtime 7 -delete find $BACKUP_DIR -name files-*.tar.gz -mtime 7 -delete把这个脚本保存为/home/deployer/backup.sh然后用crontab -e添加定时任务# 每天凌晨 2 点执行备份 0 2 * * * /home/deployer/backup.sh备份文件必须存放在与网站不同的物理位置最好是异地对象存储如 AWS S3、腾讯云 COS。我见过太多次服务器硬盘损坏连备份文件一起丢了。智能更新策略。WordPress 核心的小版本更新如 6.1.1 - 6.1.2是安全的可以开启自动更新。但大版本如 6.1 - 6.2和主题/插件更新必须手动操作。我的流程是先在一个克隆的测试环境中更新用浏览器打开所有关键页面首页、文章页、产品页、表单页确认功能正常、样式无错乱再在生产环境执行。永远不要在周五下午 5 点赶在下班前更新一个未知的商业主题。基础监控。不需要复杂的 Zabbix 或 Prometheus。一个简单的htop命令就能实时看到 CPU、内存、负载的使用情况。配合sudo tail -f /var/log/nginx/access.log和sudo tail -f /var/log/nginx/error.log你可以第一时间发现异常流量比如某个 IP 在疯狂刷/wp-login.php或 PHP 错误比如某个插件导致的Fatal error。把这些日志定期归档并用logrotate进行切割是每个运维人员的基本功。5. 常见问题与“踩坑”实录那些没人告诉你的真相5.1 “安装向导卡在最后一步页面空白” —— 90% 是 PHP 权限问题现象你填完所有信息点击“安装 WordPress”页面就变成一片空白或者显示500 Internal Server Error。F12 打开开发者工具Network 标签页里install.php这个请求的状态码是 500。原因几乎可以 100% 断定是wp-config.php文件的权限或所有权出了问题。最常见的错误是你在nano里编辑完wp-config.php后直接CtrlX退出而没有用sudo权限保存。结果这个文件的所有者变成了你当前的用户比如deployer而www-data用户没有读取权限。解决方案立刻执行sudo chmod 600 /var/www/html/example.com/wp-config.php sudo chown www-data:www-data /var/www/html/example.com/wp-config.php。然后清空浏览器缓存重新访问安装页面。如果还是不行去 Nginx 的错误日志里找线索sudo tail -f /var/log/nginx/error.log里面通常会有一行PHP message: PHP Fatal error: require(): Failed opening required ...这说明 PHP 找不到某个核心文件大概率是wp-includes或wp-admin目录的权限不对用sudo chmod -R 755 /var/www/html/example.com/wp-includes和sudo chmod -R 755 /var/www/html/example.com/wp-admin修复。实操心得我给自己立下一条铁律——所有位于/var/www/html/目录下的文件和文件夹其所有者必须是www-data权限必须是755目录或644文件除了wp-config.php这个特例。这条规则帮我避开了 95% 的“白屏”问题。5.2 “后台上传图片失败提示‘上传的文件类型不被允许’” —— MIME 类型校验惹的祸现象在 WordPress 后台点击“媒体 添加新文件”选择一张 JPG 图片点击上传却弹出红色错误“上传的文件类型不被允许。”原因这不是 WordPress 的错而是 Nginx 的锅。Nginx 有一个client_max_body_size指令默认值是 1MB。如果你试图上传一个 2MB 的高清图片Nginx 在请求到达 PHP 之前就已经把它拦下了并返回一个413 Request Entity Too Large错误。而 WordPress 的错误提示只是对这个底层错误的一个“友好包装”。解决方案编辑 Nginx 的主配置文件sudo nano /etc/nginx/nginx.conf在http块里添加一行client_max_body_size 64M;然后重启 Nginxsudo systemctl restart nginx。64M 是一个比较宽松的值足以应付绝大多数图片、PDF 和视频上传需求。如果你的业务有特殊要求可以按需调整。注意这个值必须同时在 Nginx 和 PHP 里设置。PHP 也有一个upload_max_filesize和post_max_size它们在/etc/php/7.0/fpm/php.ini文件里。确保它们的值不小于 Nginx 的client_max_body_size否则 PHP 层会再次拦截。5.3 “网站打开很慢但服务器资源占用很低” —— DNS 查询是隐形杀手现象你用htop看着CPU 和内存都空空如也但用浏览器打开网站首屏加载要 5 秒以上。用curl -o /dev/null -s -w time_connect: %{time_connect}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n http://example.com测试发现time_connect时间很长比如 2 秒。原因time_connect衡量的是建立 TCP 连接的时间它包含了 DNS 解析。如果服务器的 DNS 解析服务器/etc/resolv.conf里配置的响应很慢或者根本不可达那么每次 PHP 脚本里执行一个file_get_contents()或cURL请求比如调用天气 API、微信 JS-SDK 签名都会在这里卡住。解决方案更换一个快速、可靠的 DNS 服务器。编辑

相关新闻