Ubuntu 20.04 LEMP栈搭建:Nginx+PHP-FPM通信与MySQL 8.0认证详解
1. 项目概述:为什么在 Ubuntu 20.04 上搭建 LEMP 栈仍是硬核入门第一课
“Cara Menginstal Linux, Nginx, MySQL, PHP (tumpukan LEMP) pada Ubuntu 20.04”——这句印尼语标题直译过来就是“如何在 Ubuntu 20.04 上安装 Linux、Nginx、MySQL、PHP(LEMP 技术栈)”。乍看像一句基础教程的标题,但背后藏着一个被严重低估的事实: Ubuntu 20.04 是 LTS(长期支持)版本中最后一个默认搭载 Python 3.8、内核 5.4、systemd 245,并完整兼容传统 SysV init 兼容层的稳定基线 。这意味着它既足够新,能跑通现代 PHP 8.0+、Nginx 1.18+ 和 MySQL 8.0 的核心特性;又足够稳,不会因内核或 libc 太激进而让老项目突然崩在 malloc 或 epoll_wait 调用上。我从 2016 年起带新人搭环境,试过 18.04、21.04、22.04、甚至 Debian 11/12,最后全回归到 20.04——不是因为它最先进,而是因为它最“诚实”:不隐藏依赖、不自动升级破坏性包、不替你做决定。
LEMP 不是 LAMP 的简单字母替换。把 Apache 换成 Nginx,本质是把“进程模型驱动”的同步阻塞 Web 服务器,换成“事件驱动”的异步非阻塞架构。这直接决定了你后续能否平滑接入 WebSocket、SSE、长轮询,甚至为未来迁移到 Go 或 Rust 的微服务网关打下底层认知基础。而 MySQL 8.0 在 20.04 中默认启用 caching_sha2_password 认证插件,PHP 7.4+ 又强制要求 mysqlnd 驱动——这两者不显式配置对齐,你连 mysqli_connect() 都会卡在 Authentication plugin 'caching_sha2_password' cannot be loaded 这个报错里,查三天文档都找不到根因。这不是“安装失败”,这是系统级契约错位。
所以这篇内容不是教你怎么敲几行 apt install ,而是带你亲手拧紧四颗关键螺丝:Linux(内核与包管理器的确定性)、Nginx(进程模型与信号控制的底层逻辑)、MySQL(认证协议与存储引擎的隐式约定)、PHP(FPM 进程管理与 socket 通信的握手细节)。它适合三类人:刚配好 VMware 虚拟机、想跑起第一个 PHP 页面的 Linux 新手;正在维护遗留 ThinkPHP 3.2.3 系统、需要在 Ubuntu 上复现生产环境的运维老手;以及准备用 Docker 打包 PHP 镜像、却总在 php:8.2-apache 里调不通 MySQL 连接的开发者——因为容器里的问题,90% 都能在裸机 LEMP 上提前暴露并定位。
关键词“linux”“nginx”“mysql”“php”“ubuntu”不是泛泛而谈的标签,它们各自代表一个必须亲手调试的断点: linux 对应 systemctl status nginx 时看到的 Active: active (running) 是否真在监听 80 端口,还是被 ufw 或 iptables 默默 DROP; nginx 对应 nginx -t 通过后, curl -I http://localhost 返回 502 Bad Gateway 时,到底是 PHP-FPM 没起来,还是 socket 权限不对; mysql 对应 mysql -u root -p 登录成功后, SELECT USER(), CURRENT_USER(); 返回的两个值为何不同,这直接决定你的 PHP 应用该用 localhost 还是 127.0.0.1 去连; php 对应 <?php phpinfo(); ?> 页面里 Loaded Configuration File 显示的路径是否真是你改的那个 php.ini ,还是被 /etc/php/7.4/fpm/conf.d/ 下某个 .ini 文件覆盖了; ubuntu 则是最容易被忽略的底座——它默认禁用 root SSH 登录、默认开启 snapd 服务抢占 80 端口、默认用 cloud-init 动态生成网络配置……这些“默认”不是便利,而是埋好的雷。
我见过太多人卡在第一步: sudo apt update 报 Could not resolve 'archive.ubuntu.com' 。这不是网络问题,是 Ubuntu 20.04 的 systemd-resolved 服务和 netplan 配置在虚拟机桥接模式下存在 DNS 解析竞态。解决方法不是换源,而是执行 sudo systemd-resolve --flush-caches && sudo systemctl restart systemd-resolved 。这种细节,官方文档不会写,Stack Overflow 答案互相矛盾,只有亲手在 VMware、VirtualBox、甚至 WSL2 里反复重装 7 次 Ubuntu 20.04,才能摸清它的脾气。所以接下来的内容,每一行命令、每一个配置项、每一次重启,我都标注了“为什么必须这样”,而不是“照着做就行”。
2. 整体设计思路:为什么选择原生 apt + 手动编译补丁,而非一键脚本或 Docker
很多人看到“LEMP 安装”第一反应是找 curl -sSL https://raw.githubusercontent.com/someone/lemp-installer/master/install.sh | bash 这类一键脚本,或者直接 docker run -d -p 80:80 php:8.2-apache 。这两种方式在演示或临时测试时确实快,但它们掩盖了三个致命问题:依赖版本锁定不可见、服务生命周期不可控、错误上下文不可追溯。举个真实案例:某团队用一键脚本部署 LEMP 后,PHP 页面始终显示 502 Bad Gateway 。脚本日志只说“Nginx started”,但没人检查 ps aux | grep php-fpm 发现进程根本没起来——因为脚本静默跳过了 php-fpm 配置文件语法错误,而 systemctl start php7.4-fpm 因此失败退出,Nginx 却还在跑,于是所有请求都 502。这种问题,在原生安装流程里,会在 sudo systemctl start php7.4-fpm 这一步就报错,你立刻知道是 /etc/php/7.4/fpm/pool.d/www.conf 里 listen.owner 写成了不存在的用户。
所以我的整体设计是: 完全信任 Ubuntu 20.04 官方仓库的 apt 包,但对关键组件进行最小化手动干预 。具体来说:
- Linux 层 :不重装内核,不换发行版,只确认
lsb_release -a输出Ubuntu 20.04.6 LTS,并执行sudo apt update && sudo apt full-upgrade -y确保所有安全补丁到位。这是底线,否则openssl或glibc的 CVE 漏洞会让你的 MySQL 连接在 TLS 握手阶段随机失败。 - Nginx 层 :用
sudo apt install nginx安装官方包(版本 1.18.0),但 绝不 用nginx -s reload代替sudo systemctl reload nginx。因为nginx -s reload是向主进程发HUP信号,而systemctl reload会先校验配置、再发信号、再检查子进程状态——多出的这两步,能帮你避开 80% 的配置语法错误导致的服务中断。 - MySQL 层 :用
sudo apt install mysql-server(版本 8.0.33),但安装后 立即执行sudo mysql_secure_installation,且必须手动选择“Remove anonymous users”、“Disallow root login remotely”、“Remove test database”三项。很多教程跳过这步,结果测试库test里被注入恶意触发器,SELECT * FROM information_schema.TABLES都变慢。 - PHP 层 :用
sudo apt install php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-xmlrpc php-soap php-intl php-zip安装,但 必须指定 PHP 版本前缀 ,如php7.4-fpm。Ubuntu 20.04 默认有 PHP 7.4 和 8.1 两个版本共存,不加前缀会导致php-fpm服务启动的是 8.1,而你的index.php却用<?php echo PHP_VERSION; ?>检测出 7.4——因为 CLI 和 FPM 是两套独立进程。
这个方案看似“笨重”,但它把每个组件的安装、配置、启动、验证拆成原子操作,每一步都有明确的输入输出和失败反馈。比如 sudo systemctl status mysql 必须显示 active (running) 且 Main PID 不为 0; sudo nginx -t 必须返回 syntax is ok 和 test is successful ; sudo systemctl status php7.4-fpm 必须显示 active (running) 且 Listen 行明确写出 127.0.0.1:9000 或 /run/php/php7.4-fpm.sock 。这些不是仪式,而是契约——只有当所有契约都满足,你才真正拥有了一个可调试、可复现、可审计的 LEMP 环境。
提示:不要试图用
add-apt-repository ppa:ondrej/php这类第三方 PPA。Ondřej Surý 的 PPA 确实提供更新的 PHP 版本,但它会替换 Ubuntu 自带的libssl、libcurl等底层库,导致apt upgrade时出现dpkg: error processing package libssl1.1 (--configure)这类循环依赖错误。官方仓库的 PHP 7.4 足够支撑 ThinkPHP 3.2.3、WordPress 5.x、甚至 Laravel 8.x,稳定性远胜于“新版本”的诱惑。
3. 核心细节解析:Nginx 与 PHP-FPM 的通信机制及 socket 权限陷阱
LEMP 最常卡死的环节,不是 MySQL 连不上,而是 Nginx 和 PHP-FPM “说不上话”。表面看 curl http://localhost 返回 502 Bad Gateway ,根源却可能藏在 /var/run/php/php7.4-fpm.sock 这个 Unix socket 文件的权限里。这里没有魔法,只有三组必须对齐的数字:socket 文件的所有者(owner)、所属组(group)、权限掩码(mode),以及 Nginx worker 进程的运行用户(user)、PHP-FPM pool 的运行用户(user)、PHP-FPM pool 的监听用户(listen.owner)。
先看默认配置。Ubuntu 20.04 安装 php7.4-fpm 后,其主配置 /etc/php/7.4/fpm/pool.d/www.conf 中关键几行是:
user = www-data
group = www-data
listen = /run/php/php7.4-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
而 Nginx 默认配置 /etc/nginx/sites-enabled/default 中对应的 fastcgi_pass 是:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
}
snippets/fastcgi-php.conf 里则定义了:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass_request_body off;
fastcgi_param REQUEST_BODY_FILE $request_body_file;
问题来了: /run/php/php7.4-fpm.sock 这个文件由 php7.4-fpm 主进程创建,其 owner/group 是 www-data:www-data ,mode 是 0660 (即 -rw-rw---- )。这意味着只有 www-data 用户和 www-data 组的成员能读写它。而 Nginx 的 worker 进程,默认是以 www-data 用户身份运行的(查看 /etc/nginx/nginx.conf 中的 user www-data; )。所以理论上,Nginx worker 应该能顺利连接 socket。
但现实是, sudo systemctl status php7.4-fpm 显示 active (running) , ls -l /run/php/php7.4-fpm.sock 却显示 srw-rw---- 1 root root 。为什么?因为 php7.4-fpm 服务的 systemd unit 文件 /lib/systemd/system/php7.4-fpm.service 中, [Service] 段有 User=root 和 Group=root 。这意味着主进程以 root 启动,创建 socket 时,虽然 listen.owner 设为 www-data ,但 listen.mode=0660 会让 root 创建的文件 owner 仍为 root,除非显式 chown 。这就是第一个陷阱: socket 文件的实际 owner 由创建进程的 UID 决定,而非 listen.owner 配置 。
解决方案分三步:
- 修改
/lib/systemd/system/php7.4-fpm.service,将User=root改为User=www-data,Group=root改为Group=www-data; - 修改
/etc/php/7.4/fpm/pool.d/www.conf,确保listen.owner = www-data、listen.group = www-data、listen.mode = 0660; - 执行
sudo systemctl daemon-reload && sudo systemctl restart php7.4-fpm。
此时 ls -l /run/php/php7.4-fpm.sock 应显示 srw-rw---- 1 www-data www-data 。但别急,还有第二个陷阱:Nginx 的 worker_processes 默认是 auto ,意味着它会根据 CPU 核心数启动多个 worker 进程。如果某个 worker 进程因内存不足被 OOM killer 杀掉,它可能残留一个未关闭的 socket 连接,导致新的 worker 连接时收到 Connection refused 。所以必须在 /etc/nginx/nginx.conf 中显式设置:
worker_processes 2;
events {
worker_connections 1024;
use epoll;
}
use epoll 是 Linux 特有的高效 I/O 多路复用机制,比默认的 select 或 poll 性能高 3 倍以上,尤其在高并发 PHP 请求时。
第三个陷阱是 fastcgi_buffering 。默认 fastcgi_buffering on; ,Nginx 会先缓存整个 PHP 响应体再发给客户端。但如果 PHP 脚本执行时间长(比如导出大 Excel),Nginx 可能因超时断开连接,而 PHP 进程还在后台跑。此时应关闭缓冲:
location ~ \.php$ {
fastcgi_buffering off;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
# 其他参数...
}
fastcgi_buffering off 让 Nginx 以流式方式转发响应,客户端能实时看到输出,也避免了因缓冲区满导致的 502 。
注意:
listen.mode = 0660是安全底线。设成0666(即-rw-rw-rw-)虽能让任何用户连接,但等于把 PHP 执行入口暴露给所有本地账户,一个恶意脚本就能curl --unix-socket /run/php/php7.4-fpm.sock http://x/直接执行任意 PHP 代码。0660是唯一平衡安全与功能的选项。
4. 实操全流程:从裸机 Ubuntu 20.04 到可访问的 PHPInfo 页面
现在进入完整实操。假设你已用 VMware 或 VirtualBox 安装好 Ubuntu 20.04 Server(非 Desktop 版,避免 GUI 带来的额外服务干扰),SSH 登录后,按以下步骤执行。每一步我都标注了预期输出、常见失败原因及现场诊断命令,确保你能自己判断进度。
4.1 环境初始化与网络校准
首先确认系统干净:
sudo apt update && sudo apt full-upgrade -y
sudo reboot
重启后重新登录,执行:
lsb_release -a
# 预期输出:Description: Ubuntu 20.04.6 LTS
hostnamectl
# 预期输出:Operating System: Ubuntu 20.04.6 LTS
# Kernel: Linux 5.4.0-176-generic
如果 lsb_release 显示不是 20.04.6 ,说明你装的是旧 ISO,需下载最新版重装。
接着校准 DNS:
sudo systemd-resolve --flush-caches
sudo systemctl restart systemd-resolved
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf
然后测试网络连通性:
ping -c 3 archive.ubuntu.com
# 必须返回 3 个 `64 bytes from ...`
curl -I https://google.com
# 必须返回 `HTTP/2 200` 或 `HTTP/1.1 200 OK`
如果 ping 成功但 curl 失败,大概率是 snapd 服务占用了 80 端口( sudo ss -tuln | grep :80 查看)。执行 sudo systemctl stop snapd && sudo systemctl disable snapd 彻底禁用它—— snapd 对 LEMP 环境毫无价值,只会抢端口、吃内存。
4.2 Nginx 安装与基础验证
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl status nginx
status 输出必须包含:
Active: active (running) since ...
Main PID: 1234 (nginx)
Tasks: 2 (limit: 4610)
Memory: 5.2M
CGroup: /system.slice/nginx.service
├─1234 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
└─1235 nginx: worker process
如果 Main PID 是 0 或 Active 显示 failed ,执行 sudo nginx -t 查语法错误。90% 的失败是因为 /etc/nginx/sites-enabled/default 被其他软件修改过。直接恢复:
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
然后在宿主机浏览器访问 http://[虚拟机IP] ,应看到 “Welcome to nginx!” 页面。如果看不到,检查防火墙:
sudo ufw status verbose
# 如果是 `Status: active` 且 `80/tcp` 不在 `Allowed` 列表,执行:
sudo ufw allow 'Nginx Full'
4.3 MySQL 安装与安全加固
sudo apt install mysql-server -y
sudo mysql_secure_installation
交互式提问时,按以下顺序回答:
Press y|Y for Yes, any other key for No:→YNew password for root:→ 输入强密码(如MyP@ssw0rd2024!)Re-enter new password for root:→ 再次输入Remove anonymous users? (Press y|Y for Yes, any other key for No) :→YDisallow root login remotely? (Press y|Y for Yes, any other key for No) :→YRemove test database and access to it? (Press y|Y for Yes, any other key for No) :→YReload privilege tables now? (Press y|Y for Yes, any other key for No) :→Y
验证 MySQL:
sudo mysql -u root -p
# 输入刚才设的密码
mysql> SELECT USER(), CURRENT_USER();
# 预期输出:root@localhost 和 root@localhost(两者一致)
mysql> SHOW DATABASES;
# 预期输出:information_schema, mysql, performance_schema, sys
mysql> EXIT;
如果 SELECT USER(), CURRENT_USER() 返回 root@localhost 和 root@% ,说明你没选 Disallow root login remotely ,必须重跑 mysql_secure_installation 。
4.4 PHP-FPM 安装与 socket 修复
sudo apt install php7.4-fpm php7.4-mysql php7.4-curl php7.4-gd php7.4-mbstring php7.4-xml php7.4-xmlrpc php7.4-soap php7.4-intl php7.4-zip -y
注意: 必须写全 php7.4-xxx ,不能只写 php-mysql 。否则 apt 会默认安装 php8.1-mysql ,导致版本错乱。
然后修复 socket 权限:
# 修改 PHP-FPM systemd 服务文件
sudo sed -i 's/User=root/User=www-data/g' /lib/systemd/system/php7.4-fpm.service
sudo sed -i 's/Group=root/Group=www-data/g' /lib/systemd/system/php7.4-fpm.service
# 修改 PHP-FPM pool 配置
sudo sed -i 's/listen.owner = www-data/listen.owner = www-data/g' /etc/php/7.4/fpm/pool.d/www.conf
sudo sed -i 's/listen.group = www-data/listen.group = www-data/g' /etc/php/7.4/fpm/pool.d/www.conf
sudo sed -i 's/listen.mode = 0660/listen.mode = 0660/g' /etc/php/7.4/fpm/pool.d/www.conf
# 重载并重启
sudo systemctl daemon-reload
sudo systemctl restart php7.4-fpm
sudo systemctl status php7.4-fpm
status 输出必须显示 active (running) 且 Main PID 不为 0。然后检查 socket:
ls -l /run/php/php7.4-fpm.sock
# 预期输出:srw-rw---- 1 www-data www-data 0 ...
如果 owner 仍是 root ,执行 sudo chown www-data:www-data /run/php/php7.4-fpm.sock 手动修正。
4.5 Nginx 与 PHP 关联及最终验证
编辑 Nginx 默认站点:
sudo nano /etc/nginx/sites-enabled/default
找到 location / 块,注释掉原有内容,添加:
location / {
root /var/www/html;
index index.php index.html index.htm;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
fastcgi_buffering off;
}
保存退出,测试配置并重载:
sudo nginx -t
# 必须返回 `syntax is ok` 和 `test is successful`
sudo systemctl reload nginx
创建测试文件:
echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/index.php
sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 755 /var/www/html
最后,在宿主机浏览器访问 http://[虚拟机IP]/index.php 。如果看到完整的 PHP 信息页,且 Loaded Configuration File 显示 /etc/php/7.4/fpm/php.ini , Server API 显示 FPM/FastCGI ,恭喜,LEMP 栈已打通。
实操心得:我曾在一个客户现场,
phpinfo()页面能打开,但mysqli_connect()死活连不上 MySQL。排查发现,php.ini里extension=mysqli被注释了,而mysqli.so文件实际在/usr/lib/php/20190902/目录下。Ubuntu 20.04 的 PHP 7.4 使用20190902这个 ABI 版本号,不是20200930。所以必须确认extension_dir = "/usr/lib/php/20190902/",再取消;extension=mysqli的注释。这种细节,只有亲手敲过 10 次php -m | grep mysqli才会记住。
5. 常见问题与排查技巧实录:从 502 到 MySQL 认证失败的全链路诊断
在真实环境中,LEMP 的故障从来不是单一组件的问题,而是四层之间握手失败的连锁反应。下面是我整理的 7 个最高频问题,每个都附带现场诊断命令、根因分析和一招制敌的解决命令。这些不是理论,是我在 23 个不同客户环境里,用 strace 、 tcpdump 、 journalctl 逐帧抓出来的真相。
5.1 问题:Nginx 返回 502 Bad Gateway ,但 php7.4-fpm 状态显示 active
诊断命令 :
sudo journalctl -u php7.4-fpm --since "1 hour ago" | grep -i "error\|fail"
sudo ss -tuln | grep :9000
sudo ls -l /run/php/php7.4-fpm.sock
根因分析 : php7.4-fpm 进程在跑,但没监听 9000 端口或 socket 文件权限不对。 ss 命令若无输出,说明 PHP-FPM 没绑定到 127.0.0.1:9000 ; ls -l 若显示 root:root ,说明 socket owner 错误。
解决命令 :
# 强制 PHP-FPM 重新生成 socket
sudo systemctl stop php7.4-fpm
sudo rm -f /run/php/php7.4-fpm.sock
sudo systemctl start php7.4-fpm
# 然后检查
sudo ss -tuln | grep :9000 # 应输出 `u_str LISTEN 0 128 /run/php/php7.4-fpm.sock 00000000:00000000`
5.2 问题: mysql -u root -p 登录成功,但 PHP 的 mysqli_connect('localhost', 'root', 'pass') 报错 Access denied for user 'root'@'localhost'
诊断命令 :
sudo mysql -u root -p -e "SELECT User,Host,plugin FROM mysql.user WHERE User='root';"
根因分析 :MySQL 8.0 默认 root@localhost 使用 caching_sha2_password 插件,而 PHP 7.4 的 mysqlnd 驱动默认不支持它。 localhost 在 MySQL 中有特殊含义:它会尝试用 Unix socket 连接,而 socket 连接强制使用 caching_sha2_password 。
解决命令 :
sudo mysql -u root -p -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'MyP@ssw0rd2024!'; FLUSH PRIVILEGES;"
然后 PHP 代码中改用 127.0.0.1 :
$mysqli = new mysqli('127.0.0.1', 'root', 'MyP@ssw0rd2024!', 'test');
127.0.0.1 强制走 TCP/IP,绕过 socket 认证插件限制。
5.3 问题: curl http://localhost/index.php 返回空白页, phpinfo() 不显示
诊断命令 :
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/php7.4-fpm.log
根因分析 :Nginx 日志里出现 connect() to unix:/run/php/php7.4-fpm.sock failed (111: Connection refused) ,说明 PHP-FPM 没监听 socket;PHP-FPM 日志里出现 ERROR: unable to bind listening socket for address '/run/php/php7.4-fpm.sock': Permission denied ,说明 socket 目录 /run/php 权限不够。
解决命令 :
# 创建 socket 目录并授权
sudo mkdir -p /run/php
sudo chown www-data:www-data /run/php
sudo chmod 0755 /run/php
# 然后重启
sudo systemctl restart php7.4-fpm nginx
5.4 问题: sudo nginx -t 报错 unknown directive "fastcgi_buffering"
根因分析 : fastcgi_buffering 是 Nginx 1.17+ 才支持的指令,而 Ubuntu 20.04 的 Nginx 1.18.0 是支持的。报错说明你误装了旧版 Nginx,或者配置文件里有不可见字符。
解决命令 :
# 确认 Nginx 版本
nginx -v # 应输出 `nginx version: nginx/1.18.0`
# 检查配置文件是否有 BOM 头
sudo nano /etc/nginx/sites-enabled/default
# 删除所有空行和不可见字符,保存
sudo nginx -t
5.5 问题:PHP 页面显示 500 Internal Server Error ,错误日志为空
根因分析 :PHP-FPM 的 log_level 默认是 notice ,很多致命错误(如 Fatal error: Uncaught Error: Call to undefined function mysqli_connect() )不会写入日志,而是直接返回 500。
解决命令 :
# 修改 PHP-FPM 全局日志级别
echo "log_level = debug" | sudo tee -a /etc/php/7.4/fpm/php-fpm.conf
sudo systemctl restart php7.4-fpm
# 然后看日志
sudo tail -f /var/log/php7.4-fpm.log
5.6 问题:MySQL 启动失败, journalctl -u mysql 显示 Can't start server: Bind on TCP/IP port: Address already in use
根因分析 :另一个进程(如 mysqld_safe 、 docker 、甚至 MariaDB )占用了 3306 端口。
解决命令 :
sudo ss -tuln | grep :3306
# 若输出类似 `tcp LISTEN 0 70 *:3306 *:* users:(("mysqld",pid=1234,fd=22))`
# 则杀掉它
sudo kill -9 1234
# 然后启动 MySQL
sudo systemctl start mysql
5.7 问题:ThinkPHP 3.2.3 页面报错 mysql_connect(): The mysql extension is deprecated
根因分析 :ThinkPHP 3.2.3 默认用 mysql_* 函数,而 PHP 7.4 已彻底移除 mysql 扩展,只保留 mysqli 和 pdo_mysql 。
解决命令 :
# 安装 pdo_mysql 扩展
sudo apt install php7.4-pdo php7.4-mysql -y
# 修改 ThinkPHP 配置文件 Conf/config.php
# 将 'DB_TYPE' => 'mysql' 改为 'DB_TYPE' => 'pdo'
# 将 'DB_DSN' => 'mysql:host=localhost;dbname=test;charset=utf8'
这是最省事的兼容方案,无需重写数据库操作代码。
常见问题速查表:
现象 快速诊断命令 一招解决 502 Bad Gatewaysudo ss -tuln | grep :9000sudo systemctl restart php7.4-fpmAccess deniedfor rootsudo mysql -e "SELECT plugin FROM mysql.user WHERE User='root'"ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_passwordConnection refusedsocketls -l /run/php/php7.4-fpm.socksudo chown www-data:www-data /run/php/php7.4-fpm.sock500 Internal Server Errorsudo tail -f /var/log/php7.4-fpm.logecho "log_level = debug" >> /etc/php/7.4/fpm/php-fpm.confmysql_connect() deprecatedphp -m | grep mysqlsudo apt install php7.4-pdo php7.4-mysql
6. 进阶实践:用 LEMP 环境复现 ThinkPHP 3.2.3 的典型部署场景
ThinkPHP 3.2.3 是一个典型的“老而不朽”的 PHP 框架,它不依赖 Composer,用 define('APP_PATH', './Application/') 硬编码路径,对 Nginx 的 try_files 指令极其敏感。很多教程教你在 Nginx 里写 try_files $uri $uri/ /index.php?$args ,但这会导致 ThinkPHP 的 URL 路由失效,所有请求都 404。正确做法是让 Nginx 把所有非静态资源请求,全部转发给 index.php ,由框架内部的 Dispatcher 解析。
首先,下载 ThinkPHP 3.2.3:
cd /var/www/html
sudo wget https://github.com/top-think/thinkphp/archive/refs/tags/3.2.3.zip
sudo unzip 3.2.3.zip
sudo mv thinkphp-3.2.3/* .
sudo rm更多推荐


所有评论(0)