Debian 9 LAMP实战搭建:Apache+MariaDB+PHP7.0全链路配置指南

Debian 9 LAMP 实战校准指南:PHP模块化、Apache保守配置与MariaDB socket认证 LAMP 是 Linux、Apache、MySQL(或 MariaDB)、PHP 四大开源组件构成的经典 Web 开发栈,其核心价值在于稳定、可控与高度可定制。在实际部署中,不同发行版对各组件的默认策略存在显著差异——尤其 Debian 以安全基线高、包粒度细、服务行为严谨著称。例如 PHP 不提供元包而强制模块化安装,Apache 默认禁用 .htaccess 覆盖,MariaDB root 用户采用 unix_socket 插件认证而非密码登录。这些设计并非缺陷,而是 Debian ‘不替用户做决定’ 阅读详情

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 。这个脚本会引导你完成四件大事:

  1. 设置 root 密码 :这是必须的,输入一个强密码(至少 12 位,包含大小写字母、数字和符号)。
  2. 删除匿名用户 : Remove anonymous users? [Y/n] Y 。Debian 默认创建了一个空用户名的账户,任何人都可以用 mysql -u "" 登录,必须删掉。
  3. 禁止 root 远程登录 : Disallow root login remotely? [Y/n] Y 。这条非常重要。它会删除 root@'%' 这个用户,只保留 root@'localhost' 。这意味着你只能在服务器本机用 mysql -u root -p 登录,外部网络无法直接访问 root,大大降低了被暴力破解的风险。
  4. 删除 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 两次,导致两个实例都在抢端口。

排查步骤:

  1. 查看哪个进程占用了 80 端口: sudo ss -tulpn | grep ':80' 。 ss 命令比 netstat 更快、更现代。输出会类似:
    tcp LISTEN 0 128 *:80 *:* users:(("nginx",pid=1234,fd=6))
    
    这说明是 nginx 进程(PID 1234)占用了 80 端口。
  2. 如果是 nginx ,你可以选择停止它: sudo systemctl stop nginx ,或者卸载它: sudo apt remove nginx 。
  3. 如果是另一个 apache2 进程,用 sudo kill -9 1234 强制杀死它(把 1234 替换成实际的 PID)。
  4. 然后,再尝试启动 Apache: sudo systemctl start apache2 。

实操心得:我习惯在安装任何新服务前,先执行 sudo ss -tulpn | grep ':80\|:443' ,看看端口是否干净。这能避免 90% 的“启动失败”问题。

5.2 PHP 页面显示空白,但 Apache 日志里没有错误

这是一个经典的“静默失败”。PHP 脚本执行过程中发生了致命错误(Fatal Error),但 PHP 的错误报告被关闭了,所以页面什么也不显示,只有一片空白。

解决方法:

  1. 编辑 PHP 配置文件: sudo nano /etc/php/7.0/apache2/php.ini 。
  2. 找到 display_errors 这一行,把它改为 On 。
  3. 找到 error_reporting 这一行,把它改为 E_ALL 。
  4. 重启 Apache: sudo systemctl restart apache2 。
  5. 刷新你的 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 ),这样错误信息会记录在日志里,而不是暴露给用户。

5

Debian 10 LAMP生产部署指南:稳定、合规、可审计的Web基础设施 LAMP(Linux+Apache+MySQL/MariaDB+PHP)是历经三十年验证的开源Web基础架构范式,其模块解耦、日志可溯、权限可控的特性,使其在等保合规、离线部署、遗留系统维护等强约束场景中不可替代。Apache提供低资源占用与SELinux兼容性,MariaDB具备事务一致性与GTID主从同步能力,PHP 7.3则以配置精简、行为确定著称——这三者在Debian 10官方源中形成高度协同的稳定组合。本文聚焦真实生产约束:版本锁定、用户隔离、存储边界、SSL证书自动化与OPCache深度调优, 阅读详情

相关推荐

Ubuntu 16.04搭建Webmin+Virtualmin全栈服务器管理平台

Linux服务器管理平台是支撑网站托管、域名解析与邮件服务的核心基础设施,其本质是多个系统服务(如Web服务器、DNS、邮件传输代理)在统一内核下的协同运行。理解服务依赖关系、端口绑定原理、权限隔离机制(如AppArmor/systemd约束)及配置一致性校验,是实现稳定运维的关键技术基础。尤其在长期支持但已进入ESM阶段的Ubuntu 16.04上,Webmin与Virtualmin的版本兼容性、BIND的chroot初始化、Postfix的inet_interfaces配置等细节,直接决定DNS响应、S

weixin_33947521的博客 525

UVa 11610 Reverse Prime(树状数组+二分)

有一些7位数,倒转过之后都是小于10^6的素数,叫做倒素数。把这些倒素数按大小排列,分别求出每个倒素数的素因子个数(比如24是2,2,2,3,共4个); 先有两种操作: 1.q i:查询从第0个到第i个倒素数的所有素因子之和; 2.d x:从这些倒素数中删除x,剩下的倒素数按大小重新排列。 首先把每个倒素数除以10,然后因子个数都先加上2,消除末尾0(题目也是有点无聊); del

Just One Last Coding~♬ 967

【STM32实战】利用STM32CubeMX配置PWM互补输出驱动电机

本文详细介绍了如何利用STM32CubeMX配置STM32高级定时器的PWM互补输出功能,以驱动电机等需要半桥/全桥电路的应用。通过图形化界面设置定时器参数、使能互补通道并配置关键的死区时间,结合代码示例演示了如何启动PWM输出和动态调整占空比,确保输出安全、精确的互补信号,避免MOS管直通风险,提升驱动可靠性。

weixin_29161785的博客 535

poj 2886 - 树状数组+二分

题解思路: 这里我们可以将逆时针一同转化为顺时针,那么就是如果逆时针跳过m个人那么顺时针应该是k(圈里现有人数)-m+1,为什么要加1呢,因为我们出发点是上一次被淘汰的那个人,他已经不属于这个圈子了,所以转化成顺时针要多加1,那么我们假设刚刚被淘汰的人在po位置,那么无非是两种情况:下个被淘汰的在po-n中或1-po中,如果po-n中的人数不够的话那肯定就在1-po中,这个可以用树状数组维护,另

过路人丶的博客 471

Debian 12 安装nodejs(包括node、npm、npx、yarn、pnpm、cnpm、bun)

【代码】Debian 12 安装nodejs。

mirana的专栏 8006

不用编码器也能玩转BLDC?手把手教你反电动势定位实战

本文详细介绍了无刷直流电机(BLDC)的无传感器控制方案——反电动势定位法,通过STM32实战演示如何实现基本控制。文章涵盖核心原理、硬件准备、信号采集技巧及代码实现,特别适合静音风扇、小型机器人等对成本敏感的应用场景,帮助开发者降低硬件成本并提升系统可靠性。

lg888的博客 897

POJ 2886 Who Gets the Most Candies(线段树+约瑟夫环)

题目链接:POJ 2886 Who Gets the Most Candies 【】

RaynX的专栏 726

基于Simulink环境,提供一个关于如何对DC-DC变换器进行效率分析的仿真建模

效率定义:变换器效率通常定义为输出功率与输入功率之比,即 η=PoutPinη=Pin​Pout​​。重要性:高效率意味着更少的能量损失和更好的热管理,对于便携式设备、电动汽车等应用至关重要。挑战开关损耗:高频操作带来的开关器件损耗。导通损耗:电流流过电阻性元件(如MOSFET导通电阻)造成的能量损失。控制策略:优化控制算法以减少损耗。首先明确要模拟的任务内容。设计一个能够支持特定输入输出电压比的DC-DC变换器。根据工作频率和谐振元件值确定合适的电路参数。

xiaoheshang_123的博客 155

UVA 11610 Reverse Prime(数论+树状数组+二分)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 给出一个reverse_prime,自身是一个7位数,反转后是一个 首先求出所有的这种数 两种操作 q k :表示删除数字K http://uva.onlinejudge.org/index.php?option=com_onlinej

窝不是爱酱,喵~~~~ 2079

基于 FPGA Vivado 示波器设计(附源工程)

今天给大侠带来基于 FPGA Vivado 示波器设计,开发板实现使用的是Digilent basys 3,如有想要入手basys3开发板的,可以联系牛总:18511371833。话不多说,上货。 本篇掌握基于添加文件和IP的Vivado工程设计流程,掌握基于Tcl的Vivado工程设计流程,学习示波器的基本组成结构。获取本篇相关源工程代码,可在公众号内回复“示波器设计源工程”。 原理介绍 数字存储示波器能够将模拟信号进行采样、存储以及显示。本系统在DIGILENT ...

7386

TC3XX - MCAL知识点(九):PWM EB-tresos配置说明及代码浅析

脉冲宽度调制(PWM)驱动器负责提供与AUTOSAR指定的PWM信号生成相关的标准服务。PWM通道的底层定时器驱动是GTM (TOM或ATOM片)或CCU6 (T12或T13片)定时器通道。软硬件匹配关系如下:PWM直接引用的是GTM与CCU6模块,然后GTM与CCU6再关联到Port的,根据软硬件匹配关系,也能调用中断来使用,本例子没使用中断。CCU6是一个高分辨率的16位捕获和比较单元,具有特定的应用模式,主要用于交流驱动控制。特殊的工作模式支持控制无刷直流电机使用霍尔传感器或反电动势检测。

梦想技术家 2886

POJ - 2886 Who Gets the Most Candies? 树状数组 + 二分 + 反素数

传送门:POJ2886 题意:n个小朋友在玩一种类似于约瑟夫环的游戏,定义F(p)表示p的约数个数,第p个出队的将会得到F(P)个糖,问哪个小朋友得到的糖最多。 思路:首先明确我们一开始就能知道第几个出队的小朋友能得到最多的糖果,并且这还是一类特殊的数,叫反素数, 定义: 对于任何正整数,其约数个数记为,例如,如果某个正整数满足:对任意的正整             数,都有,那

WA是一笔财富 323

MySQL——cost成本计算之MySQL如何选择使用索引(trace)

文章目录前言trace工具分析执行计划 前言 在之前博客中,根据测试案例,发现同样的sql语句,因为传入的条件值的不同,导致MySQL有时候选择使用索引,有时候又不适用索引。 如下所示sql的执行计划: EXPLAIN SELECT * FROM employees WHERE name > 'aaa'; EXPLAIN SELECT * FROM employees WHERE name > 'zzzz'; 在MySQL中,为什么会出现上述这种玄乎的现象呢? 本篇博客重点说明原因。 在说

专注写bug 679

Debian 8 LAMP实战:理解Web服务底层契约与排错逻辑

LAMP(Linux、Apache、MySQL、PHP)是Web服务最基础的运行范式,其核心在于组件间清晰的职责边界与可验证的协作链路。Apache作为请求调度中枢,PHP以模块化方式嵌入执行,MySQL提供数据持久化契约,三者通过明确定义的端口、配置路径和权限模型协同工作。这种‘无抽象层遮蔽’的设计,使故障域可精准定位——从curl探测HTTP响应,到日志逐层下钻,再到phpinfo()验证扩展加载,形成完整的可观测性闭环。尤其在容器化与云原生环境中,Docker镜像中的/etc/apache2、/etc

weixin_30421809的博客 423

TGRS 2026 即插即用 | 注意力篇 | SCFM:双向交叉显著性引导注意力,高层语义与低层细节的双向互补!

本文介绍了MPCNet中的语义引导交叉注意力融合模块(SCFM),该模块通过双向交叉显著性引导机制实现跨尺度特征融合。SCFM创新性地结合了高层语义和低层细节的互补信息,通过轻量局部空间注意力预增强和坐标注意力全局融合引导,显著提升了红外小目标检测的精度。实验表明,SCFM在多个数据集上达到SOTA性能,同时保持轻量高效的计算特性,支持端侧设备部署。 SCFM的核心贡献包括: 双向交叉显著性引导机制,实现语义与细节的互补融合 轻量局部空间注意力预增强模块,计算量仅为传统方法的1/10 坐标注意力全局融合引导

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 145

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

CentOS 8 LAMP企业级部署:标准化安装与安全调优指南

LAMP(Linux+Apache+MariaDB+PHP)作为经典Web技术栈,其核心价值在于高度可控、透明可审计的运行机制,尤其适用于对稳定性、合规性与故障定位效率有严苛要求的生产环境。本文围绕CentOS 8这一仍广泛存在于政务、教育及国产化过渡场景的操作系统,深入解析原生RPM包管理下的组件协同原理,重点涵盖Apache模块精简与虚拟主机隔离、MariaDB utf8mb4字符集与权限模型设计、PHP-FPM进程池调优及SELinux上下文策略配置等关键技术点。通过标准化部署流程与可复现的配置实践,

dengwan3818的博客 501

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

2026版Linux运维实战教程:零基础入门到就业全链路指南

这次我们来看一套面向2026年的Linux运维教程。这套教程主打“保姆级零基础入门到实战”,目标很明确:让一个完全没有Linux基础的人,通过系统学习,能够达到就业水平,并且附带了配套的课件。对于想转行运维、开发需要熟悉Linux环境,或者单纯想系统掌握服务器操作的同学来说,这是一个非常直接的学习路径。 这套教程的核心价值在于它的“全链路”设计。它不是零散地讲几个命令,而是从最基础的虚拟机安装、Linux系统操作,一直覆盖到Shell脚本编写、常用服务(如Nginx、MySQL)部署、乃至云平台和大数据集群

weixin_33795806的博客 422

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Ubuntu 20.04 LEMP栈搭建:Nginx+PHP-FPM通信与MySQL 8.0认证详解

LEMP栈(Linux+Nginx+MySQL+PHP)是Web服务的基础运行环境,其核心在于组件间协议级协同:Nginx作为事件驱动反向代理,需通过Unix socket或TCP与PHP-FPM完成进程间通信;MySQL 8.0默认启用caching_sha2_password认证插件,而PHP 7.4+的mysqlnd驱动需显式适配;Ubuntu 20.04作为LTS基线,提供内核5.4、systemd 245及稳定libc,成为调试socket权限、服务生命周期与认证握手的理想沙箱。本文聚焦Nginx

weixin_30235225的博客 355

poj2886 (约瑟夫环,树状数组)

n个人围成圈,每个人手上有一个数字,最开始k跳出圈,如果k手上的数num是正数,则向左num个人出圈,负数就向右,直到所有人都出圈,得分最高的是第(1-n中因子数最多的数)次跳出的人 首先处理1-n中因子最多的数,有个名词叫反素数,不管他这里直接打表 #include &lt;cstdio&gt; #include &lt;cstring&gt; #include &lt;cmath&gt;...

bpdwn2017的博客 726

POJ 2886 单点更新

题意:n个小孩围一圈,他们手上卡片的数字代表下一个要出去的孩子,第K个孩子出去得到糖的数量是k的约数,输出得到糖最多的那个孩子的姓名和糖数。 首先要求反素数,也就是约数最多的,打表就行。然后线段树节点存放这个区间有多少个孩子还没走。然后模拟这个过程求出第P个孩子。 #include #include #include #include using namespace std; #define

韩小侠的专栏 已迁移至lssea.com 776

poj-2886

// 26584K 1407MS G++ #include #include #include using namespace std; #define MAX 500050 struct ChildeTreeNode { int childId; int childNum; int left; int right; }; typedef str

fyfcauc的专栏 768

poj2886线段树+反素数

题意: N个小朋友围一圈。 指定一个人为起始点之后,此人出圈。 按照这个人手中卡片的数字找到下一个人,下一个人出圈。 。。。 知道最后一个人出圈。 思路: 一:当期指定的人在第K个位置,他出圈后,找到下一个人在剩下的人中的位置next_K。 if(A >= 0) next_k = (k-1+A-1)%n + 1; else next_k = ((k-1

*Small eyes-Big world 766

poj2886

这道题让我对线段树的使用有了一个新的认识,

lalala 553

POJ 2886 【线段树&&反素数&&约瑟夫循环】

POJ 2886 【线段树&&反素数&&约瑟夫循环】 题目链接 题意:给你n,k<=5e5,n是人数下面还会给你n个人的信息,k是初始位置,每次都会根据当前的位置大于0决定顺时针走a[i],否则就走逆时针a[i],循环的次数就是小于n的因子最大的那个。题意是这样 思路: 1.首先要确定循环次数,暴力找5e5以内因子数最大的那个n*sqrt(n),加上多组肯定超...

qq_43653111的博客 218

poj2886 线段树

线段树题目,思路不难,关键是F(p),很难想清楚是神马,表示看了别人的题意解析才知道神马意思。反素数这玩意果断决定打表了,以后比赛随时带着这玩意得了。另外注意的是,反素数的因子个数不是连续变化的,有可能依次增加好几个因子,这点特别注意下。 其他就是依次剔除人了,知道人物当前位置和当前人物长度可轻易推出下次出列的人物位置,依次将人物出列直到答案的值。 代码: #include #includ

creater_X 905
上一篇: OpenClaw:私有化AI助手的CLI原生操作系统
下一篇: Ubuntu 18.04部署Minecraft服务器的稳定性实践指南
dingdi3021
博客等级 码龄11年 1粉丝 230原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值