很多人买了云服务器之后的第一反应是:系统装好了、SSH 能登进去了,然后就没有然后了。我也经历过这个阶段,对着黑乎乎的终端发呆,不知道这台 Linux 服务器到底能拿来干什么。其实服务器本身不值钱,值钱的是上面跑的服务。这篇文章我就按自己平时搭站的实际流程,从空白系统开始,一步步把一台 Linux 服务器从“能登录”变成“真正可用”,用的组合就是最经典的 Nginx + MySQL + PHP + WordPress。
这套组合的覆盖面很广,个人博客、企业展示站、在线文档站、内网测试环境,都能用它快速搭起来。无论你是刚接触服务器的新手,还是想梳理一遍完整部署流程的老手,这篇都能给你一套可以直接照着做的操作方案。文章里每一步我都会解释为什么这么做,以及哪些地方容易踩坑——这都是我反复重装服务器换来的教训。
1. 部署前的整体规划与思路
1.1 为什么选 Nginx + MySQL + PHP + WordPress 这套组合
LNMP 这套架构能成为主流,不是没有原因的。它本质上是一个“各干各的活”的架构:Nginx 负责接收 HTTP 请求、处理静态文件和做反向代理,PHP-FPM 负责处理 PHP 动态程序,MySQL 负责数据存储,WordPress 负责业务层和页面输出。每个组件只关心自己那一块,出了问题也好排查。
有人会问,Apache 不是也能干这事吗?确实能,早期 LAMP 也很流行。但 Nginx 在处理高并发静态请求时内存占用更低,作为反向代理的配置也更灵活,再加上 PHP-FPM 可以单独控制进程数和超时时间,比 Apache 的 mod_php 方式更容易调优。对于一台 1 核 2G 的小服务器来说,Nginx 的优势尤其明显。
选 WordPress 则是因为它生态太成熟了。官方插件和主题库加起来几万个,SEO 插件、缓存插件、备份插件一键搞定,遇到问题搜一下基本上都有答案。如果是自己从零写一套 PHP 站点,性能和可控性更高,但开发成本和维护成本完全不在一个量级。对绝大多数场景来说,WordPress 是性价比最高的选择。
1.2 服务器最低配置与基础环境准备
先说说硬件边界。我实测过,1 核 1G 内存的机器跑 WordPress 也扛得住,但建议至少 1 核 2G。为什么?PHP-FPM 每个进程大约占 30~50M 内存,MySQL 缓冲池一开就是几百 M,WordPress 本身还有不少常驻开销。内存低于 1G 的时候,系统会频繁使用 swap,页面响应会明显变慢。
系统方面,我以 Rocky Linux 9 为例,因为它是 RHEL 系,和 CentOS 的使用习惯完全一致,而且维护期长。Debian 或 Ubuntu 命令略有差异,但整体流程是一样的,不影响你对照操作。拿到服务器后,先做四件事:
bash复制# 1. 更新系统包
dnf update -y
# 2. 设置主机名,方便自己识别
hostnamectl set-hostname web01
# 3. 设置时区,避免日志时间对不上
timedatectl set-timezone Asia/Shanghai
# 4. 确保时间同步服务在跑
systemctl enable --now chronyd
如果服务器内存只有 1G,建议再加 2G swap。很多新手不知道 swap 怎么加,其实就几条命令:
bash复制fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
为了让重启后 swap 仍在,需要把 /swapfile swap swap defaults 0 0 写进 /etc/fstab。这一步很容易被忘,我就在这上面栽过跟头——当时以为 swap 设好了,结果重启一次就没了,数据库动不动被杀掉。
还有一个容易忽略的点:防火墙。Rocky Linux 默认启用 firewalld,如果你不开端口,后面 Nginx 装好了外面也访问不到。
bash复制systemctl enable --now firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
SSH 的 22 端口默认是放开的,不用额外设置。如果你在云厂商的安全组里也配了规则,记住两边都要放行 80 和 443,否则就算服务器内网防火墙放行了,流量照样进不来。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Nginx 安装与基础配置
2.1 用官方源安装,还是用系统自带的包?
Rocky Linux 9 的 AppStream 仓库里自带 Nginx,直接 dnf install nginx 就行。但自带的版本通常比较旧,而且更新节奏慢。我个人更推荐添加 Nginx 官方源,版本新、打补丁及时,配置方式也没有差异。
添加官方源的方式是创建一个仓库文件:
bash复制cat > /etc/yum.repos.d/nginx.repo <<'EOF'
[nginx-stable]
name=nginx stable repo
baseurl=https://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
priority=1
EOF
然后执行 dnf install -y nginx。为什么建议用新版本?旧版 Nginx 在某些 HTTP 解析场景下有已知安全问题和性能缺陷,官方源修复更快,你不需要自己编译,就能用上最新的稳定版。
2.2 最小可用配置与安全加固
Nginx 的主配置文件是 /etc/nginx/nginx.conf。默认配置直接跑没问题,但有几个地方我建议改一下。
首先是隐藏版本号。默认配置会在响应头里带 Server: nginx/1.24.0 这样的信息,等于告诉别人你用的具体版本,方便对方针对性扫描漏洞。在 http 块里加一行:
nginx复制server_tokens off;
其次是调整进程和连接数。1 核机器用 worker_processes auto; 就行,Nginx 会自动匹配 CPU 核心数。worker_connections 默认 1024,一个 worker 能同时处理的连接数,小站点不用动,如果后面并发上来了再调。
然后建立站点配置文件,我习惯放在 /etc/nginx/conf.d/ 下,一个站点一个文件,清晰好维护。先建一个基础版本:
nginx复制server {
listen 80;
server_name blog.example.com;
root /var/www/blog;
index index.php index.html;
access_log /var/log/nginx/blog.access.log;
error_log /var/log/nginx/blog.error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
这个配置里最关键的是 try_files 那一行,它是后面 WordPress 伪静态生效的基础。原理是:当请求的路径在磁盘上找不到对应文件时,回退到 index.php 去处理,这样 WordPress 才能根据 URL 解析出对应的文章页面。
3. MySQL 安装配置与安全初始化
3.1 两个步骤装好 MySQL 8.0
Rocky Linux 9 的模块仓库里自带 MySQL 8.0,这是 Oracle 官方维护的版本,不是分支,直接用就行:
bash复制dnf module list mysql
dnf module enable -y mysql:8.0
dnf install -y mysql-server
安装完成后,启动前先初始化:
bash复制systemctl start mysqld
systemctl enable mysqld
MySQL 8.0 在首次启动时会生成一个临时 root 密码,写在日志里:
bash复制grep 'temporary password' /var/log/mysqld.log
用这个密码登录:
bash复制mysql -uroot -p
然后立刻执行安全初始化脚本:
bash复制mysql_secure_installation
这个脚本会问你几个问题:是否修改 root 密码、是否删除匿名用户、是否禁止 root 远程登录、是否删除 test 库、是否刷新权限表。我的建议是全部选 yes。特别是“禁止 root 远程登录”这一项,很多人为了图省事选 no,结果数据库暴露在公网上,被扫到就是灾难。
3.2 创建 WordPress 专用账号和数据库
这一步很多教程会跳过,直接让 WordPress 用 root 连接数据库,这是绝对不可取的。应用和数据库的账号权限应该最小化,万一站点被拿下了,攻击者拿到的也只是数据库里一个库的权限,而不是整个数据库服务器的 root。
在 MySQL 里执行:
sql复制CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY '这里换成强密码';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
这里有几个细节值得说明。
第一,字符集一定用 utf8mb4,因为 MySQL 8.0 默认就是它,也支持 emoji 和生僻字,老项目常见的 utf8 已经被官方标记为废弃了。
第二,授权范围用 localhost,不要用 %。WordPress 和 MySQL 在同一台服务器上,PHP 进程通过本地 socket 或 127.0.0.1 连接,根本不需要支持远程连接。限制在 localhost 从源头堵住远程爆破的可能性。
第三,密码强度。MySQL 8.0 默认装了 validate_password 组件,弱密码是过不去的,这个特性建议保留。强密码记不住就用密码管理器存着,千万别为了图省事写成 123456。
3.3 一开始别过度调优,先设两个关键参数
关于 MySQL 性能调优,我的经验是:新站点不要一上来就抄网上那套“终极配置”。每个服务器的内存、磁盘、负载都不一样,盲目堆参数反而可能起到反作用。刚开始只需要关注两个最影响性能的:
innodb_buffer_pool_size:InnoDB 的缓冲池,用来缓存数据和索引。一般设置为物理内存的 50%~70%。1 核 2G 的机器设 1G,1 核 1G 的机器设 384M 比较稳。max_connections:最大连接数。默认 151 其实够小站用了,不需要动。如果你发现Too many connections报错,优先排查是不是 PHP-FPM 进程数开太多,而不是盲目调高这个值。
修改位置在 /etc/my.cnf.d/mysql-server.cnf,在 [mysqld] 段下加入:
ini复制innodb_buffer_pool_size = 1G
然后 systemctl restart mysqld。调整完可以用 SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; 验证。配置生效了再继续下一步。
4. PHP 安装与 PHP-FPM 集成
4.1 装 PHP 8.2 及 WordPress 必需扩展
Rocky Linux 9 自带的 PHP 是 8.0 版本,能用,但为了性能和兼容性,我推荐用 Remi 仓库装 PHP 8.2。Remi 是 RHEL 系生态里最权威的第三方 PHP 仓库,更新及时,而且和系统模块共存不冲突。
bash复制# 添加 Remi 仓库
dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm
# 重置系统的 PHP 模块,启用 remi 源里的 8.2
dnf module reset php -y
dnf module enable php:remi-8.2 -y
# 安装 PHP-FPM 和 WordPress 常用扩展
dnf install -y php-fpm php-mysqlnd php-gd php-xml php-mbstring php-json php-curl php-zip php-opcache
这里的扩展没有一个多余的,说下各自的作用。php-mysqlnd 是 PHP 连接 MySQL 的驱动,不装它 WordPress 会直接报“无法连接数据库”;php-gd 负责图片处理,WordPress 裁剪缩略图靠它;php-xml 和 php-mbstring 关系到站点地图、RSS 订阅、多语言字符串处理;php-curl 用于 WordPress 后台的远程请求,比如检查更新;php-zip 是在后台直接安装插件和主题时解压文件用的;php-opcache 是性能利器,能把 PHP 编译后的字节码缓存起来,显著降低 CPU 消耗。
装完之后确认一下版本:
bash复制php -v
4.2 PHP-FPM 与 Nginx 的联动配置
PHP-FPM 是 PHP 的 FastCGI 进程管理器。理解它的工作方式很简单:Nginx 遇到 .php 文件时,自己不处理,而是把请求交给 PHP-FPM,PHP-FPM 执行完再把结果递回给 Nginx,最后由 Nginx 返回给浏览器。
安装完成后,PHP-FPM 的默认配置需要改两个地方。编辑 /etc/php-fpm.d/www.conf:
ini复制user = nginx
group = nginx
listen = /run/php-fpm/www.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
默认配置里 user 是 apache,listen 的是 TCP 端口 127.0.0.1:9000。我改成 Nginx 用户的 socket 方式,原因有二:socket 走内核 IPC,比 TCP 回环少了协议栈开销,性能略好且更安全;统一用 nginx 用户,站点文件权限管理起来不会乱。
启动并设置开机自启:
bash复制systemctl start php-fpm
systemctl enable php-fpm
回到之前的 Nginx 站点配置,location ~ \.php$ 里的 fastcgi_pass unix:/run/php-fpm/www.sock; 就是和 PHP-FPM 对接的关键。还要注意 fastcgi_param SCRIPT_FILENAME 这行,它告诉 PHP-FPM 要执行的文件路径。如果这个参数配置不对,最常见的报错是“File not found”,明明文件在那里,PHP-FPM 就是找不到。原因就是 $document_root$fastcgi_script_name 拼出来的路径和实际路径对不上,比如 root 写的是 /var/www/blog,实际文件放在 /data/blog。
5. WordPress 部署与站点配置
5.1 下载解压并设置目录权限
当 Nginx、MySQL、PHP-FPM 三个底座都跑起来了,接下来就是把 WordPress 放进去。先下载最新版:
bash复制cd /tmp
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
mkdir -p /var/www
mv wordpress /var/www/blog
需要中文语言包的话,WordPress 官方也提供 latest-zh_CN.tar.gz,下载地址换成 https://cn.wordpress.org/latest-zh_CN.tar.gz 即可,安装包内容和国际版一致,只是默认语言是中文。
接下来是很多人会忽略的权限问题。WordPress 需要写入 wp-content/uploads 目录用于上传图片,还需要读取整个站点目录。由于 PHP-FPM 运行用户是 nginx,所以最省心的做法是直接让 nginx 拥有站点目录:
bash复制chown -R nginx:nginx /var/www/blog
然后目录权限 755、文件权限 644,如果你的目录权限不对,会出现“无法创建目录 wp-content/uploads/...”或者图片上传失败。可以批量修正:
bash复制find /var/www/blog -type d -exec chmod 755 {} \;
find /var/www/blog -type f -exec chmod 644 {} \;
5.2 在浏览器里完成安装并配置伪静态
站点文件放好后,浏览器访问 http://服务器IP/ 就能看到 WordPress 的安装引导。按照提示填写数据库名 wordpress、用户名 wpuser、密码、数据库主机 localhost,表前缀保持默认 wp_ 即可。安装过程会生成 wp-config.php,这一步完成后就能看到登录界面了。
登录后台后,如果你把固定链接设置成“文章名”这类格式,会发现所有文章页面都是 404。这是因为 WordPress 基于 Apache 的 .htaccess 做 URL 重写,而 Nginx 不认 .htaccess,需要自己在 Nginx 配置里写对应规则。
规则就是前面提到的那行:
nginx复制try_files $uri $uri/ /index.php?$query_string;
它的意思是:先按原样找文件,找不到就找目录,目录也找不到就把请求抛给 index.php,由 WordPress 根据 URL 解析路由。这就是 Nginx 版伪静态的核心,理解了它,以后遇到各种 CMS 伪静态配置都能举一反三。
5.3 三个提升安全性的配置
站点能正常访问只是第一步,上生产环境前我还会做三件小事。
第一,加固 wp-config.php。把生成密钥的随机字符串填进去,关闭后台文件编辑器:
php复制define('AUTH_KEY', '随机字符串');
define('SECURE_AUTH_KEY', '随机字符串');
define('LOGGED_IN_KEY', '随机字符串');
define('NONCE_KEY', '随机字符串');
define('AUTH_SALT', '随机字符串');
define('SECURE_AUTH_SALT', '随机字符串');
define('LOGGED_IN_SALT', '随机字符串');
define('NONCE_SALT', '随机字符串');
define('DISALLOW_FILE_EDIT', true);
密钥去 https://api.wordpress.org/secret-key/1.1/salt/ 生成就行。它主要用来加密登录 Cookie 和密码哈希,不设置也能跑,但安全性差一个档次。
第二,修改数据库表前缀。如果安装前就考虑到,可以把 wp_ 改成随机的 x9k2_ 这类前缀,能挡掉一部分针对默认前缀的 SQL 注入攻击。
第三,给 wp-config.php 单独收紧权限:
bash复制chmod 600 /var/www/blog/wp-config.php
这样即使 Web 目录被列目录,其他系统用户也读不到数据库密码等敏感信息。
6. 常见问题与排查技巧实录
6.1 部署期高发问题速查表
为了让你快速定位问题,我把部署期间最常遇到的情况整理成一张表:
| 现象 | 可能原因 | 排查与解决办法 |
|---|---|---|
| 浏览器无法访问 | 防火墙未放行端口 | 检查 firewalld 和安全组是否放行 80/443 |
| 502 Bad Gateway | PHP-FPM 未启动或 socket 不存在 | systemctl status php-fpm,确认 Nginx 配置里 fastcgi_pass 路径一致 |
| 504 Gateway Timeout | PHP 执行超时 | 调大 fastcgi_read_timeout 和 PHP-FPM 的 request_terminate_timeout |
| 页面提示“File not found” | SCRIPT_FILENAME 路径错误 | 检查 Nginx 的 root 和 fastcgi_param SCRIPT_FILENAME 是否与文件实际路径一致 |
| 无法连接数据库 | 数据库账号/密码错误,或授权 host 不匹配 | 确认 wp-config.php 中 DB_HOST、DB_USER、DB_PASSWORD;试试用命令 mysql -uwpuser -p -h localhost 能否登录 |
| 图片上传失败 | 目录权限或 upload_max_filesize 过小 | chown -R nginx:nginx /var/www/blog;调整 upload_max_filesize 和 post_max_size |
| 文章页面 404 | 伪静态规则缺失 | 检查 Nginx 站点配置的 try_files 行,改完记得 nginx -s reload |
6.2 我踩过的几个比较隐蔽的坑
第一,SELinux 导致 Nginx 连不上数据库。很多教程直接让新手把 SELinux 关掉,这是最省事的方案,但也是最不好的习惯。生产环境保持 enforcing 并不会阻碍正常的 Web 服务,只要你放开对应的布尔值。我遇到过 Nginx 配置全部正确,但 WordPress 就是连不上数据库,查了半天才发现是 SELinux 拦截了 Nginx 对 MySQL 的网络连接。解决办法是:
bash复制setsebool -P httpd_can_network_connect_db on
另一个类似情况是,如果你把站点目录放在 /data 这类自定义路径下,SELinux 也会拦截。需要给目录打上 httpd 内容标签:
bash复制semanage fcontext -a -t httpd_sys_content_t "/var/www(/.*)?"
restorecon -Rv /var/www
第二,PHP-FPM 和 Nginx 的用户不一致导致的 403。默认装完 PHP-FPM,进程用户是 apache,而站点目录属主是 nginx,Nginx 读取文件没问题,但 PHP-FPM 没有权限执行或读取部分文件,表现出来就是前面提到的 403 或者空白页。改 www.conf 里的 user 为 nginx 后,需要把运行中的 PHP-FPM 进程完整重启,不是 reload 就行,因为进程用户切换必须重建进程。
第三,PHP 7.4 以下版本连接 MySQL 8 报认证插件错误。MySQL 8 默认用 caching_sha2_password 认证插件,旧版 PHP 的 mysqlnd 驱动不认识它,会报 The server requested authentication method unknown to the client。如果你坚持用老版本 PHP,需要用下面这行把它改回去:
sql复制ALTER USER 'wpuser'@'localhost' IDENTIFIED WITH mysql_native_password BY '密码';
但我更推荐直接用 PHP 8.1 以上版本,官方驱动的兼容性早就没问题了。
第四,改完 Nginx 配置忘了测试就直接重启。Nginx 有个非常实用的测试命令 nginx -t,能检查配置文件语法和引入的路径是否正确。我一般改完配置先跑一遍,没问题再 nginx -s reload,不然一个符号写错,整个服务起不来,连自己的管理后台都进不去了。
第五,WordPress 后台在线更新插件或主题卡住。这个场景经常发生在磁盘空间不足或者 PHP 执行时间受限时。排查方法很直接:df -h 看磁盘,php -i | grep max_execution_time 看超时。如果磁盘快满了,WordPress 下载的临时包没地方放,更新就静默失败。
整套流程走下来,你会发现部署这件事本身并不难,真正决定成败的是那些“默认配置不合理”的细节。每一层服务都有它默认的安全策略和运行方式,花点时间去理解它们为什么这么设计,比背命令要重要得多。我个人的习惯是每次部署完都在终端里记一份操作清单,包括版本号、改了哪些配置、数据库账号是什么,方便下次排查问题的时候快速定位。这套 Nginx + MySQL + PHP + WordPress 的流程你多跑两三遍,基本就形成肌肉记忆了,之后不管是再加一个站点、换一台服务器,还是给它配 HTTPS,都会从容很多。
