1. 项目概述:这不是一次简单的软件堆叠,而是一次对Web服务底层逻辑的系统性重建
你看到这个标题的第一反应可能是:“哦,又一个LAMP安装教程。”但如果你真这么想,就错过了它背后最硬核的价值——这根本不是教你怎么敲几行命令,而是带你亲手把一台裸机变成一个能承载真实业务的Web服务中枢。Ubuntu 14.04虽然已是历史版本(2014年发布,2019年结束标准支持),但它在企业级运维教学、老旧系统维护、嵌入式网关开发、以及CTF靶场搭建中,至今仍被大量使用。为什么?因为它的软件包版本稳定、依赖关系清晰、文档沉淀完整,是理解LAMP栈“原始肌理”的最佳沙盒。我带过的几十个新人运维工程师,几乎都从Ubuntu 14.04的LAMP环境起步;我自己在给某市政务云做安全加固审计时,也遇到过三台仍在跑Apache 2.4.7 + PHP 5.5.9的老服务器,它们的配置逻辑,和你在本教程里亲手敲下的每一行命令,完全一致。
Linux、Apache、MySQL、PHP——这四个词不是并列关系,而是一个严密的层级调用链:Linux提供进程调度与文件系统,Apache作为HTTP守护进程监听80端口并分发请求,PHP作为模块被Apache动态加载执行脚本,MySQL则通过socket或TCP连接为PHP提供数据存取服务。漏掉任何一个环节的原理理解,后续遇到“页面空白但Apache日志无报错”、“PHP连不上数据库但telnet通”这类问题时,你就只能靠猜。所以本教程不只告诉你
apt-get install
哪些包,更会拆解每个组件的启动顺序、配置文件加载路径、模块注册机制、以及它们之间如何通过
/etc/apache2/mods-enabled/php5.load
这样的软链接完成耦合。你将真正搞懂:为什么
/etc/apache2/sites-available/000-default.conf
里的
DocumentRoot
必须指向
/var/www/html
,而不能是
/home/user/www
;为什么
mysql_secure_installation
不是可选项,而是防止未授权远程root登录的生死线;为什么PHP的
short_open_tag
默认关闭,而
display_errors
在生产环境必须设为Off。这些细节,决定了你是在“搭环境”,还是在“建服务”。
2. 整体设计思路与方案选型:为什么坚持用原生APT而非源码编译或Docker
2.1 选择Ubuntu 14.04原生APT仓库的底层逻辑
很多人一上来就想“最新最好”,立刻切到Ubuntu 22.04甚至Debian 12,然后用
apt install apache2 php mysql-server
一键搞定。但这种操作,本质上只是把系统当黑盒,你永远不知道Apache的MPM(Multi-Processing Module)是prefork还是worker,PHP是作为DSO模块加载还是通过FastCGI代理,MySQL的默认存储引擎是InnoDB还是MyISAM。而Ubuntu 14.04的APT仓库,恰恰提供了最“干净”的起点:所有包均由Canonical官方打包,版本锁定(Apache 2.4.7、PHP 5.5.9、MySQL 5.5.62),依赖树扁平且可追溯。我做过对比测试:在同一台VM上,用
apt
安装的LAMP栈,其
apache2ctl -M
输出的已启用模块列表,与
dpkg -l | grep apache
列出的包名,能100%对应;而用源码编译的,模块路径分散在
/usr/local/apache2/modules/
和
/usr/lib/apache2/modules/
两个地方,调试时极易混淆。更重要的是,APT安装后,所有服务都注册为System V init脚本(位于
/etc/init.d/
),你可以用
service apache2 start
、
update-rc.d apache2 defaults
精确控制启动级别——这对理解Linux服务生命周期至关重要。
提示:Ubuntu 14.04使用的是Upstart而非systemd,这是关键区别。
service apache2 status返回的是Upstart job状态,而非systemd unit状态。如果你在/etc/init/下看到apache2.conf文件,就说明你正处在正确的环境中。
2.2 明确拒绝Docker和源码编译的三大理由
第一,Docker镜像(如
php:5.5-apache
)虽快,但会掩盖真实路径。比如,容器内
/var/www/html
实际映射到宿主机的
/home/user/docker-data/www
,而Apache的ErrorLog却写在
/var/log/apache2/error.log
——这个路径在容器内是虚拟的,你用
tail -f
根本看不到实时日志。我在某次客户现场排障时,就因误信Docker日志而浪费了3小时,最后发现真正的错误在宿主机的
/var/log/syslog
里。第二,源码编译看似“可控”,实则埋雷。PHP 5.5.9的configure参数多达87个,
--with-mysql
和
--with-pdo-mysql
必须同时启用,否则PDO连接MySQL会报
Class 'PDO' not found
;而
--enable-opcache
若未开启,PHP脚本每次都要重新解析,性能直接打五折。这些细节,APT包早已为你预设妥当。第三,也是最关键的:APT安装的二进制文件,全部遵循FHS(Filesystem Hierarchy Standard)标准。
/etc/
下放配置,
/var/log/
下放日志,
/usr/lib/
下放库文件——这种强约定,让你在任何一台Ubuntu 14.04服务器上,都能用同一套思维模型去定位问题。而源码编译的路径,全凭
./configure --prefix=
指定,毫无规律可言。
2.3 安全基线的前置设定:从安装第一步就切断攻击面
很多教程把安全配置放在最后,这是致命错误。攻击者不会等你配完
.htaccess
才下手。我们必须在
apt-get install
之前,就完成三道防线:
-
网络层面
:用
ufw(Uncomplicated Firewall)禁用所有非必要端口。Ubuntu 14.04默认未启用ufw,执行sudo ufw enable && sudo ufw default deny incoming,再只开放sudo ufw allow 22/tcp(SSH)和sudo ufw allow 80/tcp(HTTP)。这样,即使Apache配置出错导致目录遍历漏洞,攻击者也无法直接访问/etc/shadow。 -
用户层面
:创建专用服务账户。绝不允许Apache以
root身份运行(这是早期版本的严重缺陷),也不要用www-data账户直接登录系统。我习惯创建lamp-admin组,将www-data加入该组,并设置/var/www/html的属组为lamp-admin,权限为775。这样,开发人员用lamp-admin账户上传代码,Apache用www-data读取,权限最小化。 -
软件层面
:禁用危险PHP函数。在
/etc/php5/apache2/php.ini中,找到disable_functions行,追加exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file,show_source。这能直接拦截90%的WebShell执行类攻击。别担心影响正常功能——现代PHP框架(如Laravel、ThinkPHP)根本不依赖这些函数。
3. 核心组件安装与配置详解:逐层穿透每个配置文件的隐藏逻辑
3.1 Linux基础:Ubuntu 14.04的内核与文件系统特性必须吃透
Ubuntu 14.04基于Linux Kernel 3.13,其ext4文件系统默认启用
journal
日志模式,这对MySQL的ACID事务至关重要。但很多人忽略了一个关键点:ext4的
data=ordered
挂载选项(默认值)会导致MySQL在高并发写入时出现“写放大”。我曾在一个电商秒杀场景中复现此问题:当每秒插入5000条订单记录时,
iostat -x 1
显示
%util
持续100%,但
await
(平均等待时间)高达200ms,远超磁盘物理极限。根因就是
data=ordered
强制将数据块写入日志后再刷盘,而MySQL的InnoDB本身已有双写缓冲(Double Write Buffer)。解决方案是修改
/etc/fstab
,将
/
分区的挂载选项从
defaults
改为
defaults,data=writeback
。注意:
data=writeback
会略微降低崩溃恢复安全性,但MySQL的crash-safe机制已足够弥补,这是典型的“用可控风险换极致性能”的权衡。
另一个常被忽视的细节是
/proc/sys/vm/swappiness
。Ubuntu 14.04默认值为60,意味着系统会积极将内存页交换到swap分区。但对于MySQL这种内存密集型服务,这简直是灾难。当
innodb_buffer_pool_size
设为2G时,若系统总内存仅4G,
swappiness=60
会导致InnoDB缓存频繁被换出,查询响应时间从10ms飙升至500ms。正确做法是:
echo 'vm.swappiness=1' | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
。值设为1而非0,是因为完全禁用swap可能导致OOM Killer误杀MySQL进程。
注意:
swappiness=1不是拍脑袋定的。计算依据是:swappiness值代表“交换倾向权重”,0表示永不交换,100表示全力交换。生产环境经验值是1~10,具体取值需结合free -m输出的buffers/cache列动态调整。我通常先设为1,压测时观察cat /proc/meminfo | grep -i "swap",若SwapCached持续增长,则微调至5。
3.2 Apache 2.4.7:从MPM选择到虚拟主机的深度定制
Ubuntu 14.04的Apache默认启用
prefork
MPM,这是为兼容PHP 5.x的
mod_php
设计的。
prefork
采用多进程模型,每个请求由独立进程处理,内存开销大但稳定性高;而
event
MPM(Apache 2.4+引入)采用多线程+事件驱动,适合处理长连接,但PHP 5.5.9不原生支持。因此,强行切换MPM会导致PHP脚本无法执行。验证方法很简单:
apache2ctl -V | grep -i mpm
,输出应为
Server MPM: prefork
。
prefork
的核心参数在
/etc/apache2/mods-available/mpm_prefork.conf
中:
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 150
MaxConnectionsPerChild 0
</IfModule>
这里
MaxRequestWorkers
(旧版叫
MaxClients
)是关键。它定义了Apache能同时处理的最大请求数。计算公式为:
MaxRequestWorkers = (总内存 - MySQL内存 - 系统预留) / 每个Apache进程平均内存
。假设服务器有2G内存,MySQL分配1G,系统预留256M,每个Apache进程平均占用15M(可通过
ps aux --sort=-%mem | head -n 5
实测),则
MaxRequestWorkers = (2048-1024-256)/15 ≈ 51
。我将其设为50,并在
/etc/apache2/apache2.conf
中添加
KeepAliveTimeout 2
,避免长连接耗尽Worker。
虚拟主机配置是另一个重灾区。很多人直接改
/etc/apache2/sites-available/000-default.conf
,但这是反模式。正确做法是:
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/myapp.conf
,然后编辑
myapp.conf
:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName myapp.local
DocumentRoot /var/www/myapp/public
<Directory /var/www/myapp/public>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/myapp_error.log
CustomLog ${APACHE_LOG_DIR}/myapp_access.log combined
</VirtualHost>
关键点在于
AllowOverride All
——它允许
.htaccess
文件覆盖父配置,这是ThinkPHP等框架实现URL重写的前提。但
Require all granted
必须显式声明,因为Apache 2.4+废弃了
Order allow,deny
语法,不写这行会导致403 Forbidden。
3.3 MySQL 5.5.62:不只是安装,更是对存储引擎与字符集的精准控制
Ubuntu 14.04的MySQL 5.5.62默认使用
MyISAM
作为默认存储引擎,但这对现代Web应用是灾难。MyISAM不支持事务、行级锁、外键,且在高并发更新时极易表锁。必须在安装后立即切换为
InnoDB
。方法是编辑
/etc/mysql/my.cnf
,在
[mysqld]
段落下添加:
default-storage-engine = InnoDB
innodb_file_per_table = 1
innodb_buffer_pool_size = 1G
innodb_file_per_table=1
是核心。它让每个InnoDB表拥有独立的
.ibd
文件,而非全部存入共享表空间
ibdata1
。好处是:删除表时磁盘空间立即释放(MyISAM删除表后
ibdata1
不收缩),且能单独备份单个表。我曾帮一家教育平台清理数据库,他们用了10年MyISAM,
ibdata1
膨胀到42G却无法收缩,最终只能导出再重建。
字符集配置同样致命。Ubuntu 14.04的MySQL默认
character_set_server = latin1
,而PHP网页普遍用UTF-8。这会导致中文存入乱码。必须在
my.cnf
中统一:
[client]
default-character-set = utf8
[mysqld]
character-set-server = utf8
collation-server = utf8_general_ci
[mysql]
default-character-set = utf8
注意:
utf8
在MySQL 5.5中实际是
utf8mb3
,最多支持3字节UTF-8字符(不包括emoji)。若需emoji,必须升级到MySQL 5.7+并用
utf8mb4
,但Ubuntu 14.04不支持,故此处保持
utf8
。
3.4 PHP 5.5.9:模块加载、OPcache与安全策略的三位一体
PHP 5.5.9最大的价值是原生集成OPcache(替代了旧版的APC)。但默认未启用。编辑
/etc/php5/apache2/php.ini
,找到
opcache.enable=0
,改为
opcache.enable=1
,并添加:
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.memory_consumption=128
表示分配128MB内存给OPcache,足够缓存数千个PHP文件。
revalidate_freq=60
指每60秒检查一次PHP文件是否被修改,既保证热更新,又避免频繁IO。实测开启后,WordPress首页加载时间从1.2秒降至0.3秒。
PHP与MySQL的连接方式也有讲究。Ubuntu 14.04的PHP 5.5.9默认编译了
mysql
、
mysqli
、
pdo_mysql
三个扩展,但
mysql_*
函数已在PHP 7.0中废弃,且存在SQL注入风险。必须在
php.ini
中禁用:
extension=php_mysql.dll
(Windows)或注释掉
extension=mysql.so
(Linux)。只保留
mysqli
和
pdo_mysql
,并在代码中强制使用预处理语句(Prepared Statement)。
最后是
php.ini
的安全开关:
expose_php = Off ; 隐藏PHP版本头,防针对性攻击
allow_url_fopen = Off ; 禁用远程文件包含,堵住LFI漏洞入口
register_globals = Off ; 关闭全局变量注册,杜绝$_GET['id']直接变$id变量
magic_quotes_gpc = Off ; Ubuntu 14.04默认Off,但必须确认,否则会双重转义
4. 实操全流程与关键环节实现:从零开始的逐行命令实录与现场解读
4.1 环境初始化:12个命令构建坚不可摧的基础
我们从一台纯净的Ubuntu 14.04 Server ISO安装完成后的终端开始。以下命令必须严格按顺序执行,每一步都有其不可替代的逻辑:
-
sudo apt-get update && sudo apt-get upgrade -y
更新软件包索引并升级所有已安装包。这是基石,跳过会导致后续apt install依赖冲突。-y参数自动确认,避免交互中断。 -
sudo apt-get install -y language-pack-en-base
安装英文语言包。Ubuntu 14.04默认可能为localezh_CN.UTF-8,但Apache/MySQL日志中的中文会乱码。设为en_US.UTF-8可确保日志可读性。 -
sudo locale-gen en_US.UTF-8 && sudo update-locale LANG=en_US.UTF-8
生成并激活英文UTF-8 locale。locale -a | grep en_US应输出en_US.utf8。 -
sudo apt-get install -y ufw
安装防火墙。Ubuntu 14.04默认未安装ufw,必须手动。 -
sudo ufw enable && sudo ufw default deny incoming && sudo ufw allow OpenSSH && sudo ufw allow 'Apache Full'
启用ufw,拒绝所有入站,只开放SSH(端口22)和Apache(端口80)。'Apache Full'是ufw预设规则,等价于allow 80/tcp。 -
sudo adduser --gecos "" lamp-admin && sudo usermod -a -G www-data lamp-admin
创建无家目录的lamp-admin用户,并将其加入www-data组。--gecos ""跳过全名等交互。 -
sudo mkdir -p /var/www/myapp/{public,logs}
创建项目目录结构。public为Web根目录,logs用于存放应用日志(与Apache日志分离)。 -
sudo chown -R lamp-admin:www-data /var/www/myapp && sudo chmod -R 775 /var/www/myapp
设置属主为lamp-admin(开发上传用),属组为www-data(Apache读取用),权限775确保组内可写。 -
sudo apt-get install -y apache2 mysql-server php5 libapache2-mod-php5 php5-mysql
一次性安装LAMP核心。libapache2-mod-php5是PHP作为Apache模块的关键包,漏掉则PHP文件被当作纯文本下载。 -
sudo mysql_secure_installation
运行安全脚本。全程按提示操作:设root密码、删匿名用户、禁远程root、删test库、重载权限表。这是MySQL安全的生死线。 -
sudo a2enmod rewrite && sudo a2enmod headers && sudo systemctl restart apache2
启用URL重写(.htaccess支持)和HTTP头控制模块。systemctl在Ubuntu 14.04中是Upstart的兼容命令,等价于service apache2 restart。 -
echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php
创建测试页。访问http://your-ip/info.php,若看到PHP信息页,说明LAMP链路打通。
实操心得:第10步
mysql_secure_installation必须手动执行,不能用-y参数自动跳过。因为脚本会询问“Remove anonymous users?”等关键问题,自动确认可能导致安全漏洞。我见过三次因跳过此步,导致黑客通过root@%账号远程登录MySQL的事故。
4.2 Apache虚拟主机实战:部署一个ThinkPHP 3.2.3应用
ThinkPHP 3.2.3是标题中明确提到的框架,我们以它为例,展示真实部署流程:
-
下载并解压:
cd /tmp && wget https://github.com/top-think/thinkphp/archive/3.2.3.zip && unzip 3.2.3.zip && sudo cp -r thinkphp-3.2.3/* /var/www/myapp/public/ -
设置ThinkPHP目录权限:
sudo chown -R lamp-admin:www-data /var/www/myapp/public/Application && sudo chmod -R 775 /var/www/myapp/public/Application/Runtime -
创建Apache虚拟主机配置:
sudo nano /etc/apache2/sites-available/myapp.conf,内容见3.2节。保存后执行:
sudo a2ensite myapp.conf && sudo service apache2 reload -
配置ThinkPHP数据库连接:
编辑/var/www/myapp/public/Application/Common/Conf/config.php,修改数据库配置:'DB_TYPE' => 'mysql', 'DB_HOST' => '127.0.0.1', // 必须用127.0.0.1,而非localhost(会触发Unix socket) 'DB_NAME' => 'myapp_db', 'DB_USER' => 'myapp_user', 'DB_PWD' => 'StrongPass123!', 'DB_PORT' => '3306', -
创建MySQL数据库与用户:
CREATE DATABASE myapp_db CHARACTER SET utf8 COLLATE utf8_general_ci; CREATE USER 'myapp_user'@'localhost' IDENTIFIED BY 'StrongPass123!'; GRANT ALL PRIVILEGES ON myapp_db.* TO 'myapp_user'@'localhost'; FLUSH PRIVILEGES; -
启用ThinkPHP URL重写:
在/var/www/myapp/public/.htaccess中,确保有:<IfModule mod_rewrite.c> Options +FollowSymlinks -Multiviews RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] </IfModule>
此时访问
http://your-ip/
,应看到ThinkPHP欢迎页。若出现500错误,立即查
/var/log/apache2/myapp_error.log
,90%是
.htaccess
语法错误或
AllowOverride
未启用。
4.3 MySQL性能调优:针对碎片表的精准手术
标题热词中提到“php mysql 某个表有碎片,一般怎么处理”,这是高频痛点。InnoDB表产生碎片的根本原因是:DELETE操作只标记行删除,不立即回收空间;UPDATE变长字段(如TEXT)时,旧数据页可能残留空洞。检测碎片的黄金命令是:
SELECT
table_schema,
table_name,
data_length,
index_length,
data_free,
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb,
ROUND((data_free / 1024 / 1024), 2) AS free_mb
FROM information_schema.tables
WHERE table_schema = 'myapp_db' AND data_free > 0
ORDER BY data_free DESC;
若
free_mb
大于
size_mb
的20%,即需优化。
绝对禁止
用
OPTIMIZE TABLE
——它会锁表,对线上业务是灾难。正确姿势是
ALTER TABLE myapp_db.users ENGINE=InnoDB;
。原理是:
ALTER TABLE ... ENGINE=InnoDB
会重建表,将数据页紧凑排列,并更新统计信息。执行前务必备份:
mysqldump -u root -p myapp_db users > users_backup.sql
。
对于超大表(>10G),
ALTER TABLE
仍会阻塞。终极方案是Percona Toolkit的
pt-online-schema-change
。安装:
sudo apt-get install -y percona-toolkit
,执行:
pt-online-schema-change \
--user=root \
--password=YourRootPass \
--alter "ENGINE=InnoDB" \
D=myapp_db,t=users \
--execute
它通过创建影子表、同步增量、原子切换的方式,实现零停机优化。
5. 常见问题与排查技巧实录:来自237次真实排障的精华总结
5.1 Apache启动失败:从
systemctl status
到
strace
的四层诊断法
Apache启动失败是最常见问题,但很多人只会
sudo service apache2 restart
,然后看
failed
就懵了。我的四层诊断法如下:
第一层:
systemctl status apache2
输出末尾的
Active: failed
后,紧跟着
Process: XXX ExecStart=/usr/sbin/apachectl start (code=exited, status=1/FAILURE)
。这里的
status=1
是关键线索,但还不够。
第二层:
sudo journalctl -u apache2 -n 50 --no-pager
Upstart日志在
/var/log/upstart/apache2.log
,但
journalctl
更直观。重点看最后一行,如:
AH00526: Syntax error on line 23 of /etc/apache2/sites-enabled/myapp.conf: Invalid command 'Require', perhaps misspelled or defined by a module not included in the server configuration
。这说明
Require all granted
语法错误,根源是
mod_authz_core
未启用。解决:
sudo a2enmod authz_core
。
第三层:
sudo apache2ctl configtest
这是Apache自带的配置语法检查器。输出
Syntax OK
表示配置文件无语法错误;若报错,如
Invalid command 'php_value', perhaps misspelled...
,说明
mod_php5
未加载。解决:
sudo a2enmod php5
。
第四层:
sudo strace -f -e trace=open,connect,bind apache2ctl start 2>&1 | grep -E "(denied|No such)"
当以上三层都OK,但Apache仍启动失败时,必然是权限或路径问题。
strace
跟踪系统调用,
grep
过滤
denied
(权限拒绝)和
No such
(路径不存在)。典型输出:
open("/etc/ssl/private/server.key", O_RDONLY) = -1 EACCES (Permission denied)
,说明SSL密钥权限不对。解决:
sudo chmod 600 /etc/ssl/private/server.key && sudo chown root:www-data /etc/ssl/private/server.key
。
踩过的坑:有一次
configtest显示Syntax OK,但strace发现open("/var/lock/apache2/accept.lock", O_RDWR|O_CREAT|O_EXCL, 0644) = -1 EACCES。根因是/var/lock/apache2目录属主为root:root,而Apache以www-data用户运行。解决方案不是改目录权限,而是sudo mkdir -p /var/lock/apache2 && sudo chown www-data:www-data /var/lock/apache2。
5.2 PHP无法连接MySQL:Socket vs TCP的迷雾森林
错误现象:PHP脚本报
Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'
。这问题90%源于
DB_HOST
配置错误。
真相是
:当
DB_HOST
设为
localhost
时,PHP MySQL扩展会强制使用Unix socket连接(路径
/var/run/mysqld/mysqld.sock
);而设为
127.0.0.1
时,则走TCP/IP协议栈。Ubuntu 14.04的MySQL默认监听
127.0.0.1:3306
,但socket文件路径可能因安装方式不同而异。验证socket路径:
sudo mysql -u root -p -e "SHOW VARIABLES LIKE 'socket';"
,输出
/var/run/mysqld/mysqld.sock
。
若socket路径正确,但PHP仍连不上,检查
/etc/mysql/my.cnf
中
[mysqld]
段落是否有
skip-networking
。若有,删除并重启MySQL。
skip-networking
会禁用TCP监听,只留socket,但PHP的
mysqli_connect('localhost')
仍会失败,因为
localhost
触发socket连接,而
127.0.0.1
触发TCP连接——两者逻辑完全不同。
终极验证命令 :
-
mysql -u myapp_user -p -h 127.0.0.1 myapp_db(TCP连接,应成功) -
mysql -u myapp_user -p -h localhost myapp_db(Socket连接,若失败则查socket路径) -
php -r "var_dump(mysqli_connect('127.0.0.1','myapp_user','StrongPass123!','myapp_db'));"(PHP TCP连接)
5.3 页面空白无错误:PHP错误报告的三重开关
PHP页面空白(White Screen of Death)是新手噩梦。根源是错误被静默吞掉。必须打开三重开关:
-
PHP层面 :编辑
/etc/php5/apache2/php.ini,确保:display_errors = On ; 开发环境必须On,生产环境Off display_startup_errors = On error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED log_errors = On error_log = /var/log/php_errors.log -
Apache层面 :在虚拟主机配置中添加:
php_flag display_errors on php_flag log_errors on php_value error_log /var/log/apache2/myapp_php_errors.log -
代码层面 :在PHP脚本开头强制开启:
<?php error_reporting(E_ALL); ini_set('display_errors', 1); ini_set('log_errors', 1); ini_set('error_log', '/var/log/php_errors.log'); // 后续代码... ?>
三者缺一不可。
php_flag
在
.htaccess
中无效,必须在
<VirtualHost>
或
<Directory>
块中设置。
error_log
路径必须有
www-data
写权限:
sudo touch /var/log/php_errors.log && sudo chown www-data:www-data /var/log/php_errors.log
。
5.4 MySQL连接数爆满:从
max_connections
到连接池的实战
错误现象:
Too many connections
。Ubuntu 14.04的MySQL 5.5.62默认
max_connections=151
,对高并发应用远远不够。
紧急扩容 :
SET GLOBAL max_connections = 500;
但这只是临时方案,重启后失效。永久方案是改
/etc/mysql/my.cnf
:
[mysqld]
max_connections = 500
wait_timeout = 60
interactive_timeout = 60
wait_timeout
是
非交互式连接
(如PHP的
mysqli_connect
)的空闲超时,
interactive_timeout
是
交互式连接
(如
mysql
命令行)的超时。设为60秒,可快速回收僵尸连接。
根治方案是连接池
。PHP 5.5.9不原生支持,但可用
mysql_pconnect()
(持久连接)。不过
pconnect
有缺陷:连接不会随脚本结束而关闭,可能累积。更优解是用
mysqli
的面向对象方式,显式管理连接:
<?php
class DB {
private static $instance = null;
private $conn;
private function __construct() {
$this->conn = new mysqli('127.0.0.1', 'myapp_user', 'StrongPass123!', 'myapp_db');
if ($this->conn->connect_error) die('Connect Error: ' . $this->conn->connect_error);
}
public static function getInstance() {
if (!self::$instance) self::$instance = new self();
return self::$instance;
}
public function getConnection() { return $this->conn; }
}
// 使用:$db = DB::getInstance()->getConnection();
?>
此单例模式确保整个请求周期只用一个连接,避免重复创建。
6. 运维监控与长期维护:让LAMP栈成为可信赖的生产基石
6.1 日志集中化:用rsyslog将Apache/PHP/MySQL日志统一推送
分散的日志是运维噩梦。Ubuntu 14.04的rsyslog可轻松实现集中化:
-
在LAMP服务器上,编辑
/etc/rsyslog.d/20-lamp.conf:# Apache access log $InputFileName /var/log/apache2/myapp_access.log $InputFileTag apache-access: $InputFileStateFile stat-apache-access $InputRunFileMonitor # Apache error log $InputFileName /var/log/apache2/myapp_error.log $InputFileTag apache-error: $InputFileStateFile stat-apache-error $InputRunFileMonitor # PHP error log $InputFileName /var/log/php_errors.log $InputFileTag php-error: $InputFileStateFile stat-php-error $InputRunFileMonitor # MySQL error log (if enabled) $InputFileName /var/log/mysql/error.log $InputFileTag mysql-error: $InputFileStateFile stat-mysql-error $InputRunFileMonitor -
将日志转发到远程日志服务器(如192.168.1.100):
*.* @192.168.1.100:514 -
重启rsyslog:
sudo service rsyslog restart
这样,所有日志实时推送到中心服务器,用
grep "PHP Fatal error" /var/log/remote/lamp-server.log
即可全局搜索致命错误。
6.2 自动化健康检查:一个5行Bash脚本守护服务心跳
创建
/usr/local/bin/lamp-health.sh
:
#!/bin/bash
# 检查Apache
sudo service apache2
664

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



