拿到一台 VPS 后,搭建网站不只是安装 Nginx。一个可用的站点还需要正确的域名解析、PHP 运行环境、数据库、目录权限、主机防火墙和 HTTPS 证书。任何一层配置错误,都可能表现为“网站打不开”“出现五百错误”或“上传文件失败”。
这篇文章以常见的 LNMP 架构为例,分别说明 Rocky、RHEL、CentOS 系和 Debian、Ubuntu 系的安装方法。LNMP 中的 L 代表 Linux,N 代表 Nginx,M 可以是 MySQL 或兼容的 MariaDB,P 代表 PHP。文中使用 example.com 作为示例域名,操作时必须替换成自己的域名,并先为现有数据和配置做备份。
部署前规划域名、端口和目录
先确认 VPS 具备公网地址,并且本地可以通过 SSH 登录。网站对外至少需要 TCP 80 和 443 端口,管理用的 SSH 端口只应允许管理员来源。数据库默认端口 3306 不需要向公网开放,因为 Nginx、PHP 和数据库都运行在同一台服务器上,可通过本机套接字或回环地址连接。
建议为每个站点建立独立目录,例如:
/var/www/example.com/
├── public/ # 网站公开目录,Nginx 的 root 指向这里
├── storage/ # 应用可写数据,按框架需要创建
└── releases/ # 可选,用于保留发布版本
把 Nginx 根目录指向 public,可以避免配置文件、源码仓库和环境变量文件被直接下载。不要把 .env、数据库备份和私钥放进公开目录。即使 Nginx 配置了隐藏文件拒绝规则,也应从目录结构上减少误暴露风险。
资源方面,小型博客或企业官网可从两个 vCPU、二到四吉字节内存起步。动态插件多、访问峰值高或数据库较大时,需要更多内存与稳定磁盘。这个范围只是经验起点,应根据 PHP 响应时间、数据库慢查询、内存和磁盘延迟调整。
域名解析可以在安装前配置,也可以等本机验证通过后再切换。至少需要一条 A 记录指向 VPS 的 IPv4 地址;若服务器和网络完整支持 IPv6,再添加 AAAA 记录。www 子域可以使用 A 记录或 CNAME 指向主域名。解析生效时间由 DNS 的 TTL 和缓存决定,切换旧站前应提前降低 TTL,并保留回滚记录。
在两类发行版上安装 LNMP
安装前先查看系统版本,并更新软件包:
cat /etc/os-release
Rocky、RHEL、CentOS 系
现代版本优先使用 dnf:
sudo dnf upgrade --refresh -y
sudo dnf install -y nginx mariadb-server php php-fpm php-mysqlnd php-cli php-gd php-mbstring php-xml php-opcache
sudo systemctl enable --now nginx
sudo systemctl enable --now mariadb
sudo systemctl enable --now php-fpm
旧版 CentOS 可以把 dnf 替换为 yum。检查三个服务状态:
systemctl status nginx --no-pager
systemctl status mariadb --no-pager
systemctl status php-fpm --no-pager
RHEL 兼容发行版的 PHP-FPM 常监听 127.0.0.1:9000,也可能由发行版或管理员改成 Unix 套接字。可以用下面命令确认实际配置:
grep -R '^listen =' /etc/php-fpm.d/
sudo ss -lntp | grep 9000
如果没有输出,不要盲目改 Nginx,应检查 /etc/php-fpm.d/www.conf、服务日志和 Unix 套接字路径。
Debian、Ubuntu 系
使用 apt 安装 Nginx、MariaDB 与 PHP-FPM:
sudo apt update
sudo apt upgrade -y
sudo apt install -y nginx mariadb-server php-fpm php-mysql php-cli php-gd php-mbstring php-xml php-opcache
sudo systemctl enable --now nginx
sudo systemctl enable --now mariadb
PHP-FPM 服务名包含版本号,软件包安装时通常会自动启动。可以查看当前单元和套接字:
systemctl list-units --type=service 'php*-fpm.service'
find /run/php -maxdepth 1 -type s -name 'php*-fpm.sock' -print
后面的 Nginx 配置必须填写这里查到的真实套接字,例如 /run/php/php8.2-fpm.sock。版本会随发行版变化,不应复制一个不匹配的固定路径。
初始化数据库
两类系统都可以运行安全初始化向导:
sudo mariadb-secure-installation
某些版本命令名仍是:
sudo mysql_secure_installation
按提示移除匿名用户、禁止远程 root 登录、删除测试库并刷新权限。不同版本对 root 的认证方式不同,不能照搬旧教程强制改成弱密码认证。应用应使用独立数据库和最小权限账号,而不是直接使用 root。
进入数据库控制台后,可执行以下 SQL。请把示例密码替换为随机生成的强密码,并保存在受控的密钥管理位置:
CREATE DATABASE website CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'website_user'@'localhost' IDENTIFIED BY 'REPLACE_WITH_STRONG_PASSWORD';
GRANT ALL PRIVILEGES ON website.* TO 'website_user'@'localhost';
FLUSH PRIVILEGES;
SQL 权限仅覆盖 website 数据库,避免一个站点账号读取其他业务库。生产数据库还要定期导出并把备份复制到另一台主机或对象存储,不能只留在同一块 VPS 磁盘。
创建站点目录并配置 Nginx server
先创建部署用户和站点目录。以下用 deploy 作为文件所有者。Debian、Ubuntu 的 Web 服务组通常是 www-data:
sudo adduser --disabled-password --gecos '' deploy
sudo install -d -o deploy -g www-data -m 2755 /var/www/example.com/public
Rocky、RHEL、CentOS 的 Nginx 组通常是 nginx:
sudo useradd -m -s /bin/bash deploy
sudo install -d -o deploy -g nginx -m 2755 /var/www/example.com/public
若用户已存在,跳过创建命令。2755 中的组继承位可以让新目录沿用站点组,但应用是否需要组写入取决于框架。公开静态文件通常使用目录 755、文件 644;只有上传、缓存或会话目录需要受控写权限。不要执行 chmod -R 777,这会让本机所有用户都能修改网站文件。
创建测试页面:
sudo -u deploy tee /var/www/example.com/public/index.php >/dev/null <<'PHP'
RHEL 系可创建 /etc/nginx/conf.d/example.com.conf:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/public;
index index.php index.html;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
}
location ~ /\. {
deny all;
}
}
如果 grep -R '^listen =' /etc/php-fpm.d/ 显示的是套接字,fastcgi_pass 必须相应修改。不要同时填写不存在的地址。
Debian、Ubuntu 可创建 /etc/nginx/sites-available/example.com,主体基本相同,但 PHP 转发使用实际套接字:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/public;
index index.php index.html;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
location ~ /\. {
deny all;
}
}
上面的 php8.2-fpm.sock 只是格式示例,必须替换为 find /run/php 查到的真实路径。然后启用站点:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
每次修改都先做语法检查,再平滑重载:
sudo nginx -t
sudo systemctl reload nginx
curl -H 'Host: example.com' http://127.0.0.1/
如果 nginx -t 失败,不要重载。根据输出中的文件和行号修正,必要时恢复改动前备份。测试通过后应删除显示环境详情的测试脚本,尤其不要把 phpinfo() 页面长期暴露公网,因为它会泄露路径、模块和配置参数。
处理权限、SELinux 和应用发布
网站代码建议由部署用户持有,Nginx 与 PHP-FPM 只获得读取权限。需要写入的目录单独授权。例如 Debian、Ubuntu 下应用需要写 storage:
sudo install -d -o deploy -g www-data -m 2770 /var/www/example.com/storage
sudo find /var/www/example.com/public -type d -exec chmod 755 {} \;
sudo find /var/www/example.com/public -type f -exec chmod 644 {} \;
RHEL 系把组名换成 nginx,但还要考虑 SELinux。不要直接执行 setenforce 0 长期关闭保护。先安装管理工具并设置内容标签:
sudo dnf install -y policycoreutils-python-utils
sudo semanage fcontext -a -t httpd_sys_content_t '/var/www/example.com(/.*)?'
sudo restorecon -Rv /var/www/example.com
若确实有运行时可写目录,仅给该目录写标签:
sudo semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/example.com/storage(/.*)?'
sudo restorecon -Rv /var/www/example.com/storage
使用数据库时,如果 PHP 通过本机 TCP 连接而被 SELinux 拒绝,应先查看审计日志确认原因,再决定是否启用相应布尔值。不能看到五百错误就关闭 SELinux。常用排查命令如下:
sudo ausearch -m AVC -ts recent
sudo journalctl -u php-fpm -n 100 --no-pager
sudo tail -n 100 /var/log/nginx/example.com.error.log
正式发布时,先把新版本上传到独立目录,安装依赖并做健康检查,再切换软链接或替换站点路径。保留上一个可运行版本能加快回滚。数据库结构变更必须单独备份,并确认旧程序能否兼容新结构,不能只回滚代码。
敏感配置不应提交到 Git。数据库密码、邮件凭据和第三方令牌可放在站点公开目录之外的配置文件中,限制为应用用户可读。备份文件也不要使用 .bak 后缀直接留在 public 下,因为 Nginx 可能把它当普通文件下载。
配置 DNS、放行 80/443 并启用 HTTPS
在 DNS 管理处添加 A 记录后,可以从本地检查解析:
nslookup example.com
也可以在 Linux 终端使用:
getent ahosts example.com
确认结果指向新 VPS,再放行网络。云平台安全组需要入站允许 TCP 80 和 443,来源通常是公网;SSH 仍只允许管理员地址。安全组放行后,还要配置系统防火墙。
Rocky、RHEL、CentOS 使用 firewalld:
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
Debian、Ubuntu 使用 UFW:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
风险提示:启用主机防火墙前,必须确认实际 SSH 端口已放行,并保留当前连接。若误封,可通过云控制台终端执行 sudo ufw disable,或修复 firewalld 规则。不要在没有控制台救援手段时远程一次性修改 SSH 端口和防火墙。
DNS 生效且 80 端口可访问后,可申请 HTTPS 证书。Debian、Ubuntu 可安装 Certbot 的 Nginx 插件:
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
RHEL 兼容发行版需先确保软件仓库提供对应包,再安装:
sudo dnf install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
Certbot 会验证域名是否指向当前服务器,因此解析错误、端口未开放或反向代理拦截都会导致失败。签发后测试自动续期:
sudo certbot renew --dry-run
最后分别访问 HTTP 与 HTTPS,确认 HTTP 是否按预期跳转、证书域名是否匹配、PHP 页面是否正常。还应检查访问日志、错误日志和证书续期定时器。若站点有表单登录,应在 HTTPS 正常后再开放真实用户访问。
常见问题
浏览器显示五百错误,先查什么?
先运行 nginx -t,再查看站点错误日志和 PHP-FPM 日志。常见原因是 PHP 套接字路径写错、文件权限不足、应用配置缺失或数据库连接失败,不要直接把目录改成 777。
出现五零二 Bad Gateway 怎么办?
通常是 Nginx 无法连接 PHP-FPM。检查 PHP-FPM 服务是否运行、listen 配置与 fastcgi_pass 是否一致、套接字权限是否允许 Nginx 访问,并查看对应服务日志。
域名已经解析,为什么仍显示旧网站?
可能是本地或递归 DNS 缓存尚未过期,也可能访问了 www 与主域名中的另一个记录。分别查询 A、AAAA 记录,确认没有旧 IPv6 地址,并等待 TTL 到期。
可以把 MySQL 3306 端口开放公网吗?
同机部署完全没有必要。跨服务器访问也应优先走私有网络,并把来源限制为应用服务器。若必须远程管理,使用 VPN 或 SSH 隧道,不要对全网开放数据库端口。
快照能替代网站备份吗?
不能。快照可能与 VPS 位于同一平台,也可能只提供崩溃一致性。网站应定期备份数据库和上传文件到独立存储,并实际恢复到测试环境验证。
总结
- LNMP 建站要同时处理 Nginx、数据库、PHP-FPM、域名、权限和防火墙,不能只完成软件安装。
- Nginx 的站点根目录应指向公开子目录,数据库和 PHP 套接字使用实际环境值,修改后先执行语法检查再重载。
- 代码由部署用户持有,只给必要目录写权限;不要使用
777,RHEL 系优先正确配置 SELinux 标签。 - 安全组与主机防火墙都要放行 80/443,SSH 只允许受控来源,数据库端口不对公网开放。
- HTTPS 签发后要验证自动续期,网站数据还需异地备份和恢复演练,不能只依赖本机或单个平台快照。
企业QQ咨询




