当前位置: 首页 > news >正文

Ubuntu 20.04 手动搭建 LAMP 全流程:Apache+MySQL+PHP 协同部署与排错

1. 项目概述:为什么在 Ubuntu 20.04 上亲手搭一套 LAMP 不是“复古操作”,而是硬核基本功

LAMP 这个词,从 2000 年代初火起来,到现在快二十年了,很多人第一反应是“老古董”“过时方案”。但现实恰恰相反——它不是被时代淘汰的技术栈,而是被无数现代云服务、容器平台和 SaaS 工具悄悄封装在底层的“隐形骨架”。你用 WordPress 搭个人博客?背后是 LAMP;你部署一个内部 PHP 管理系统?八成跑在 LAMP 上;甚至某些国产信创环境里的 Web 中间件,其 Apache + PHP 模块加载逻辑、MySQL 连接池配置方式,都脱胎于这套经典组合。我带过十几期运维和全栈新人培训,发现一个关键现象:凡是跳过手动搭建 LAMP 直接上 Docker 或一键脚本的学员,一旦遇到 Apache 配置文件里DirectoryIndex顺序错乱导致首页 403、PHP 扩展没加载成功却报“函数未定义”、MySQL 8.0 默认认证插件caching_sha2_password和 PHP 的mysqli扩展握手失败这类问题,排查起来就特别吃力——因为缺了对各组件之间“怎么连上”“谁管谁”“数据怎么流”的肌肉记忆。

Ubuntu 20.04 是一个极具代表性的 LTS(长期支持)版本,它自带的软件源稳定、社区文档丰富、硬件兼容性成熟,更重要的是,它默认使用systemd管理服务、apt作为包管理器、ufw作为防火墙,这些都不是抽象概念,而是你每天要敲命令、看日志、改配置的真实界面。标题里那个“[Краткое руководство]”(俄语“简明指南”)其实是个善意的误导——真想把这套环境搭得稳、调得顺、查得清,光靠“简明”远远不够。你需要知道:为什么apache2包在 Ubuntu 里默认不启用rewrite模块?为什么mysql-server安装后 root 用户默认没有密码,但你却无法用空密码登录?为什么php包安装后,Apache 里phpinfo()页面能显示,但连接 MySQL 却提示“Access denied for user 'root'@'localhost'”?这些问题的答案,不在任何一键脚本的注释里,而在你亲手执行每一条apt installa2enmodmysql_secure_installation时,终端返回的那几行提示信息中。这篇内容,就是带你回到命令行最原始的交互现场,把 LAMP 四个字母拆开揉碎,看清每个螺丝钉是怎么拧紧的,每个接口是怎么对齐的。它适合三类人:刚接触 Linux 的开发者,需要建立服务间协作的第一手认知;正在排查线上 PHP 应用慢、500 错误频发的运维同学,需要回溯基础链路;还有那些评估国产 Linux 发行版兼容性的技术决策者——因为 Ubuntu 20.04 的这套流程,就是绝大多数国产发行版 LAMP 支持能力的“基准测试”。

2. 整体设计与思路拆解:拒绝“一键安装”,选择分步可控的四段式构建法

很多教程一上来就甩出一行命令:sudo apt update && sudo apt install lamp-server^。这个lamp-server^是 Ubuntu 提供的“任务包”(task package),它本质是一个元包(metapackage),作用是自动拉取apache2mysql-serverphp及其常用扩展的依赖列表。听起来很省事,但我在生产环境踩过太多坑:某次升级后,lamp-server^自动把 PHP 从 7.4 升到 8.0,结果一个依赖mysql_*函数的老系统直接崩掉;另一次,mysql-server更新触发了mysqld服务重启,而apache2正好在处理长连接,导致部分请求超时,监控告警响了一整晚。所以,我的设计原则非常明确:分步、显式、可验证。整个搭建过程被严格划分为四个独立阶段,每个阶段只做一件事,做完立刻验证,确认无误再进入下一阶段。这不仅是操作习惯,更是故障隔离的基本思维。

2.1 阶段一:Apache —— 先立起“门面”,确保 HTTP 服务本身可靠

Apache 在这里不是“Web 服务器”这么简单,它是整个 LAMP 请求流的入口守门员。它的核心职责有三:接收客户端 HTTP 请求、根据 URL 路径决定由谁处理(静态文件?PHP 脚本?代理给后端?)、把处理结果打包成 HTTP 响应发回去。因此,第一阶段的目标不是让它“能跑 PHP”,而是让它“能稳定响应任何请求”。我们不装lamp-server^,而是单独执行sudo apt install apache2。这个命令会安装 Apache 二进制文件、默认网站配置/etc/apache2/sites-available/000-default.conf、主配置/etc/apache2/apache2.conf,以及最重要的——systemd服务单元apache2.service。安装完成后,立刻执行sudo systemctl status apache2,这不是走形式,而是要看三个关键点:服务状态是否为active (running);主进程 PID 是否存在;最近的日志行里有没有AH00558: apache2: Could not reliably determine the server's fully qualified domain name这类警告(它不影响运行,但暴露了主机名配置问题,后面要修)。然后,用curl -I http://localhost检查 HTTP 头,确认返回HTTP/1.1 200 OK,这才是真正的“门面立住了”。这一步的意义在于,把网络层、进程管理、基础配置这三个维度的问题全部前置暴露出来。如果连curl都不通,那后面装 PHP、MySQL 全是空中楼阁。

2.2 阶段二:MySQL —— 构建“数据心脏”,强调安全初始化与权限模型

MySQL 是 LAMP 的数据心脏,但它的“心跳”必须是受控的。Ubuntu 20.04 的mysql-server包默认采用auth_socket插件进行本地 root 认证,这意味着你用sudo mysql -u root可以直接登录,但用mysql -u root -p却会失败——因为-p参数要求输入密码,而auth_socket根本不检查密码,它检查的是当前 Linux 用户是否为root。这是一个典型的设计陷阱:它提升了本地管理便利性,却模糊了数据库用户和系统用户的边界。所以,第二阶段的核心动作不是“启动服务”,而是执行sudo mysql_secure_installation。这个脚本会引导你完成五件事:设置 root 密码(强制切换为caching_sha2_password插件)、删除匿名用户、禁止 root 远程登录、删除 test 数据库、重载权限表。其中,“设置 root 密码”这一步,我强烈建议你不要跳过,哪怕只是设一个临时密码。因为后续 PHP 连接 MySQL 时,mysqli_connect()函数的参数里hostusernamepassword必须一一对应,如果 root 没密码,PHP 代码里就得传空字符串,而空字符串在某些 PHP 版本或配置下会被解释为NULL,导致连接失败。更关键的是,mysql_secure_installation执行后,它会修改/etc/mysql/debian.cnf文件,这个文件里存着debian-sys-maint用户的凭据,它是 Ubuntu 系统维护 MySQL 服务(如自动备份、日志轮转)所必需的。如果你跳过这一步,后期systemd服务管理可能会出问题。验证这一步是否成功,不是看脚本能跑完,而是用sudo mysql -u root -p登录,输入你刚设的密码,能进去再exit出来,才算真正过关。

2.3 阶段三:PHP —— 搭建“业务引擎”,聚焦模块加载与配置协同

PHP 在 LAMP 里是业务逻辑的执行引擎,但它本身不直接监听端口,也不处理 HTTP 协议。它的角色,是被 Apache “调用”的一个动态库。所以,第三阶段的关键,不是装 PHP 解释器,而是让 Apache “认识”并“信任”它。Ubuntu 20.04 的php包(实际是php7.4)安装后,会在/etc/php/7.4/apache2/下生成一套默认配置,包括php.ini(主配置)、mods-available/(可用模块目录)。但此时,Apache 并不知道要加载 PHP 模块。这就引出了a2enmod命令——它不是简单的“启用模块”,而是执行一个符号链接操作:把/etc/apache2/mods-available/php7.4.load链接到/etc/apache2/mods-enabled/php7.4.load。这个.load文件里只有一行:LoadModule php7_module /usr/lib/apache2/modules/libphp7.4.so,它告诉 Apache:“请把/usr/lib/apache2/modules/libphp7.4.so这个动态库加载进内存”。紧接着,a2enconf php7.4命令会把/etc/apache2/conf-available/php7.4.conf链接到/etc/apache2/conf-enabled/php7.4.conf,这个配置文件定义了关键行为:AddType application/x-httpd-php .php(告诉 Apache,所有.php后缀的文件,都交给 PHP 模块处理)、DirectoryIndex index.php index.html(当访问目录时,优先找index.php)。这两步做完,必须执行sudo systemctl restart apache2,因为模块加载是进程级的,不重启 Apache,新模块永远不会生效。验证方法很简单:在/var/www/html/下创建info.php,内容为<?php phpinfo(); ?>,然后用浏览器访问http://localhost/info.php。如果页面能打开,并且顶部显示PHP Version 7.4.x,且Loaded Modules里能看到core,mod_php7,mpm_event等,说明 PHP 引擎已成功嵌入 Apache。

2.4 阶段四:协同验证 —— 用真实 PHP+MySQL 代码打通全链路

前三步都是单点验证,第四步才是真正的“集成测试”。它要模拟一个最简业务场景:PHP 脚本连接 MySQL,查询一张表,把结果输出到网页。这一步的代码不能写在info.php里,必须新建一个独立文件,比如/var/www/html/test_db.php。代码内容看似简单,但每一行都直指核心:

<?php $host = 'localhost'; $username = 'root'; $password = 'your_root_password_here'; // 这里必须填你在 mysql_secure_installation 里设的密码 $database = 'test_db'; // 创建连接 $conn = mysqli_connect($host, $username, $password, $database); // 检查连接 if (!$conn) { die("Connection failed: " . mysqli_connect_error()); } // 创建测试表(如果不存在) $sql_create = "CREATE TABLE IF NOT EXISTS test_table ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )"; if (!mysqli_query($conn, $sql_create)) { die("Create table failed: " . mysqli_error($conn)); } // 插入一条测试数据 $sql_insert = "INSERT INTO test_table (name) VALUES ('LAMP Test')"; mysqli_query($conn, $sql_insert); // 查询并输出 $sql_select = "SELECT * FROM test_table ORDER BY id DESC LIMIT 1"; $result = mysqli_query($conn, $sql_select); if ($result && mysqli_num_rows($result) > 0) { $row = mysqli_fetch_assoc($result); echo "Success! Last inserted record: ID=" . $row['id'] . ", Name=" . $row['name']; } else { echo "No data found."; } mysqli_close($conn); ?>

这段代码的价值,在于它同时触发了三个关键路径:PHP 的mysqli扩展是否已加载(mysqli_connect函数是否存在);PHP 是否能通过localhost这个 host 连接到 MySQL(这涉及 MySQL 的bind-address配置,默认是127.0.0.1,但localhost在 Unix Socket 下有特殊解析逻辑);MySQL 的 root 用户是否真的拥有对test_db数据库的操作权限(CREATE,INSERT,SELECT)。如果访问http://localhost/test_db.php页面显示 “Success!...”,恭喜,你的 LAMP 链路已经完全打通。如果报错,错误信息就是最精准的诊断线索——是Call to undefined function mysqli_connect()(PHP 扩展没装),还是Connection refused(MySQL 服务没启或端口被占),还是Access denied(用户名密码错或权限不足),每一种都指向一个明确的、可快速修复的环节。这种“用最小闭环验证最大集成”的思路,是我过去十年处理上百个 Web 环境部署问题后,总结出的最高效方法。

3. 核心细节解析与实操要点:那些官方文档不会写的“魔鬼在细节”

LAMP 的每个组件,表面看是标准化的开源软件,但深入到 Ubuntu 20.04 这个具体发行版的实现细节里,处处是“魔鬼”。这些细节不写在手册里,却决定了你的环境是“能用”还是“好用”,是“三天一崩”还是“三年不 reboot”。下面这些,全是我在客户现场、自己实验室反复验证过的硬核要点,它们不是锦上添花,而是避坑刚需。

3.1 Apache 的DocumentRootDirectory权限:一个被严重低估的安全基线

/var/www/html/是 Apache 的默认网站根目录,这是常识。但很多人不知道,/var/www/这个父目录的权限,直接决定了 Apache 能否正常读取子目录下的文件。Ubuntu 20.04 安装后,/var/www/的默认权限是drwxr-xr-x(755),所有者是root:root。这看起来没问题,但当你用普通用户(比如ubuntu)去cd /var/www/html/touch test.txt时,会发现文件所有者是ubuntu:ubuntu,而 Apache 的工作进程(www-data用户)可能没有权限读取它。这就是为什么你有时明明文件放对了位置,浏览器却返回403 Forbidden。根本原因在于,Linux 的目录访问权限遵循“路径上每一级目录都必须有x(执行)权限才能进入”的规则。/var/www/www-data组是r-x,没问题;但/var/www/html/如果被你chown成了ubuntu:ubuntu,而www-data不在ubuntu组里,那www-data就失去了对html目录的x权限,自然进不去。解决方案有两个,我推荐后者:永远不要chown -R ubuntu:ubuntu /var/www/html/。正确的做法是,把你的开发用户(比如ubuntu)加入www-data组:sudo usermod -a -G www-data ubuntu,然后把/var/www/html/的组所有权设为www-datasudo chgrp -R www-data /var/www/html/,最后设置setgid位:sudo chmod -R g+s /var/www/html/。这样,以后在这个目录下创建的任何文件,其组都会自动继承为www-data,Apache 进程就能无缝读取。这个操作,比每次chmod 755chown www-data:www-data更优雅、更可持续。

3.2 MySQL 的bind-addressskip-networking:本地连接的“双面镜”

bind-address是 MySQL 配置文件/etc/mysql/mysql.conf.d/mysqld.cnf里的一个关键参数,它决定了 MySQL 服务器监听哪个网络接口。Ubuntu 20.04 的默认值是127.0.0.1,意思是“只接受来自本机 localhost 的 TCP 连接”。这很安全,但也是很多 PHP 连接失败的根源。因为 PHP 的mysqli_connect('localhost', ...)这个localhost,在 MySQL 客户端库里有特殊含义:它会优先尝试 Unix Socket 连接(/var/run/mysqld/mysqld.sock),而不是 TCP。而 Unix Socket 连接,绕过了bind-address的限制,只要 socket 文件路径正确、权限正确,就能连上。所以,当你看到mysqli_connect('localhost', ...)成功,但mysqli_connect('127.0.0.1', ...)失败时,不要慌,这恰恰证明bind-address生效了,而且你的 Unix Socket 是通的。但如果你的应用明确要求用 IP 地址连接(比如某些容器化部署),或者你想从另一台机器远程管理 MySQL,那就必须修改bind-address。可以改成0.0.0.0(监听所有接口),但这极度危险,必须配合ufw防火墙:sudo ufw allow from 192.168.1.100 to any port 3306(只允许特定 IP 访问)。另一个常被忽略的参数是skip-networking,如果它被设为ON,MySQL 将完全禁用 TCP/IP 协议栈,只保留 Unix Socket。检查它是否存在:sudo grep skip-networking /etc/mysql/mysql.conf.d/mysqld.cnf。如果存在且值为1,请把它注释掉或删掉,否则任何基于 IP 的连接都会失败。记住,bind-addressskip-networking是一对“开关”,它们共同决定了 MySQL 的网络可见性,理解它们,就掌握了 MySQL 连接问题的半壁江山。

3.3 PHP 的extension_dirdate.timezone:两个影响全局的“静默杀手”

PHP 的php.ini文件里,extension_dir指定了 PHP 扩展(.so文件)的存放路径。Ubuntu 20.04 的默认值通常是/usr/lib/php/20190902/(数字是 PHP API 版本号)。这个路径必须绝对准确,否则extension=mysqli.so这样的配置就会失效,导致mysqli_connect()函数不存在。怎么确认?执行php -i | grep extension_dir,它会输出当前生效的路径。如果和php.ini里写的不一样,说明你编辑的是错误的php.ini文件(PHP 有多个配置文件:CLI 用/etc/php/7.4/cli/php.ini,Apache 用/etc/php/7.4/apache2/php.ini)。另一个“静默杀手”是date.timezone。PHP 7.4 默认不设置时区,这会导致date()strtotime()等函数返回false,并在错误日志里埋下Warning: date(): It is not safe to rely on the system's timezone settings。这个问题不会让你的脚本立即崩溃,但会让所有时间相关的逻辑出错,而且错误日志里不会直接告诉你哪行代码错了,只会告诉你“时区没设”。解决方案是,在/etc/php/7.4/apache2/php.ini里找到;date.timezone =这一行,去掉分号,填上你的时区,比如date.timezone = Asia/Shanghai。填完后,必须重启 Apache:sudo systemctl restart apache2,因为php.ini的加载是在 Apache 启动时完成的。这两个配置,一个关乎功能可用性(扩展路径),一个关乎业务逻辑正确性(时区),它们不出错时你感觉不到,一出错就是大面积故障,务必在环境初始化时就搞定。

3.4ufw防火墙与apache2的端口策略:安全与可用的精确平衡

Ubuntu 20.04 默认安装ufw(Uncomplicated Firewall),但它默认是inactive状态。很多教程会教你sudo ufw enable,然后sudo ufw allow OpenSSH,这没错,但对 Web 服务来说,仅仅allow 'Apache Full'是不够的。'Apache Full'是一个预设规则,它等价于allow 80,443/tcp。但如果你在开发中用了自定义端口,比如8080,或者你启用了 HTTP/2(需要 ALPN 协商),或者你配置了 WebSocket(ws://协议),那么ufw就成了一个隐形的“拦截器”。我见过最典型的案例:一个 PHP WebSocket 服务,在本地curl测试一切正常,但前端浏览器连接时一直pending,最后发现是ufw8080端口挡住了。所以,我的实操心得是:ufw启用前,先用sudo ss -tuln | grep ':80\|:443'确认 Apache 真正监听的端口ss命令比netstat更快更准,-tuln参数表示只看 TCP (-t)、UDP (-u)、监听 (-l)、数字端口 (-n)。如果看到*:80127.0.0.1:80,说明 Apache 在监听。然后,针对每个你确认需要开放的端口,单独添加规则:sudo ufw allow 8080/tcp。对于生产环境,我甚至会禁用ufw,改用云服务商的安全组(Security Group)或硬件防火墙,因为ufw是主机级的,而安全组是网络级的,粒度更细、管理更集中。但在本地开发或小型 VPS 上,ufw是最轻量、最可靠的守护者,用好它,就是用好安全与可用之间的那条精确平衡线。

4. 实操过程与核心环节实现:从零开始,逐行命令还原真实部署现场

现在,让我们把前面所有的原理、设计和细节,全部落地为一份可直接复制粘贴、逐行执行的实操清单。这不是一个理想化的“完美流程”,而是我在我自己的 Ubuntu 20.04 虚拟机上,从sudo apt update开始,完整复现一遍后,记录下来的每一个命令、每一次输出、每一个需要你手动确认的节点。我会在关键步骤后,附上“为什么这么做”和“如果出错怎么办”的即时分析,让你像站在我身后一样,看清整个操作的脉络。

4.1 环境准备与系统更新:别跳过这五分钟,它能省你两小时

首先,确保你有一个干净的 Ubuntu 20.04 系统。无论是物理机、虚拟机(VMware/VirtualBox)还是云服务器(AWS EC2、阿里云 ECS),只要内核版本是5.4.x,并且apt源配置正确,就可以开始。登录后,第一件事不是装软件,而是更新系统:

sudo apt update && sudo apt upgrade -y

提示:apt update是刷新本地软件包索引,apt upgrade是升级已安装的软件包。-y参数是自动确认所有Y/n提示。这一步耗时取决于你的网络和服务器性能,通常 2-5 分钟。为什么要先做这个?因为 Ubuntu 的mysql-server包在 20.04.6 版本之后,修复了一个关于caching_sha2_password插件的兼容性 bug。如果你跳过更新,直接apt install mysql-server,可能会装到一个有已知问题的老版本,导致后续 PHP 连接失败。执行完后,检查一下内核和系统版本:uname -rlsb_release -a,确认是5.4.0-xx-genericUbuntu 20.04.6 LTS,这样我们才站在同一个起跑线上。

接下来,安装一些基础工具,它们不是 LAMP 的一部分,但会让你的调试过程丝滑无比:

sudo apt install -y curl wget vim net-tools dnsutils
  • curlwget:用于下载文件、测试 HTTP 请求。
  • vim:强大的终端文本编辑器,比nano功能更全,是运维和开发的标配。
  • net-tools:提供ifconfignetstat等经典网络诊断命令(虽然ip命令更现代,但很多老文档和脚本还在用netstat)。
  • dnsutils:提供dignslookup,用于排查 DNS 解析问题。

安装完成后,用which vimwhich curl确认它们已就位。这一步看似琐碎,但它建立了你和系统的“信任连接”——你知道哪些命令可用,哪些工具在手,心里才有底。

4.2 Apache 安装与基础验证:从systemctl statuscurl -I

现在,正式进入 LAMP 的第一块基石:

sudo apt install -y apache2

安装过程会输出大量日志,关注最后一行,通常是Setting up apache2 (2.4.41-4ubuntu3.20)这样的信息,表示安装成功。紧接着,立刻验证:

sudo systemctl status apache2

你应该看到类似这样的输出(关键字段已加粗):

● apache2.service - The Apache HTTP Server Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled) Active: **active (running)** since Mon 2023-10-02 10:15:22 CST; 1min 23s ago Docs: https://httpd.apache.org/docs/2.4/ Process: 1234 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS) Main PID: **1245** (apache2) Tasks: 55 (limit: 9452) Memory: 8.2M CGroup: /system.slice/apache2.service ├─1245 /usr/sbin/apache2 -k start ├─1247 /usr/sbin/apache2 -k start └─1248 /usr/sbin/apache2 -k start

重点看Active:后面的active (running)Main PID:后面的数字。如果状态是inactive (dead),说明服务没起来,最常见的原因是 80 端口被占用。用sudo ss -tuln | grep ':80'查看谁在监听 80 端口。如果是nginx或其他服务,要么停掉它,要么修改 Apache 的监听端口(在/etc/apache2/ports.conf里改Listen 80Listen 8080)。

验证服务状态后,用curl测试 HTTP 层:

curl -I http://localhost

预期输出是:

HTTP/1.1 200 OK Date: Mon, 02 Oct 2023 02:17:33 GMT Server: Apache/2.4.41 (Ubuntu) Last-Modified: Mon, 02 Oct 2023 02:15:22 GMT ETag: "2c3-5e8a1f8a8a1f8" Accept-Ranges: bytes Content-Length: 707 Vary: Accept-Encoding Content-Type: text/html

HTTP/1.1 200 OK是黄金标准。如果返回curl: (7) Failed to connect to localhost port 80: Connection refused,说明 Apache 没监听 80 端口,回到上一步检查systemctl statusss命令。

最后,确认 Apache 的默认网站根目录/var/www/html/是否可写。用你的普通用户(比如ubuntu)执行:

echo "Hello from $(whoami)" | sudo tee /var/www/html/test.html

然后curl http://localhost/test.html,应该输出Hello from ubuntu。这证明文件能写入,且 Apache 能读取。这一步完成了 Apache 的“门面”建设,它现在是一个稳定、可访问、可写入的 HTTP 服务。

4.3 MySQL 安装与安全加固:mysql_secure_installation的每一步详解

Apache 立住了,下一步是数据心脏:

sudo apt install -y mysql-server

安装完成后,mysql服务会自动启动。再次用systemctl确认:

sudo systemctl status mysql

状态应该是active (running)。现在,最关键的一步来了:sudo mysql_secure_installation。这个脚本会交互式地问你五个问题,我来逐个解释:

  1. Securing the MySQL server deployment.
    这是开场白,按回车继续。

  2. The existing password for the user account root has expired. Please set a new password.
    这里,Ubuntu 20.04 的mysql-server包会检测到 root 密码已过期(即使你从来没设过),强制你设置一个新密码。输入一个强密码,比如MyP@ssw0rd2023!,然后按回车。这个密码将是你后续所有 PHP 连接、命令行登录的凭证。

  3. By default, a MySQL installation has an anonymous user, allowing anyone to log into MySQL without having to have a user account created for them... Remove anonymous users? (Press y|Y for Yes, any other key for No) : Y
    输入Y。匿名用户是巨大的安全隐患,必须删除。

  4. Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? (Press y|Y for Yes, any other key for No) : Y
    输入Y。禁止 root 远程登录,这是最基本的安全策略。

  5. By default, MySQL comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? (Press y|Y for Yes, any other key for No) : Y
    输入Y。删除test数据库,避免信息泄露。

  6. Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? (Press y|Y for Yes, any other key for No) : Y
    输入Y。重载权限表,让上面的所有更改立即生效。

脚本执行完毕后,你会看到All done!。现在,用新密码测试登录:

mysql -u root -p

输入你刚设的密码,如果成功进入 MySQL 命令行(提示符变成mysql>),输入exit退出。这证明 MySQL 的核心安全加固已完成。注意,此时sudo mysql(不带-p)依然可以登录,因为auth_socket插件还在为root用户服务,这是设计使然,无需担心。

4.4 PHP 安装、模块加载与配置协同:a2enmoda2enconf的魔法

现在,让业务引擎运转起来:

sudo apt install -y php libapache2-mod-php php-mysql

这条命令安装了三样东西:php(PHP 解释器)、libapache2-mod-php(Apache 的 PHP 模块)、php-mysql(PHP 的 MySQL 扩展,让mysqli_*函数可用)。安装完成后,Apache 还不知道要加载这个模块,所以我们手动启用:

sudo a2enmod php7.4 sudo a2enconf php7.4

a2enmoda2enconf是 Apache 的“开关管理器”,它们的本质是创建符号链接。你可以用ls -l /etc/apache2/mods-enabled/ | grep phpls -l /etc/apache2/conf-enabled/ | grep php来验证链接是否创建成功。接下来,重启 Apache,让新模块生效:

sudo systemctl restart apache2

重启后,创建一个phpinfo页面来验证 PHP 是否就位:

echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php

然后在浏览器访问http://localhost/info.php。页面应该能打开,并且顶部显示PHP Version 7.4.x。滚动页面,找到Loaded Modules部分,确认里面有core,mod_php7,mpm_event。再找到mysqlnd部分,确认Client API version显示的是mysqlnd 7.4.x,这证明php-mysql扩展已加载。如果页面打不开,或者提示500 Internal Server Error,请检查 Apache 错误日志:sudo tail -f /var/log/apache2/error.log,它会实时输出错误,比如PHP Startup: Unable to load dynamic library 'mysqli.so',这说明php-mysql没装好,重新执行sudo apt install php-mysql

4.5 全链路协同验证:test_db.php的诞生与生死时速

最后,也是最关键的集成测试。我们创建一个完整的、能创建表、插入数据、查询数据的 PHP 脚本:

sudo tee /var/www/html/test_db.php << 'EOF' <?php $host = 'localhost'; $username = 'root'; $password = 'MyP@ssw0rd2023!'; // 替换为你自己的密码 $database = 'lamp_test'; // 创建连接 $conn = mysqli_connect($host, $username, $password); // 检查连接 if (!$conn) { die("Connection failed: " . mysqli_connect_error()); } // 创建数据库(如果不存在) $sql_create_db = "CREATE DATABASE IF NOT EXISTS $database CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"; if (!mysqli_query($conn, $sql_create_db)) { die("Create database failed: " . mysqli_error($conn)); } // 选择数据库 mysqli_select_db($conn, $database); // 创建测试表 $sql_create_table = "CREATE TABLE IF NOT EXISTS test_table
http://www.jsqmd.com/news/1054758/

相关文章:

  • Fate/Grand Automata:5步掌握F/GO安卓自动战斗工具配置与使用
  • 2026年化工原料优质供应商推荐:山东喜玛供应链管理有限公司1,2-丙二醇等全系供应 - 品牌推荐官
  • 2026年GEO优化公司选择全指南:7大核心标准+5家全国头部geo服务商深度推荐+选型FAQ - 互联网科技品牌测评
  • 河北三江环保设备推荐:一体化污水泵站等玻璃钢产品专业供应 - 品牌推荐官
  • CentOS 8 LAMP环境搭建与三重加固实战指南
  • 2026年重庆印刷服务优选:智创未来广告传媒提供画册/手提袋印刷包装一站式方案 - 品牌推荐官
  • HarmonyOS 6:为什么 getContext 废弃,使用 getHostContext 说明
  • 2026年管道配件实力厂家推荐:巩义市隆盛管道设备有限公司法兰接头全系供应 - 品牌推荐官
  • 从MC68HC908AZ60A到MC9S08DZ60:EEPROM、时钟与外设迁移实战指南
  • Apex Legends智能压枪宏终极指南:自动武器检测与多分辨率支持
  • 2026年五金精密配件厂家推荐:东莞市沃富五金制品有限公司螺母/铜套一站式供应 - 品牌推荐官
  • Ubuntu 20.04 下 X2Go 远程桌面实战:低带宽稳定方案
  • 2026年风阀设备专业厂家推荐:泰州华业管道设备制造有限公司全系风阀供应 - 品牌推荐官
  • 江苏普罗斯智能科技:合金喷涂加工及耐磨防腐涂层技术实力推荐 - 品牌推荐官
  • Bioicons完整指南:5步掌握免费生物科研矢量图标库
  • 2026年众智商学院SCMP前期缴费和考试认证费怎么分开付?四五六模块费用缴纳节点说明 - 众智商学院官方
  • 阿里云百炼模型全览与实战指南(2026 版)
  • Web安全入门:从零开始掌握SQL注入、XSS与越权漏洞挖掘实战
  • 暗黑破坏神2存档编辑器:从十六进制到可视化,技术玩家必备的存档管理革命
  • 3步搞定Obsidian PDF导出:让你的知识库变身精美文档
  • Performance-Fish终极指南:彻底优化RimWorld性能,告别卡顿与掉帧
  • CentOS 5/6 上部署 ejabberd 的兼容性实践
  • DeepSeek-V4 API 接入指南:破解 OpenOcta 协议认证与模型约束
  • 2026年铸铁闸门厂家实力推荐:河北智瀚水利机械平板/水库/渠道闸门全解析 - 品牌推荐官
  • 内蒙古跟团游防坑手册:选对导游,草原才是你想象中的样子(附7位持证导游全公开) - 纯玩旅游推荐官
  • 广东世腾智慧科技:家具/化工/食品/定制/冷库纸箱全系供应实力之选 - 品牌推荐官
  • 河南新丁氏纸制品推荐:豆浆杯/蛋挞杯等38品类纸杯,20余年行业经验 - 品牌推荐官
  • 2026年精密导柱生产厂家推荐:无锡杨楠机械导柱导套全系供应解析 - 品牌推荐官
  • 歌词滚动姬:零基础打造专业级歌词同步体验的极简工具
  • 从埃尔德什猜想证伪到智能底层逻辑:OpenAI 强化学习负责人深度解读 AI 科学突破的核心路径