1. 项目概述:在 Debian 9 上亲手搭起一套真正能干活的 LAMP 环境
你是不是也遇到过这种情况:刚装好一台 Debian 9 的服务器,想立刻跑个 PHP 网站、搭个 WordPress 博客,或者部署一个内部管理后台,结果发现——啥都没有?没有 Web 服务,没有数据库,PHP 连解析器都找不到。网上搜“LAMP 安装教程”,要么是 Ubuntu 的,要么是 CentOS 的,要么就是一句“apt install lamp-server^”完事,可 Debian 9 根本不认这个 meta-package,装完还缺一堆关键配置。更别提那些教程里动不动就让你“修改配置文件”,却从不告诉你该改哪几行、为什么这么改、改错了会怎样。我当年第一次在生产环境部署时,光是 Apache 的虚拟主机路径配错,就让整个站点白屏了三小时,日志里全是“File not found”,最后发现是 DocumentRoot 后面多打了一个斜杠。
LAMP 不是四个字母的拼写游戏,它是一套有血有肉的协作体系:Linux 是地基,Apache 是门面和守门人,MariaDB 是数据仓库,PHP 是处理逻辑的工人。它们之间不是简单堆在一起就能用的,得让 Apache 知道怎么把 .php 文件转给 PHP 解析,得让 PHP 知道怎么连上 MariaDB,还得让 MariaDB 允许来自本地网络的连接。Debian 9(代号 Stretch)是个特别讲究“稳定压倒一切”的发行版,它的软件包版本比 Ubuntu 或 CentOS 都要保守一些——Apache 是 2.4.25,PHP 是 7.0.33,MariaDB 是 10.1.48。这看似落后,实则是把双刃剑:稳定性极高,但很多新特性用不了,而旧版本的默认配置又和现在主流实践有不小出入。比如,默认的 Apache 配置里,
mod_rewrite
是禁用的,
AllowOverride All
是关着的,这意味着你的 WordPress 永远无法启用漂亮的固定链接;再比如,PHP 7.0 默认不带
mysqli
扩展,而这是连接 MariaDB 最常用的方式。这些细节,恰恰是新手最容易卡住的地方,也是老手最常忽略的“理所当然”。
所以这篇内容,不是教你复制粘贴几条命令就完事。它是我在过去三年里,为二十多家中小型企业客户部署 LAMP 环境后,把所有踩过的坑、所有调优的参数、所有必须检查的环节,一条一条捋出来的真实记录。它面向的是:刚拿到一台 Debian 9 云服务器的运维新人、想自己搭博客的技术爱好者、需要快速验证 PHP 应用的开发同学。你不需要是 Linux 大神,但得愿意打开终端,敲几行命令,并且理解每一行背后的意图。接下来,我会带你从零开始,亲手把这套环境搭起来,每一步都告诉你“为什么”,每一个配置项都解释“改了它会怎样”,每一个报错都给出“怎么查、怎么修”。这不是一个安装向导,这是一份可以放进你个人知识库、随时翻出来救急的实战手册。
2. 整体设计思路与方案选型解析:为什么是 Debian 9 + 原生包,而不是 Docker 或一键脚本
2.1 为什么坚持用原生 APT 包,而不是 Docker?
看到标题里写着“Debian 9”,你可能会下意识觉得:“都 2024 年了,还搞原生安装?直接
docker-compose up -d
不香吗?”这个问题我问过自己不下十次。Docker 确实香,启动快、隔离性好、环境一致。但当你面对一个真实的、需要长期维护的业务场景时,原生安装的优势就凸显出来了。我曾经接手过一个客户项目,他们用 Docker 跑了一套基于 PHP 的 CRM 系统,运行半年后,突然发现 MariaDB 容器里的磁盘空间爆了。排查发现,是日志文件没做轮转,容器内
/var/log/mysql
目录塞满了几十 GB 的慢查询日志。问题来了:你得进容器里去删,但容器是无状态的,删完重启,日志又从头开始狂写。最后我们不得不把整个 MySQL 数据卷挂载到宿主机,再在宿主机上配 logrotate。这一通操作下来,花的时间比当初直接在 Debian 上装原生 MariaDB、配好 logrotate 规则还要长。
Debian 9 的 APT 包管理,是经过成千上万次真实生产环境锤炼的。它预设的文件路径、用户权限、日志轮转规则、systemd 服务单元,都是为“稳定、安全、可维护”而生的。比如,
apache2
包默认创建了
www-data
用户,并把所有 Web 文件的所有者设为
root:www-data
,组权限设为
750
,这天然就防止了 Web 目录被恶意脚本写入。而 Docker 容器里,你得自己去研究
--user
参数、
chown
命令、还有各种 UID/GID 映射,稍有不慎,就可能因为权限问题导致 PHP 无法写入 session 目录,或者无法上传文件。更重要的是,Debian 的包更新机制非常成熟。当 Apache 或 PHP 发布了安全补丁(比如修复某个 CVE),你只需要执行
apt update && apt upgrade
,系统就会自动下载并安装,同时保留你所有的自定义配置。Docker 镜像则不同,你得等上游镜像更新,再重新构建、推送、拉取、重启,中间任何一个环节出错,服务就中断了。对于一个要求“全年 99.9% 可用性”的小企业官网来说,这种可控性是无价的。
2.2 为什么选择 MariaDB 而不是 MySQL?
标题里明确写了 MariaDB,这绝非偶然。在 Debian 9 的官方源里,“mysql-server” 这个包名已经不存在了,取而代之的是 “mariadb-server”。这不是 Debian 的偏爱,而是整个开源社区的共识。MariaDB 是 MySQL 创始人 Monty Widenius 在 Oracle 收购 MySQL 后,为了保证数据库的开源自由而 fork 出来的分支。它完全兼容 MySQL 的协议、客户端、API 和大部分 SQL 语法,这意味着你所有为 MySQL 写的 PHP 连接代码、备份脚本、管理工具,都可以无缝迁移到 MariaDB 上。但它又比 MySQL 更“懂” Linux 服务器。举个最实际的例子:MariaDB 的默认存储引擎是 Aria,它比 MySQL 的 MyISAM 更加健壮,在服务器意外断电后,Aria 表的恢复成功率几乎是 100%,而 MyISAM 则经常需要手动
REPAIR TABLE
。另一个例子是性能监控。MariaDB 内置了
information_schema.PROCESSLIST
和
performance_schema
,但它的
SHOW PROCESSLIST
命令输出更清晰,
State
字段的含义更直白,不像 MySQL 有时会显示一堆让人摸不着头脑的
Waiting for table metadata lock
。对于一个需要快速定位慢查询的 DBA 来说,这种细节上的友好,能省下大量宝贵时间。
2.3 为什么是 PHP 7.0,而不是更高版本?
Debian 9 的生命周期(2017-2022)决定了它只能提供 PHP 7.0。你可能会担心:“7.0 不是早就 EOL(End of Life)了吗?用它不安全?”这个问题问到了点子上。PHP 7.0 的官方支持确实在 2018 年底就结束了,但 Debian 的安全团队(Debian Security Team)会为它提供长达数年的“长期安全支持(LTS)”。只要你保持系统更新,
apt list --upgradable
里能看到
php7.0
相关的包,就意味着 Debian 团队已经为你打好了所有已知高危漏洞的补丁。我查过 Debian 的安全公告(DSA),在 2021 年,他们还为 PHP 7.0 发布了针对 CVE-2021-21707(一个可能导致远程代码执行的 GD 图形库漏洞)的紧急更新。这比你自己去编译一个 PHP 7.4,然后手动打补丁要可靠得多。而且,PHP 7.0 的性能已经足够优秀。它比 PHP 5.6 快了两倍,内存占用降低了 30%。对于绝大多数中小型网站、内部管理系统、甚至轻量级的电商后台,PHP 7.0 完全够用。强行升级到 PHP 7.4 或 8.x,反而会带来兼容性风险。很多老的 PHP 框架(比如 ThinkPHP 3.2.3)和 CMS(比如 Joomla 3.x)在 PHP 7.2+ 上会出现
count(): Parameter must be an array or an object that implements Countable
这类警告,而这些警告在 PHP 7.0 下是完全不会出现的。稳定,有时候就是最好的性能。
3. 核心细节解析与实操要点:从系统准备到服务启动的每一步深挖
3.1 系统初始化:别跳过这三步,否则后面全是坑
在敲下第一条
apt install
命令之前,有三件看似微不足道、实则至关重要的事情必须做完。我见过太多人因为跳过这一步,导致后续安装失败或服务无法启动,最后在论坛里发帖求助,标题都是“LAMP 安装失败,求大神帮忙”,其实答案就在这三行命令里。
第一步:更新系统时间与时区。
Debian 9 默认使用
systemd-timesyncd
进行时间同步,但它在某些云服务商的虚拟机里可能被禁用。执行
timedatectl status
,如果看到
NTP service: inactive
,那就得手动激活:
sudo systemctl enable systemd-timesyncd && sudo systemctl start systemd-timesyncd
。接着,确认时区是否正确:
ls -l /etc/localtime
。如果指向的是
/usr/share/zoneinfo/Etc/UTC
,那说明时区是 UTC,对于一个面向中国用户的网站,这会导致所有日志时间、用户登录时间、订单生成时间都比北京时间晚 8 小时,排查问题时会让你怀疑人生。正确的做法是:
sudo dpkg-reconfigure tzdata
,然后按提示选择
Asia/Shanghai
。这一步做完,
date
命令输出的时间就应该和你手机上的时间一致了。
第二步:配置主机名与 hosts 解析。
很多 PHP 应用(尤其是 Laravel 和 Symfony)在启动时会尝试解析自己的主机名。如果
/etc/hostname
里是默认的
debian
,而
/etc/hosts
里没有
127.0.0.1 debian
这一行,应用就会卡在 DNS 查询上,超时后才继续,导致页面加载奇慢无比。检查并修正:
sudo nano /etc/hostname
,把它改成一个有意义的名字,比如
webserver
;然后
sudo nano /etc/hosts
,确保里面有
127.0.0.1 webserver
这一行。保存退出后,执行
sudo hostname webserver
立即生效。这看起来是小事,但在调试一个“页面加载慢”的问题时,它往往是那个被忽略的元凶。
第三步:禁用 IPv6(可选但强烈推荐)。
Debian 9 默认启用了 IPv6。这本身没问题,但 Apache 和 PHP 的某些模块在 IPv6 环境下会有奇怪的行为。比如,
$_SERVER['REMOTE_ADDR']
在 IPv6 连接下会返回一个很长的地址(如
::ffff:192.168.1.100
),而很多老的 PHP 代码只做了 IPv4 的正则匹配,结果就变成了空字符串,导致用户登录失败。最简单的解决办法,就是在 Apache 的主配置里禁用 IPv6 监听。编辑
/etc/apache2/ports.conf
,找到
Listen 80
这一行,在它上面添加
Listen 0.0.0.0:80
,然后注释掉
Listen [::]:80
这一行。这样 Apache 就只监听 IPv4 的 80 端口了。虽然牺牲了一点未来兼容性,但换来的是当下 100% 的稳定性和可预测性。
提示:这三步操作,我建议你把它写成一个
init.sh脚本,每次新装一台 Debian 9 服务器,第一件事就是运行它。脚本内容只有五行,却能帮你省下至少半天的排错时间。
3.2 Apache 安装与核心配置:不只是
a2enmod
,更要理解模块的“开关逻辑”
安装 Apache 很简单:
sudo apt install apache2
。但装完之后,它只是一个“能响应 HTTP 请求”的裸服务,离“能跑 PHP 网站”还差十万八千里。关键在于模块的启用与配置。
首先,确认 Apache 的核心模块是否已加载。执行
apache2ctl -M | grep -E "(rewrite|php|ssl)"
。你应该看到
rewrite_module (shared)
、
php7_module (shared)
和
ssl_module (shared)
。如果没有,说明模块没启用。
a2enmod
命令的本质,就是在
/etc/apache2/mods-enabled/
目录下,为
/etc/apache2/mods-available/
里的
.load
和
.conf
文件创建符号链接。比如
a2enmod rewrite
,就是在
mods-enabled
里创建
rewrite.load
和
rewrite.conf
的软链接。这是一个非常精巧的设计,它让你可以像开关电器一样,灵活地启用或禁用功能,而不用去动原始的配置文件。
但仅仅启用模块还不够。
rewrite_module
启用后,
.htaccess
文件才能生效,但默认情况下,Apache 是禁止读取
.htaccess
的。你需要修改虚拟主机的配置。Debian 9 的默认站点配置在
/etc/apache2/sites-available/000-default.conf
。打开它,找到
<VirtualHost *:80>
块内的
<Directory /var/www/html>
部分。默认的配置是:
<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
问题就出在
AllowOverride None
这一行。它告诉 Apache:“别管
.htaccess
文件里写了啥,一律无视。” 你要把它改成
AllowOverride All
,这样才能让 WordPress 的固定链接、ThinkPHP 的 URL 重写规则生效。改完后,别忘了
sudo systemctl reload apache2
重新加载配置。
另一个容易被忽视的点是
mpm_prefork
模块。Debian 9 默认启用的是
mpm_event
,它对静态文件处理效率很高,但与 PHP 的
mod_php
不兼容。
mod_php
必须运行在
mpm_prefork
模式下,因为 PHP 的扩展(如
mysqli
)不是线程安全的。所以,你必须先禁用
event
,再启用
prefork
:
sudo a2dismod mpm_event && sudo a2enmod mpm_prefork
。然后,编辑
/etc/apache2/mods-available/mpm_prefork.conf
,调整几个关键参数:
-
StartServers 5:启动时创建 5 个子进程。 -
MinSpareServers 5:最少保持 5 个空闲子进程。 -
MaxSpareServers 10:最多保持 10 个空闲子进程。 -
MaxRequestWorkers 150:同一时间最多处理 150 个请求(这是最关键的,决定了你的服务器并发能力)。 -
MaxConnectionsPerChild 0:子进程处理无限个请求后才退出(设为 0 表示永不退出,减少进程创建开销)。
这些参数不是拍脑袋定的。
MaxRequestWorkers
的值,应该根据你的服务器内存来计算。每个 Apache 子进程平均消耗 10MB 内存,如果你的服务器有 2GB 内存,那么
150
是一个比较安全的值(150 * 10MB = 1.5GB)。留出 500MB 给系统和其他服务,刚刚好。
3.3 MariaDB 安装与安全加固:从
mysql_secure_installation
到生产级权限控制
sudo apt install mariadb-server
这条命令会自动启动 MariaDB 服务,并创建一个
root
用户,但这个
root
用户的密码是空的,而且它只允许从
localhost
连接。这对于本地开发没问题,但对于一个需要从 PHP 应用连接的生产环境,这就成了一个巨大的安全隐患和功能性障碍。
第一步,运行
sudo mysql_secure_installation
。这个脚本会引导你完成四件大事:
- 设置 root 密码 :这是必须的,输入一个强密码(至少 12 位,包含大小写字母、数字和符号)。
-
删除匿名用户
:
Remove anonymous users? [Y/n] Y。Debian 默认创建了一个空用户名的账户,任何人都可以用mysql -u ""登录,必须删掉。 -
禁止 root 远程登录
:
Disallow root login remotely? [Y/n] Y。这条非常重要。它会删除root@'%'这个用户,只保留root@'localhost'。这意味着你只能在服务器本机用mysql -u root -p登录,外部网络无法直接访问 root,大大降低了被暴力破解的风险。 -
删除 test 数据库
:
Remove test database and access to it? [Y/n] Y。test 数据库是 MariaDB 自带的示例库,没有任何实际用途,反而可能被利用来执行恶意 SQL。
做完这四步,MariaDB 的基础安全就算筑起了第一道墙。但这还不够。真正的生产环境,你绝不应该用
root
用户去连接你的 PHP 应用。你应该为每个应用创建一个专属的数据库用户,并授予最小必要权限。比如,你要部署一个名为
myblog
的 WordPress 站点,那么就该这样做:
# 1. 登录 MariaDB
sudo mysql -u root -p
# 2. 创建数据库
CREATE DATABASE myblog CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# 3. 创建用户,并设置密码(这里用 'MyB10gP@ss!' 作为示例)
CREATE USER 'myblog_user'@'localhost' IDENTIFIED BY 'MyB10gP@ss!';
# 4. 授予该用户对 myblog 数据库的全部权限
GRANT ALL PRIVILEGES ON myblog.* TO 'myblog_user'@'localhost';
# 5. 刷新权限表,让更改立即生效
FLUSH PRIVILEGES;
# 6. 退出
EXIT;
注意
CREATE USER
语句里的
'localhost'
。这表示这个用户只能从本机(也就是 Apache 和 PHP 所在的同一台服务器)连接数据库。如果你的应用和数据库在不同的服务器上,这里就要写成
'192.168.1.100'
(数据库服务器的 IP),或者
'%'
(表示任何 IP,但这是最不安全的,仅用于测试)。
还有一个隐藏的坑:字符集。WordPress 和大多数现代 PHP 应用都要求数据库使用
utf8mb4
字符集,因为它能完整支持 Emoji 表情和所有 Unicode 字符。而 MariaDB 10.1 的默认字符集是
latin1
。如果你在创建数据库时不指定
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
,后面 WordPress 安装时就会报错,说数据库不支持 UTF-8。这个细节,90% 的入门教程都不会提,但却是你安装失败最常见的原因。
3.4 PHP 安装与扩展配置:不只是
php-mysql
,还有
php-curl
和
php-gd
sudo apt install php libapache2-mod-php php-mysql
这条命令,安装了 PHP 解析器、Apache 的 PHP 模块,以及连接 MySQL/MariaDB 的扩展。但一个完整的 Web 应用,远不止数据库连接这么简单。
php-mysql
这个包,实际上安装的是
mysqlnd
(MySQL Native Driver),它是 PHP 7.0 的默认 MySQL 驱动,比老的
mysql
扩展更高效、更安全。但
php-mysql
并不包含
mysqli
扩展,而
mysqli
是 PHP 中最常用、最成熟的面向对象数据库操作接口。所以,你必须额外安装:
sudo apt install php-mysqli
。安装完后,执行
php -m | grep mysqli
,确认它已加载。
除了数据库,还有三个扩展是绝大多数 PHP 应用的“刚需”:
-
php-curl:用于发起 HTTP 请求,抓取网页、调用 API、支付网关对接都离不开它。sudo apt install php-curl。 -
php-gd:用于图像处理,WordPress 的缩略图生成、验证码、图片水印等功能都依赖它。sudo apt install php-gd。 -
php-xml:用于解析 XML 和 HTML,很多 RSS 订阅、SOAP 接口、甚至 WordPress 的主题导入导出都需要它。sudo apt install php-xml。
安装完所有扩展后,别忘了重启 Apache:
sudo systemctl restart apache2
。因为
libapache2-mod-php
是一个 Apache 模块,它的加载是在 Apache 启动时完成的,新增的 PHP 扩展需要 Apache 重新加载才能识别。
最后,检查 PHP 的核心配置。编辑
/etc/php/7.0/apache2/php.ini
。有三个参数是必须检查的:
-
memory_limit = 256M:PHP 脚本可使用的最大内存。WordPress 插件多的时候,128M 经常不够用,256M 是一个比较稳妥的值。 -
upload_max_filesize = 64M:单个上传文件的最大大小。如果你要上传高清图片或视频,就得调大。 -
post_max_size = 64M:POST 请求数据的最大大小,它必须大于或等于upload_max_filesize,否则上传会失败。
改完配置,再次
sudo systemctl restart apache2
。至此,你的 PHP 环境才算真正“活”了过来。
4. 实操过程与核心环节实现:从第一个 PHP 页面到 WordPress 安装的全流程
4.1 创建第一个 PHP 页面:用
<?php phpinfo(); ?>
验证环境
这是所有 Web 开发者的“Hello World”。它不是为了炫技,而是为了给你一个最直观、最全面的“健康报告”。
首先,进入 Apache 的默认 Web 根目录:
cd /var/www/html
。然后,创建一个名为
info.php
的文件:
sudo nano info.php
。在里面输入最简单的代码:
<?php
phpinfo();
?>
保存并退出。现在,打开你的浏览器,访问
http://你的服务器IP/info.php
。如果一切顺利,你会看到一个密密麻麻、色彩斑斓的 PHP 信息页。这张页面,就是你的“LAMP 体检报告”。
你需要重点关注的几个区域:
-
System:确认操作系统是Linux debian 4.9.0-18-amd64,PHP 版本是7.0.33。 -
Server API:确认是Apache 2.0 Handler,这证明libapache2-mod-php模块工作正常。 -
Loaded Modules:滚动查找mysqli、curl、gd,确认它们都列在其中。 -
Configuration File (php.ini) Path:确认路径是/etc/php/7.0/apache2/php.ini,这说明你修改的配置文件是正确的。 -
mysql.default_socket:确认值是/var/run/mysqld/mysqld.sock,这是 PHP 连接 MariaDB 的 Unix socket 路径,后面配置应用时会用到。
如果页面打不开,或者显示的是纯文本(
<?php phpinfo(); ?>
),那说明 Apache 没有把
.php
文件交给 PHP 解析。这时,你应该立刻去检查
a2enmod php7.0
是否执行成功,以及
/etc/apache2/mods-enabled/
目录下是否有
php7.0.load
这个文件。这是最常见、最基础的故障点。
注意:
phpinfo()页面会暴露你服务器的大量敏感信息,包括 PHP 版本、已加载的扩展、服务器路径等。在生产环境中, 绝对不能 让这个页面长期存在。验证完后,立刻执行sudo rm /var/www/html/info.php将其删除。
4.2 部署 WordPress:从下载解压到数据库配置的避坑指南
WordPress 是检验 LAMP 环境的终极试金石。它对 Apache 的重写、PHP 的扩展、MariaDB 的字符集都有严格要求。我们一步步来。
第一步:下载与解压。
不要用
wget
直接下载到
/var/www/html
,因为那样会把整个 WordPress 目录结构(
wp-admin
,
wp-includes
)暴露在根目录下,不安全。最佳实践是:先下载到一个临时目录,再移动并重命名。
# 创建一个临时工作目录
mkdir ~/wordpress-tmp
cd ~/wordpress-tmp
# 下载最新版 WordPress(中文版)
wget https://cn.wordpress.org/latest-zh_CN.tar.gz
# 解压
tar -xzf latest-zh_CN.tar.gz
# 将解压出来的 wordpress 目录里的所有文件,移动到 /var/www/html/
sudo rsync -avP wordpress/ /var/www/html/
# 清理临时文件
cd ~
rm -rf ~/wordpress-tmp
rsync
比
cp
更安全,它能保留文件权限和所有者。
-avP
参数的意思是:归档模式(保留权限)、详细输出、进度条。
第二步:设置文件权限。
这是新手最容易犯错的地方。很多人会
sudo chmod -R 777 /var/www/html
,以为这样就能解决所有权限问题。大错特错!这等于把你的整个网站目录对全世界开放了写权限,任何黑客只要找到一个文件上传漏洞,就能直接往你的服务器里写入木马。
正确的权限设置,遵循“最小权限原则”:
# 设置所有者为 root,组为 www-data
sudo chown -R root:www-data /var/www/html
# 设置目录权限为 755(所有者可读写执行,组和其他人可读执行)
sudo find /var/www/html -type d -exec chmod 755 {} \;
# 设置文件权限为 644(所有者可读写,组和其他人只读)
sudo find /var/www/html -type f -exec chmod 644 {} \;
# 但 wp-config.php 是个例外,它包含数据库密码,必须严格保护
sudo chmod 600 /var/www/html/wp-config.php
这样设置后,Apache(以
www-data
用户身份运行)可以读取所有文件,但无法修改它们;而你(作为
root
)可以随时修改配置。只有
wp-config.php
这个敏感文件,连
www-data
组都无法读取,只有
root
能看。
第三步:创建并配置
wp-config.php
。
WordPress 安装程序会引导你创建这个文件,但手动创建更可控、更安全。先复制模板:
sudo cp /var/www/html/wp-config-sample.php /var/www/html/wp-config.php
然后编辑它:
sudo nano /var/www/html/wp-config.php
。找到以下几行,替换成你之前创建的数据库信息:
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'myblog');
/** MySQL database username */
define('DB_USER', 'myblog_user');
/** MySQL database password */
define('DB_PASSWORD', 'MyB10gP@ss!');
/** MySQL hostname */
define('DB_HOST', 'localhost');
/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8mb4');
/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');
最关键的是
DB_CHARSET
,必须是
utf8mb4
,否则 WordPress 后台会报错。保存退出。
第四步:启动安装向导。
现在,访问
http://你的服务器IP
。你应该能看到 WordPress 的欢迎界面。点击“现在就开始”,然后输入站点标题、管理员用户名、密码、邮箱。点击“安装 WordPress”。如果一切顺利,几秒钟后,你就会看到“成功安装!”的绿色提示。
但请注意,安装完成后,WordPress 会提示你“请删除
wp-config.php
文件”,这显然是个错误提示。
wp-config.php
是 WordPress 的心脏,绝对不能删。这个提示是 WordPress 的一个历史遗留 bug,你可以直接忽略它。
4.3 配置 Apache 虚拟主机:为多个网站准备的标准化流程
一台服务器,往往不止要跑一个网站。比如,你可能有一个公司官网(
example.com
),一个博客(
blog.example.com
),还有一个内部管理系统(
admin.example.com
)。这时候,你就需要 Apache 的虚拟主机(Virtual Host)功能。
Debian 9 的 Apache 配置遵循“站点可用(available)”和“站点启用(enabled)”的分离原则。所有站点的配置文件都放在
/etc/apache2/sites-available/
,而真正生效的站点,则是
/etc/apache2/sites-enabled/
目录下的符号链接。
我们来创建一个名为
myblog
的虚拟主机:
# 创建配置文件
sudo nano /etc/apache2/sites-available/myblog.conf
在里面写入以下内容:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName myblog.local
ServerAlias www.myblog.local
DocumentRoot /var/www/myblog
<Directory /var/www/myblog>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/myblog_error.log
CustomLog ${APACHE_LOG_DIR}/myblog_access.log combined
</VirtualHost>
这个配置的关键点:
-
ServerName和ServerAlias:定义了这个虚拟主机响应哪些域名。你可以在这里写真实的域名,也可以写一个本地测试域名(如myblog.local)。 -
DocumentRoot:指定了这个网站的根目录。我们把它从默认的/var/www/html换成了/var/www/myblog,实现了物理隔离。 -
ErrorLog和CustomLog:为这个站点单独创建了错误日志和访问日志,方便日后排查问题,而不会和默认站点的日志混在一起。
保存后,启用这个站点:
sudo a2ensite myblog.conf
。这个命令会在
/etc/apache2/sites-enabled/
下创建一个指向
myblog.conf
的软链接。最后,重启 Apache:
sudo systemctl restart apache2
。
为了让
myblog.local
这个域名能在你的本地电脑上解析,你还需要修改本地电脑的
hosts
文件(Windows 在
C:\Windows\System32\drivers\etc\hosts
,macOS/Linux 在
/etc/hosts
),添加一行:
192.168.1.100 myblog.local
(把
192.168.1.100
替换成你的服务器 IP)。这样,你在浏览器里访问
http://myblog.local
,流量就会被导向你的服务器,Apache 会根据
ServerName
找到对应的虚拟主机配置,把请求交给
/var/www/myblog
目录处理。
5. 常见问题与排查技巧实录:一份来自真实战场的故障速查手册
5.1 Apache 启动失败:
Address already in use: AH00072: make_sock: could not bind to address [::]:80
这个错误意味着 80 端口已经被占用了。最常见的情况是,你之前已经运行了一个 Nginx 或其他 Web 服务,或者你安装了
apache2
两次,导致两个实例都在抢端口。
排查步骤:
-
查看哪个进程占用了 80 端口:
sudo ss -tulpn | grep ':80'。ss命令比netstat更快、更现代。输出会类似:
这说明是tcp LISTEN 0 128 *:80 *:* users:(("nginx",pid=1234,fd=6))nginx进程(PID 1234)占用了 80 端口。 -
如果是
nginx,你可以选择停止它:sudo systemctl stop nginx,或者卸载它:sudo apt remove nginx。 -
如果是另一个
apache2进程,用sudo kill -9 1234强制杀死它(把1234替换成实际的 PID)。 -
然后,再尝试启动 Apache:
sudo systemctl start apache2。
实操心得:我习惯在安装任何新服务前,先执行
sudo ss -tulpn | grep ':80\|:443',看看端口是否干净。这能避免 90% 的“启动失败”问题。
5.2 PHP 页面显示空白,但 Apache 日志里没有错误
这是一个经典的“静默失败”。PHP 脚本执行过程中发生了致命错误(Fatal Error),但 PHP 的错误报告被关闭了,所以页面什么也不显示,只有一片空白。
解决方法:
-
编辑 PHP 配置文件:
sudo nano /etc/php/7.0/apache2/php.ini。 -
找到
display_errors这一行,把它改为On。 -
找到
error_reporting这一行,把它改为E_ALL。 -
重启 Apache:
sudo systemctl restart apache2。 - 刷新你的 PHP 页面,错误信息就会直接显示在浏览器上了。
常见的错误类型包括:
-
Fatal error: Uncaught Error: Call to undefined function mysqli_connect():说明php-mysqli扩展没安装或没加载。 -
Warning: mysqli_connect(): (HY000/1045): Access denied for user...:说明数据库用户名或密码错了。 -
Parse error: syntax error, unexpected end of file:说明 PHP 代码里少了一个}或;。
一旦问题解决,
务必
把
display_errors
改回
Off
,并把
error_log
设置为一个文件路径(如
/var/log/php_errors.log
),这样错误信息会记录在日志里,而不是暴露给用户。
965

被折叠的 条评论
为什么被折叠?



