PHP云系统搭建教程:从环境配置到项目部署

资讯1小时前发布 jdkjadmin
0 00
PHP云系统搭建教程:从环境配置到项目部署

PHP云系统搭建教程:从环境配置到项目部署

把 PHP 项目部署到云服务器,通常不是安装一个 PHP 软件包就结束了。还需要配置 Web 服务器、PHP 运行进程、数据库、域名和 HTTPS,并明确哪些文件可以被公网访问、哪些数据必须留在服务器内部。本文以 Ubuntu 24.04、Nginx、PHP 8.3、MariaDB 为例,搭建一个能运行的最小项目,再说明如何将同一套思路用于现有 PHP 应用。

文中的命令适合有 SSH 管理权限的 Linux 云主机。不同云厂商的控制台、网络规则和镜像可能不同;如果使用托管 PHP、容器平台或已有运维规范,应以对应平台文档为准。示例不包含高可用、自动扩缩容或完整的生产级监控方案。

一、先明确“云系统”的范围

这里的“PHP 云系统”指部署在云服务器或云平台上的 PHP 网站或业务应用,例如企业后台、内容管理系统、接口服务和内部工具。它不等同于云厂商的数据库、对象存储或云原生平台;这些服务可以作为应用的外部依赖,但需要单独配置访问权限、费用和备份策略。

  • 适合的场景:已有 PHP 项目需要上线;单台或少量服务器运行中小型网站;需要自行控制运行环境、数据库和发布过程。
  • 不适合直接照搬的场景:要求多机容灾、严格合规、超大并发或自动弹性伸缩的系统。此类项目还需要负载均衡、共享会话或外部缓存、数据库高可用、集中日志与故障演练。
  • 重要边界:云服务器只提供计算和网络资源,不会自动保证代码安全、数据库可恢复或服务持续可用。HTTPS、访问控制、更新和备份仍需自行负责。

二、准备云服务器和域名

创建一台 Ubuntu 24.04 LTS 云服务器。学习或小型项目可以从 2 核 CPU、2GB 内存起步,但实际容量取决于 PHP 请求耗时、数据库大小、并发量和后台任务。不要把示例规格理解成性能保证。

在云厂商安全组或防火墙中,通常只需开放:

  • TCP 22:SSH 管理。建议限制来源为自己的固定 IP;如果没有固定 IP,也应使用密钥登录并按需调整策略。
  • TCP 80:HTTP,用于网站访问和证书签发验证。
  • TCP 443:HTTPS。

不要将 MariaDB 的 3306 端口直接对全网开放。SSH 的默认端口是否修改,不是安全的替代措施;重点是密钥认证、来源限制和及时更新系统。登录服务器后先更新软件包:

sudo apt update
sudo apt upgrade -y

创建独立的部署用户并使用 SSH 密钥,是比长期使用 root 远程登录更好的管理方式。不同云镜像默认用户名称可能是 ubuntu、debian 或厂商自定义账号;应以创建实例时的说明为准。修改 SSH 配置前,先确认新用户能登录,并保留当前 SSH 会话,避免配置错误导致无法管理。

三、安装 Nginx、PHP-FPM 和 MariaDB

在 Ubuntu 24.04 官方软件源中,可安装 PHP 8.3 及其 FPM、MySQL 驱动。若项目指定其他 PHP 版本,应先核对系统源和项目依赖,不要未经测试就跨大版本升级。

sudo apt install -y nginx mariadb-server \
  php8.3-fpm php8.3-cli php8.3-mysql php8.3-curl \
  php8.3-mbstring php8.3-xml php8.3-zip

检查服务状态和 PHP 版本:

sudo systemctl status nginx
sudo systemctl status php8.3-fpm
php -v
php -m

项目可能还需要 gd、intl、redis 等扩展。应根据项目的 composer.json、安装说明或 composer check-platform-reqs 检查结果安装,而不是把所有扩展都装上。生产服务器通常应启用 FPM,不应通过 Nginx 直接执行 PHP。

四、创建数据库和最小应用

MariaDB 的本地管理通常使用系统授权机制。进入数据库控制台:

sudo mariadb

创建仅供本项目使用的数据库账号。把示例密码替换为随机生成的强密码,不要复制示例字符串用于真实服务:

CREATE DATABASE cloudapp
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

CREATE USER 'cloudapp_user'@'localhost'
  IDENTIFIED BY '替换为随机生成的强密码';

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX
  ON cloudapp.* TO 'cloudapp_user'@'localhost';

FLUSH PRIVILEGES;
EXIT;

上述授权适合演示建表和常规增删改查。真实项目可把部署迁移账号与运行时账号分开:运行时账号只保留必要权限,迁移时再临时使用建表权限。不要使用数据库 root 账号连接网站,也不要把数据库暴露到公网。

建立项目目录。这里将公开入口放在 public,配置文件放在网站根目录之外:

sudo mkdir -p /var/www/cloudapp/public
sudo mkdir -p /var/www/cloudapp/shared
sudo chown -R "$USER":www-data /var/www/cloudapp
sudo chmod 750 /var/www/cloudapp /var/www/cloudapp/shared
sudo chmod 750 /var/www/cloudapp/public

创建数据库配置文件:

sudo nano /var/www/cloudapp/shared/config.php

写入以下内容,并替换密码。配置文件是 PHP 文件,不能放在 public 目录中。目录权限应允许 PHP-FPM 用户读取,但不应对所有本地用户开放:

<?php
return [
    'dsn' => 'mysql:host=127.0.0.1;dbname=cloudapp;charset=utf8mb4',
    'user' => 'cloudapp_user',
    'password' => '替换为随机生成的强密码',
];
sudo chown root:www-data /var/www/cloudapp/shared/config.php
sudo chmod 640 /var/www/cloudapp/shared/config.php

为演示准备一张表。实际项目应通过框架迁移工具或版本化 SQL 管理结构变更:

sudo mariadb
USE cloudapp;

CREATE TABLE notes (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  body VARCHAR(500) NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);

EXIT;

创建 /var/www/cloudapp/public/index.php,提供列表展示和新增功能:

<?php
declare(strict_types=1);

$config = require '/var/www/cloudapp/shared/config.php';

try {
    $pdo = new PDO(
        $config['dsn'],
        $config['user'],
        $config['password'],
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES => false,
        ]
    );
} catch (PDOException $e) {
    error_log('Database connection failed: ' . $e->getMessage());
    http_response_code(500);
    exit('服务暂时不可用');
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $body = trim((string)($_POST['body'] ?? ''));

    if ($body === '' || mb_strlen($body, 'UTF-8') > 500) {
        http_response_code(422);
        exit('内容不能为空,且不能超过500个字符');
    }

    $stmt = $pdo->prepare('INSERT INTO notes (body) VALUES (:body)');
    $stmt->execute(['body' => $body]);

    header('Location: /', true, 303);
    exit;
}

$notes = $pdo->query(
    'SELECT id, body, created_at FROM notes ORDER BY id DESC LIMIT 100'
)->fetchAll();

function h(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
?>
<!doctype html>
<html lang="zh-CN">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>云端便笺</title>
<h1>云端便笺</h1>
<form method="post">
  <label>内容
    <input name="body" maxlength="500" required>
  </label>
  <button type="submit">保存</button>
</form>
<ul>
<?php foreach ($notes as $note): ?>
  <li><?= h($note['body']) ?>
    <small><?= h($note['created_at']) ?></small>
  </li>
<?php endforeach; ?>
</ul>
</html>

代码使用 PDO 预处理语句,避免把用户输入直接拼接进 SQL;输出时通过 htmlspecialchars 转义,降低内容被浏览器当作 HTML 执行的风险。输入长度限制是应用层校验,不代替数据库约束,也不等同于完整的业务校验。这个演示没有登录、权限控制、CSRF 防护和限流,因此不能直接作为多用户生产系统使用。

五、配置 Nginx,让公网只访问公开目录

将 example.com 换成自己的域名,并先在 DNS 中把域名的 A 记录指向服务器公网 IPv4 地址。如果使用 IPv6,还需正确配置 AAAA 记录和对应网络规则。

创建站点配置:

sudo nano /etc/nginx/sites-available/cloudapp
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/cloudapp/public;
    index index.php;

    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.3-fpm.sock;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}

root 指向 public,这样配置文件和项目内部文件不会因为路径配置失误而直接暴露。该示例用于普通 PHP 页面;如果是 Laravel、Symfony 等框架,还应按框架要求配置入口文件、重写规则和静态资源目录。

启用站点并检查配置:

sudo ln -s /etc/nginx/sites-available/cloudapp \
  /etc/nginx/sites-enabled/cloudapp
sudo nginx -t
sudo systemctl reload nginx

如果默认站点占用了相同域名或造成访问到错误站点,可以检查 /etc/nginx/sites-enabled/,确认没有不需要的默认配置。修改配置后先执行 nginx -t,通过后再 reload;不要在配置错误时直接重启服务。

六、检查权限并测试应用

Nginx 和 PHP-FPM 在 Ubuntu 软件包的默认配置中通常以 www-data 用户运行。先测试网页目录和配置文件是否可读:

sudo -u www-data test -r /var/www/cloudapp/public/index.php \
  && echo "入口文件可读"
sudo -u www-data test -r /var/www/cloudapp/shared/config.php \
  && echo "配置文件可读"

不需要给整个项目目录设置 777。只有应用确实需要写入的目录,例如上传文件或缓存目录,才应授予 PHP-FPM 写权限,并限制该目录中的文件类型和可执行能力。用户上传的文件最好放在 Web 根目录之外;如必须公开提供下载,应使用受控的下载接口或专用静态存储。

从浏览器访问域名,或在服务器上用 curl 检查:

curl -I http://example.com
curl -sS http://example.com

如果访问出现 502,通常是 Nginx 找不到 PHP-FPM socket、服务未运行或权限不符;404 可能是域名未命中正确站点、入口文件不存在或路由规则不适用;页面出现“服务暂时不可用”,应查看 PHP-FPM 与 Nginx 日志,而不是在浏览器输出数据库密码或完整异常堆栈。

七、启用 HTTPS

确认域名已经解析到服务器,且安全组放行 80、443 后,可使用 Certbot 的 Nginx 插件申请证书。Ubuntu 24.04 可从发行版软件源安装:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

根据交互提示选择是否将 HTTP 重定向到 HTTPS。证书签发失败时,先核对 DNS 解析、域名拼写和公网端口,不要通过关闭防火墙或开放数据库端口来排错。检查自动续期定时任务:

sudo certbot renew --dry-run

HTTPS 保护浏览器与服务器之间的传输,不会自动加密数据库备份、修复 SQL 注入,也不代表服务器上所有通信都安全。证书续期和域名变更都应纳入维护流程。

八、把示例迁移到真实 PHP 项目

对于使用 Composer 的项目,建议在 CI 构建或发布机上安装依赖,再将可部署产物发布到服务器。常见命令如下,是否能使用 --no-dev 取决于项目是否把运行时依赖错误地放在开发依赖中:

composer install --no-dev --prefer-dist --optimize-autoloader
composer check-platform-reqs

不要在生产服务器上执行未经审查的第三方安装脚本。部署前检查项目版本要求、PHP 扩展、环境配置和数据库迁移;发布后执行健康检查。框架的缓存、队列、定时任务和文件权限配置各不相同,应以项目文档为准。

一个相对可靠的发布过程通常包含:拉取固定版本或发布包、安装依赖、备份数据库、运行迁移、切换当前版本、验证关键功能。不要直接在正在服务的目录中覆盖文件;中断期间可能出现新旧代码混用。小型系统可以用版本目录和符号链接实现切换,但回滚代码并不一定能回滚数据库结构变更,迁移设计要考虑兼容性。

敏感配置不要提交到 Git,也不要写进可公开下载的配置文件。可以使用服务器权限保护的配置文件或平台提供的密钥管理服务;前者需要控制文件读取权限,后者也要限制谁能读取密钥。修改密码后应同步更新配置,并安排数据库账号轮换。

九、日志、备份与日常维护

先熟悉服务日志的实际位置:

sudo journalctl -u nginx --since "30 minutes ago"
sudo journalctl -u php8.3-fpm --since "30 minutes ago"
sudo tail -n 100 /var/log/nginx/error.log
sudo tail -n 100 /var/log/nginx/access.log

生产环境应关闭向客户端展示详细错误信息,将异常写入受控日志,并避免在日志中记录密码、令牌、完整支付信息等敏感数据。日志需要轮转和保留策略;只查看日志而不限制其增长,仍可能耗尽磁盘。

数据库备份可用 mariadb-dump 导出。下面命令将 SQL 写到标准输出,备份文件应放到受限目录,并避免将密码直接写在命令行参数里,以免暴露在 shell 历史或进程信息中:

sudo install -d -m 700 /var/backups/cloudapp
sudo mariadb-dump cloudapp \
  | gzip \
  | sudo tee /var/backups/cloudapp/cloudapp-$(date +%F).sql.gz > /dev/null
sudo chmod 600 /var/backups/cloudapp/cloudapp-$(date +%F).sql.gz

该命令适用于本机 MariaDB 且当前系统用户具备数据库访问权限的情况;若认证方式不同,应按实际账号配置。备份保存在同一台服务器,无法防范服务器丢失或磁盘故障。生产环境应把备份复制到独立存储,限制访问,并定期在隔离环境中实际恢复验证。备份成功不等于可恢复。

还应定期检查系统安全更新、磁盘空间、证书到期、数据库容量和应用错误率。云平台快照可以作为补充,但不能替代数据库一致性备份和恢复演练。

十、常见错误及排查顺序

1. 域名访问到错误页面

先检查 DNS 是否指向正确公网地址,再核对 Nginx 的 server_name、站点是否启用以及安全组是否放行 80/443。多个站点使用同一端口时,Nginx 会根据请求主机名选择站点;域名不匹配时可能落到默认站点。

2. PHP 文件被下载或显示源码

这是高风险配置错误,说明请求没有正确交给 PHP-FPM。立即停止对外访问并检查 Nginx 的 PHP location、FPM socket 路径和服务状态。不要把应用的 PHP 源码、配置或密钥留在公开目录中;修复后还要评估是否已经发生泄露并轮换受影响凭据。

3. Nginx 返回 502 Bad Gateway

检查 systemctl status php8.3-fpm、PHP-FPM 日志和 Nginx 中的 socket 路径。PHP 版本升级后,socket 名称可能改变。若使用 TCP 监听而非 Unix socket,还要确认监听地址与访问控制设置一致。

4. 数据库连接失败或提示拒绝访问

核对配置文件是否可读、数据库名和账号是否正确、数据库服务是否运行,以及账号允许连接的主机范围。使用 localhost 与 127.0.0.1 时,客户端可能采用不同连接方式;不要为绕过问题而给账号授予全网访问权限。

5. 上传、缓存或日志目录出现权限错误

不要用递归 777 解决。确认实际运行用户,再只对确需写入的目录设置所有者或组权限;其余 PHP 代码应保持只读。权限调整前先查明哪个进程需要写入,避免让 Web 进程可以修改全部应用代码。

6. 页面报错但日志里没有应用异常

核对 PHP 错误日志配置、应用日志目录权限和日志级别。还要检查磁盘是否已满、PHP-FPM 是否达到进程上限、请求是否超时。提高超时或进程数会增加资源消耗,不应只为消除报错而无限增大。

结语

PHP 项目上云的基本链路是:云主机提供运行环境,Nginx 接收 HTTP 请求,PHP-FPM 执行 PHP,数据库保存结构化数据,域名和 HTTPS 提供可访问入口。真正决定部署是否可靠的,往往不是安装命令,而是公开目录边界、最小权限、错误处理、备份恢复和可重复发布。

本文示例可以帮助验证一台 Ubuntu 云服务器上的基础 PHP 部署,但便笺程序刻意保持简单,不具备生产系统所需的身份认证、授权、CSRF 防护、审计、限流和高可用能力。上线业务前,应结合数据敏感度、访问规模和恢复目标补齐这些设计,并先在测试环境验证升级与回滚流程。

© 版权声明

相关文章