Ubuntu 18.04 手搭 LAMP 环境:Apache+MySQL+PHP 原生部署指南
1. 项目概述:在 Ubuntu 18.04 上亲手搭起一个能跑 PHP 网站的“四件套”
你搜到这个标题,大概率正卡在某个具体动作上:可能是刚装好 Ubuntu 18.04 虚拟机,想立刻跑起一个本地测试环境;也可能是接手了一个老项目,文档里只写着“需 LAMP 环境”,而你对着终端发呆;又或者你在看某篇 PHP 教程,第一步就是“请确保已安装 LAMP”,结果发现自己的系统里只有 Linux,Apache、MySQL、PHP 全是空的。别急——这四个组件合起来叫 LAMP,不是什么神秘咒语,而是几十年来最稳、最透明、最便于你从底层理解 Web 运行逻辑的一套组合。它不依赖 Docker 镜像的黑盒封装,不靠一键脚本隐藏所有细节,而是让你亲手敲下每一行命令,看清 Apache 怎么把请求转给 PHP,PHP 又怎么连上 MySQL 拿数据,最后把 HTML 塞回浏览器。Ubuntu 18.04 虽然已停止标准支持,但它仍是大量生产服务器、教学环境和嵌入式网关的基石版本,它的软件源稳定、文档齐备、社区经验沉淀极厚。我过去三年带过 27 个新人做后端开发入门,第一课永远是手搭 LAMP:因为只有当你亲手改过 /etc/apache2/sites-available/000-default.conf ,重启服务时看到 Job for apache2.service failed 并逐行查日志定位到少了个分号,你才算真正“看见”了 Web 服务的骨架。这不是复古情怀,而是工程能力的锚点——当未来你用 Laravel Sail 或 Laradock 一键拉起整套环境时,那个藏在 docker-compose.yml 底层的 apache2.conf 和 php.ini ,你一眼就能认出它当年在 Ubuntu 18.04 里长什么样。
2. 整体设计与思路拆解:为什么坚持“原生安装”而非一键脚本或 Docker
很多人看到“LAMP 安装”第一反应是找一键脚本,比如 lamp.sh 或某些论坛流传的“三行命令搞定”。我试过不下十种,结果无一例外:要么在 Ubuntu 18.04 的 apt 源上因包名变更失败,要么装完 Apache 版本是 2.4.18(太旧,不支持 mod_rewrite 的某些新语法),要么 PHP 扩展没开全,连 mysqli 都报错。更麻烦的是,一旦出问题,你面对的是一堆被封装在脚本里的 if-else 判断和 curl 下载逻辑,调试成本远高于从头装。Docker 方案看似现代,但对初学者反而制造了认知屏障——你得先懂镜像分层、卷挂载、网络模式,才能搞明白为什么 localhost:8080 访问不到容器里的 PHP 页面。而原生安装的核心价值,在于它强制你建立一套清晰的因果链: apt install apache2 → /var/www/html/ 成为默认根目录 → 修改 000-default.conf 就能换路径 → systemctl restart apache2 是唯一生效方式。这种线性关系,是理解任何 Web 架构的起点。
Ubuntu 18.04 的软件源策略决定了我们的选型逻辑。它默认提供的是 Apache 2.4.29 、 MySQL 5.7.33 、 PHP 7.2.24 这一组经过充分测试的版本。有人会问:“PHP 7.2 不是早就 EOL 了吗?为什么不装 8.x?” 这是个好问题。答案是:Ubuntu 18.04 的 universe 源里没有官方 PHP 8.x 包,强行从第三方 PPA 添加(如 ondrej/php)虽可行,但会破坏系统包管理的完整性——你得手动处理 apt update 时的密钥警告、版本冲突,甚至可能影响 ubuntu-desktop 的升级。对于学习和轻量级部署,PHP 7.2 完全够用,且它的语法和扩展机制与 8.x 差异不大,核心概念(如 mysqli 连接、 PDO 预处理、 error_reporting 级别)完全一致。更重要的是,MySQL 5.7 是最后一个默认使用 mysql_native_password 认证插件的版本,这恰好避开了 MySQL 8.0+ 默认的 caching_sha2_password 在 PHP 连接时需要额外配置的坑。所以,我们不追求“最新”,而追求“最稳”:用系统源原生包,省去所有兼容性博弈,把精力聚焦在理解组件间如何协作上。
3. 核心细节解析与实操要点:每个组件的安装逻辑与关键配置项
3.1 Apache:不只是“装上就行”,关键是理解它的模块化与虚拟主机机制
Apache 在 Ubuntu 18.04 中以 apache2 包形式存在,但它的强大不在于安装本身,而在于其模块化设计。默认安装只启用最基础的模块( mpm_event , authz_core , access_compat ),而 PHP 支持需要手动启用 php7.2 模块。很多人卡在这一步,以为装完 PHP 就自动集成,其实不然——Apache 必须明确知道“遇到 .php 文件时,该调用哪个模块来处理”。这个指令就藏在 /etc/apache2/mods-enabled/php7.2.load 里,它本质是一个软链接,指向 /etc/apache2/mods-available/php7.2.load 。如果你用 a2dismod php7.2 关闭过,再 a2enmod php7.2 启用,就是在操作这个链接。另一个常被忽略的点是 mpm (Multi-Processing Module)的选择。Ubuntu 18.04 默认启用 mpm_event ,它适合高并发静态文件服务,但 PHP 的传统 mod_php 模式要求 mpm_prefork 。所以,我们必须先禁用 event ,再启用 prefork :
sudo a2dismod mpm_event
sudo a2enmod mpm_prefork
sudo a2enmod php7.2
提示:执行
a2enmod后不会立即生效,必须sudo systemctl restart apache2。很多新手改完配置却刷新页面还是 403 错误,就是因为忘了这一步重启。
虚拟主机(Virtual Host)是 Apache 的灵魂。默认的 000-default.conf 文件定义了监听 *:80 的站点,根目录为 /var/www/html 。但实际项目中,你绝不会把所有代码扔进这个目录。正确的做法是为每个项目创建独立的 .conf 文件,比如 /etc/apache2/sites-available/myproject.conf ,内容如下:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName myproject.local
DocumentRoot /var/www/myproject/public
<Directory /var/www/myproject/public>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/myproject_error.log
CustomLog ${APACHE_LOG_DIR}/myproject_access.log combined
</VirtualHost>
这里的关键是 AllowOverride All —— 它允许项目根目录下的 .htaccess 文件覆盖 Apache 全局设置,这是 Laravel、WordPress 等框架实现漂亮 URL(如 /posts/123 而非 /index.php?post=123 )的基础。而 ServerName myproject.local 则要求你在本地 /etc/hosts 文件中添加一行 127.0.0.1 myproject.local ,否则浏览器无法解析这个域名。
3.2 MySQL:安全初始化比“设个密码”重要十倍
Ubuntu 18.04 的 mysql-server 包安装后,会自动运行 mysql_secure_installation 脚本,这是整个流程中最不能跳过的环节。它不只是让你设 root 密码,而是执行四步关键加固:
- 移除匿名用户(Remove anonymous users) :默认 MySQL 允许
''@'localhost'这样的空用户名登录,这是巨大安全隐患; - 禁止远程 root 登录(Disallow root login remotely) :确保 root 只能在本机通过
sudo mysql -u root进入,杜绝网络暴露; - 删除 test 数据库(Remove test database and access to it) :
test库默认对所有用户可读写,极易被利用; - 重载权限表(Reload privilege tables now) :让上述修改立即生效。
注意:
mysql_secure_installation脚本在 Ubuntu 18.04 中有时会因auth_socket插件问题卡在密码验证环节。如果遇到ERROR 1698 (28000): Access denied for user 'root'@'localhost',请先用sudo mysql进入,然后执行:USE mysql; UPDATE user SET plugin='mysql_native_password' WHERE User='root'; FLUSH PRIVILEGES; EXIT;再运行
sudo mysql_secure_installation即可。
创建应用数据库和用户时,切忌直接用 root。正确姿势是:
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'myapp_user'@'localhost' IDENTIFIED BY 'StrongPass123!';
GRANT ALL PRIVILEGES ON myapp.* TO 'myapp_user'@'localhost';
FLUSH PRIVILEGES;
这里用了 utf8mb4 而非 utf8 ,是因为前者完整支持 Emoji 和四字节 Unicode 字符(如某些生僻汉字),而旧 utf8 在 MySQL 中实际是 utf8mb3 ,会截断数据。 GRANT ALL PRIVILEGES 看似粗放,但在开发机上可接受;生产环境应精确到 SELECT, INSERT, UPDATE, DELETE 。
3.3 PHP:7.2 的扩展管理与配置文件定位逻辑
Ubuntu 18.04 的 PHP 7.2 默认只安装核心包 php7.2-cli ,Web 服务需要额外安装 libapache2-mod-php7.2 (让 Apache 调用 PHP)和 php7.2-mysql (提供 MySQL 连接能力)。但很多 PHP 项目还依赖其他扩展,比如 php7.2-curl (HTTP 请求)、 php7.2-gd (图片处理)、 php7.2-mbstring (多字节字符串,中文处理必备)。安装命令是:
sudo apt install php7.2-curl php7.2-gd php7.2-mbstring php7.2-xml php7.2-zip
PHP 的配置文件有两套:CLI(命令行)用 /etc/php/7.2/cli/php.ini ,Apache 模块用 /etc/php/7.2/apache2/php.ini 。它们是独立的!你改了 CLI 的 memory_limit ,不影响网页里的内存限制。检查当前生效的配置,最可靠的方法不是猜路径,而是创建一个 info.php 文件:
<?php phpinfo(); ?>
放在 /var/www/html/ 下,用浏览器访问 http://localhost/info.php ,页面顶部会明确显示 “Loaded Configuration File” 的路径。常见需调整的参数:
display_errors = On(开发时打开,方便调试;生产必须Off)error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED(显示所有错误,但忽略提示和弃用警告)date.timezone = Asia/Shanghai(避免date()函数报时区警告)
实操心得:每次修改
php.ini后,必须sudo systemctl restart apache2,因为 PHP 配置是 Apache 启动时加载的,不是运行时热更新。
4. 实操过程与核心环节实现:从零开始的完整搭建流水线
4.1 环境准备与系统更新:别跳过这三分钟,它省你三小时
在任何安装前,先确保系统干净、源列表最新、基础工具就位。这不是仪式感,而是 Ubuntu 包管理的硬性前提:
# 1. 更新软件包索引(同步远程源的包列表)
sudo apt update
# 2. 升级已安装的包(修复已知漏洞,避免依赖冲突)
sudo apt upgrade -y
# 3. 安装常用基础工具(wget 下载、curl 测试、unzip 解压、git 版本控制)
sudo apt install -y wget curl unzip git
# 4. 验证基础环境(确认 curl 和 wget 可用,为后续下载做准备)
curl --version
wget --version
为什么强调 -y 参数?因为它自动确认所有 apt 的交互式提问(如“是否继续?[Y/n]”)。在自动化脚本或远程服务器上,没有 -y 会导致命令卡死。但注意: apt upgrade 加 -y 有风险,它会自动重启服务(如 sshd ),如果你是 SSH 连接,可能断开。所以建议先 apt list --upgradable 查看将升级哪些包,确认无关键服务再执行。
4.2 Apache 安装与基础验证:让“It Works!”真正出现
现在开始安装 Apache:
# 安装 apache2 包(包含主程序、默认配置、基础模块)
sudo apt install -y apache2
# 启用并启动服务(enable=开机自启,start=立即运行)
sudo systemctl enable apache2
sudo systemctl start apache2
# 检查服务状态(确认 Active: active (running))
sudo systemctl status apache2
此时,打开浏览器访问 http://localhost 或 http://你的服务器IP ,应该看到经典的 “Apache2 Ubuntu Default Page”。如果看不到,请按顺序排查:
- 防火墙 :Ubuntu 18.04 默认启用
ufw(Uncomplicated Firewall)。检查状态:sudo ufw status。如果显示Status: active且80端口未开放,执行sudo ufw allow 'Apache Full'(它会同时开放 80 和 443)。 - 端口占用 :执行
sudo ss -tulpn | grep ':80',看是否有其他进程(如 Nginx、Python HTTP 服务)占用了 80 端口。若有,sudo kill -9 <PID>杀掉它。 - SELinux/AppArmor :Ubuntu 18.04 默认用 AppArmor。检查日志:
sudo journalctl -u apache2 | grep -i denied。若出现apparmor="DENIED",说明安全模块阻止了 Apache 访问某些文件,需临时禁用测试:sudo systemctl stop apparmor(仅用于排查,勿长期关闭)。
提示:
systemctl status的输出里,Loaded:行会显示配置文件路径(通常是/lib/systemd/system/apache2.service),这是你日后定制启动参数的地方。
4.3 MySQL 安装与安全初始化:从“空密码”到“最小权限”
# 安装 mysql-server(会自动安装 mysql-client 和依赖)
sudo apt install -y mysql-server
# 运行安全脚本(全程按提示操作,密码务必记牢)
sudo mysql_secure_installation
安全脚本交互示例(你的输入用 ** 标出):
Securing the MySQL server deployment.
Connecting to MySQL using a blank password.
VALIDATE PASSWORD PLUGIN can be used to test passwords and improve security. It checks the strength of password and allows the users to set only those passwords which are secure enough. Would you like to setup VALIDATE PASSWORD plugin?
Press y|Y for Yes, any other key for No: **N** # 开发环境可跳过复杂密码策略
New password: **MyRootPass123!**
Re-enter new password: **MyRootPass123!**
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. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment.
Remove anonymous users? (Press y|Y for Yes, any other key for No) : **Y**
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**
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**
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**
验证 MySQL 是否正常:
# 用 root 用户登录(会提示输入密码)
sudo mysql -u root -p
# 在 MySQL 提示符下,执行简单查询
mysql> SHOW DATABASES;
mysql> EXIT;
4.4 PHP 及扩展安装:让 Apache 能“读懂” PHP 文件
# 安装 PHP 核心及 Apache 模块
sudo apt install -y php7.2 libapache2-mod-php7.2
# 安装常用扩展(根据项目需求增减)
sudo apt install -y php7.2-mysql php7.2-curl php7.2-gd php7.2-mbstring php7.2-xml php7.2-zip
# 重启 Apache,使 PHP 模块生效
sudo systemctl restart apache2
创建测试文件验证 PHP 解析:
# 编辑 /var/www/html/test.php
sudo nano /var/www/html/test.php
写入内容:
<?php
echo "PHP is working! Version: " . phpversion();
phpinfo();
?>
保存后,浏览器访问 http://localhost/test.php 。如果只看到纯文本 <?php echo ... ,说明 PHP 模块未启用或 Apache 未重启;如果看到 PHP 版本和详细的 phpinfo() 页面,恭喜,PHP 已就绪。
4.5 创建第一个 PHP+MySQL 项目:连接数据库并显示数据
现在,我们整合所有组件,做一个真实可用的小项目。目标:创建一个 users 表,插入一条记录,用 PHP 读取并显示。
步骤 1:创建数据库和用户
sudo mysql -u root -p
-- 创建数据库
CREATE DATABASE lamp_demo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 创建专用用户
CREATE USER 'lamp_user'@'localhost' IDENTIFIED BY 'DemoPass456!';
-- 授予数据库权限
GRANT ALL PRIVILEGES ON lamp_demo.* TO 'lamp_user'@'localhost';
-- 刷新权限
FLUSH PRIVILEGES;
-- 使用新数据库
USE lamp_demo;
-- 创建 users 表
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入测试数据
INSERT INTO users (name, email) VALUES ('张三', 'zhangsan@example.com');
-- 查询验证
SELECT * FROM users;
EXIT;
步骤 2:编写 PHP 连接脚本
sudo nano /var/www/html/db_test.php
<?php
$host = 'localhost';
$dbname = 'lamp_demo';
$username = 'lamp_user';
$password = 'DemoPass456!';
try {
// 使用 PDO 连接 MySQL(推荐,更安全)
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
// 查询所有用户
$stmt = $pdo->query("SELECT * FROM users");
$users = $stmt->fetchAll();
echo "<h2>LAMP Demo Users</h2>";
echo "<table border='1'>";
echo "<tr><th>ID</th><th>Name</th><th>Email</th><th>Created At</th></tr>";
foreach ($users as $user) {
echo "<tr>";
echo "<td>" . htmlspecialchars($user['id']) . "</td>";
echo "<td>" . htmlspecialchars($user['name']) . "</td>";
echo "<td>" . htmlspecialchars($user['email']) . "</td>";
echo "<td>" . htmlspecialchars($user['created_at']) . "</td>";
echo "</tr>";
}
echo "</table>";
} catch (PDOException $e) {
die("Connection failed: " . $e->getMessage());
}
?>
步骤 3:访问测试
浏览器打开 http://localhost/db_test.php 。如果看到一个带边框的表格,显示 ID、Name、Email、Created At 和那条测试数据,说明 LAMP 四件套已完全打通。整个数据流是:浏览器请求 → Apache 接收 → 发现 .php 后缀 → 调用 libapache2-mod-php7.2 → PHP 解析脚本 → PDO 连接 localhost:3306 的 MySQL → 执行 SQL → 返回 HTML。
5. 常见问题与排查技巧实录:那些让我熬夜到凌晨三点的坑
5.1 Apache 启动失败: Job for apache2.service failed
这是最高频的报错。不要慌,按以下顺序排查:
| 排查步骤 | 命令/操作 | 说明 |
|---|---|---|
| 1. 查看详细错误日志 | sudo journalctl -u apache2 -n 50 --no-pager |
-n 50 显示最近 50 行, --no-pager 防止分页器干扰。重点看 AH00526 开头的配置错误。 |
| 2. 检查配置语法 | sudo apache2ctl configtest |
这是 Apache 自带的语法检查器。输出 Syntax OK 才代表配置文件无硬错误。 |
| 3. 定位错误行 | sudo nano /etc/apache2/apache2.conf 或对应 .conf 文件 |
如果 configtest 报错如 Invalid command 'SSLEngine', perhaps misspelled or defined by a module not included in the server configuration ,说明你启用了 mod_ssl 但没加载模块,执行 sudo a2enmod ssl 。 |
| 4. 检查端口冲突 | sudo ss -tulpn | grep ':80' |
如果看到 nginx 或 node 占用, sudo kill -9 <PID> 。 |
实操心得:我曾在一个客户服务器上遇到
AH00534: apache2: Configuration error: No MPM loaded.。查日志发现mpm_event和mpm_prefork被同时启用,而 Apache 只允许一个 MPM。解决方法是sudo a2dismod mpm_event && sudo a2enmod mpm_prefork && sudo systemctl restart apache2。
5.2 PHP 页面显示源码,不解析
现象:浏览器打开 .php 文件,显示的是 <?php echo ... 的原始代码,而非执行结果。
根本原因 :Apache 没有加载 PHP 模块,或模块加载顺序错误。
解决方案 :
- 确认模块已启用:
ls /etc/apache2/mods-enabled/ \| grep php,应看到php7.2.load和php7.2.conf。 - 确认
mpm_prefork已启用:ls /etc/apache2/mods-enabled/ \| grep mpm,应只有mpm_prefork.load,不能有mpm_event.load。 - 检查
/etc/apache2/mods-enabled/php7.2.conf内容,确保包含:<FilesMatch \.php$> SetHandler application/x-httpd-php </FilesMatch> - 终极验证 :执行
apache2ctl -M \| grep php,输出应包含php7_module (shared)。
5.3 MySQL 连接被拒绝: Connection refused 或 Access denied
| 错误类型 | 可能原因 | 解决方案 |
|---|---|---|
Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' |
MySQL 服务未运行 | sudo systemctl status mysql → sudo systemctl start mysql |
Access denied for user 'lamp_user'@'localhost' |
用户密码错误,或权限未刷新 | sudo mysql -u root -p → FLUSH PRIVILEGES; |
Connection refused (用 IP 连接时) |
MySQL 绑定地址是 127.0.0.1 ,不监听外部 |
编辑 /etc/mysql/mysql.conf.d/mysqld.cnf ,注释掉 bind-address = 127.0.0.1 ,重启 sudo systemctl restart mysql ( 仅限内网测试,生产环境严禁! ) |
Client does not support authentication protocol requested by server |
PHP 7.2 与 MySQL 8.0+ 的认证插件不兼容 | 此问题在 Ubuntu 18.04 + MySQL 5.7 组合中 不会出现 ,因为 5.7 默认用 mysql_native_password 。 |
5.4 PHP 连接 MySQL 失败: Call to undefined function mysqli_connect()
现象:PHP 脚本报错,说找不到 mysqli_connect 函数。
原因 : php7.2-mysql 扩展未安装,或安装后未在 php.ini 中启用。
验证与修复 :
- 检查扩展是否安装:
dpkg -l \| grep php7.2-mysql,应有输出。 - 检查
php.ini中是否启用了扩展:sudo nano /etc/php/7.2/apache2/php.ini,搜索;extension=mysqli,去掉前面的分号;,保存。 - 重启 Apache :
sudo systemctl restart apache2(再次强调,这是关键!)。
5.5 中文乱码:网页显示 ???? 或方块
这是字符集不一致导致的经典问题,需三处统一:
- MySQL 数据库/表字符集 :建库时用
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci。 - PHP 连接时指定字符集 :在 PDO DSN 中加入
charset=utf8mb4,或在mysqli连接后执行mysqli_set_charset($conn, 'utf8mb4')。 - HTML 页面声明 :在 PHP 输出的 HTML
<head>中加入<meta charset="UTF-8">。
提示:
utf8mb4是 MySQL 对完整 UTF-8 的实现,utf8是别名,实际是utf8mb3。用utf8mb4可避免 Emoji 和部分生僻字存储失败。
6. 进阶配置与生产就绪建议:从“能跑”到“稳跑”
6.1 Apache 性能微调:应对小流量突发
Ubuntu 18.04 默认的 mpm_prefork 配置( StartServers 5 , MinSpareServers 5 , MaxSpareServers 10 , MaxRequestWorkers 150 )对个人开发绰绰有余,但若要支撑几十人同时访问的内部工具,可适度优化。编辑 /etc/apache2/mods-available/mpm_prefork.conf :
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 250 # 原150,提升至250
MaxConnectionsPerChild 10000
</IfModule>
MaxRequestWorkers 是最大并发连接数,值越大越耗内存。计算公式: MaxRequestWorkers ≈ (总内存 - 系统预留) / 每个 Apache 进程平均内存 。在 2GB 内存的 VPS 上,250 是安全上限。
6.2 PHP 安全加固:关闭危险函数与错误显示
开发时 display_errors = On 很方便,但上线后必须关闭,否则会泄露服务器路径、PHP 版本等敏感信息。编辑 /etc/php/7.2/apache2/php.ini :
; 关闭错误显示(生产环境必须!)
display_errors = Off
log_errors = On
error_log = /var/log/php/error.log
; 禁用高危函数(防止恶意脚本执行系统命令)
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
注意:
disable_functions会禁用curl_exec,如果你的项目依赖 cURL,需将其从列表中移除。安全与功能需权衡。
6.3 MySQL 连接池与慢查询日志:让数据库“会呼吸”
默认 MySQL 连接是“用完即丢”,频繁创建销毁连接很耗资源。开启查询缓存(虽然 MySQL 5.7 中已废弃,但连接池思想仍在):
-- 查看当前连接数
SHOW VARIABLES LIKE 'max_connections';
SHOW STATUS LIKE 'Threads_connected';
-- 开启慢查询日志(记录执行超2秒的SQL)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log';
然后在 /etc/mysql/mysql.conf.d/mysqld.cnf 的 [mysqld] 段落下添加:
slow_query_log = 1
long_query_time = 2
slow_query_log_file = /var/log/mysql/mysql-slow.log
6.4 自动化部署脚本:把 20 分钟操作压缩成 1 分钟
把上面所有步骤写成一个可复用的 Bash 脚本,是资深运维的基本功。以下是一个精简版 install_lamp.sh :
#!/bin/bash
# LAMP Installer for Ubuntu 18.04
set -e # 任何命令失败则退出
echo "=== Updating system ==="
sudo apt update && sudo apt upgrade -y
echo "=== Installing Apache ==="
sudo apt install -y apache2
sudo systemctl enable apache2
sudo systemctl start apache2
echo "=== Installing MySQL ==="
sudo apt install -y mysql-server
# 自动化安全脚本(跳过密码策略,设root密码为'root')
sudo mysql_secure_installation <<EOF
n
root
root
y
y
y
y
EOF
echo "=== Installing PHP ==="
sudo apt install -y php7.2 libapache2-mod-php7.2 php7.2-mysql php7.2-curl php7.2-gd php7.2-mbstring php7.2-xml php7.2-zip
sudo systemctl restart apache2
echo "=== Creating test page ==="
echo "<?php echo 'LAMP installed successfully! PHP version: ' . phpversion(); ?>" | sudo tee /var/www/html/lamp_test.php
echo "=== Done! Visit http://$(hostname -I | awk '{print $1}')/lamp_test.php ==="
赋予执行权并运行: chmod +x install_lamp.sh && ./install_lamp.sh 。脚本中的 <<EOF ... EOF 是 Here Document 语法,用于向 mysql_secure_installation 自动输入答案,避免交互阻塞。
7. 项目收尾与个人体会:为什么这套“老古董”依然值得你花时间
写完这篇近六千字的实操指南,我重新打开了自己三年前在 Ubuntu 18.04 上搭的第一个 LAMP 环境。 /var/www/html/ 目录下,那个名为 first_project 的文件夹还在,里面 index.php 的第一行注释写着:“2021-03-15, LAMP 搭建成功,PHP 7.2.24, MySQL 5.7.33”。当时为了搞懂 AllowOverride All 和 .htaccess 的关系,我在 DocumentRoot 下反复创建、删除、修改,直到 mod_rewrite 规则真的把 /about 重写成 /index.php?page=about 。那种“啊哈!”的顿悟感,是任何一键脚本都无法给予的。
今天,Docker、Kubernetes、Serverless 这些词铺天盖地,但它们的底层,依然是 Linux 进程、TCP 连接、文件系统权限这些朴素的概念。LAMP 就像一辆结构透明的老爷车,引擎盖打开,每个活塞、每根皮带都清晰可见。你不需要记住所有 docker-compose 的 YAML 参数,但必须理解 volumes 是如何把宿主机目录映射进容器的——而这,正是 Apache 的 DocumentRoot 和 MySQL 的 datadir 在几十年前就教会我们的事。
所以,如果你正站在 Ubuntu 18.04 的终端前,犹豫要不要点开那个“一键安装”的链接,请停下来,亲手敲下 sudo apt install apache2 。不是为了怀旧,而是为了在技术浪潮中,牢牢抓住那根叫“原理”的锚链。它不会让你立刻写出最炫的前端,但会让你在任何故障面前,都有底气打开日志,逐行阅读,然后说:“哦,原来是这里错了。” 这份底气,才是一个工程师真正的护城河。
更多推荐
所有评论(0)