基于 LNMP 架构部署 CRMEB 电商系统
LNMP 企业架构简介
LNMP 是一种非常成熟、高效的 Web 服务器架构组合,用于搭建高性能、稳定的动态网站环境。
它由以下四个开源组件组成:
- Linux:操作系统(如 RHEL、CentOS、Ubuntu,Debian)
- Nginx:高性能 Web 服务器 / 反向代理服务器
- MySQL/MariaDB:关系型数据库管理系统
- PHP/Python:脚本语言(用于动态内容生成)

扩展
在企业级开发市场中,大约在2019年以后,用Java(阿里、京东等)和Go(字节、小米等)的越来越多,PHP在中高级开发市场中用的较少。
学习Nginx,以LNMP引入,可以简化很多开发上的知识,对初学者非常友好。
运维二十年演变发展史
项目开发流程
公司老板和产品经理根据市场调查,决定开发的一整套互联网产品。
互动社交+电商+用户论坛(BBS)
1、产品决策(老板+产品+UI设计)
2、代码开发(程序开发人员[前端开发[客户端页面或者APP]和后端开发[java php python node ruby])
3、测试工作(测试人员)
4、部署上线(运维人员)
人员分配:
Developers 开发 : Operators 运维 = 8 : 1
项目周期:
技术人员在项目开发周期大概2-4个月(中小),大型项目开发周期大概6个月-8个月左右。
1 产品 + 1UI + 1 前端 + 6 个后端 + 1 个测试 + 1 运维团队(网络 + 运维 + 数据库) => 10人
10人 * 3月 = 30人月
10人 * 6月 = 60人月
10人 * 12月 = 120人月
扩展
人月(Man-Month) 是项目管理中用于衡量工作量的常用单位,表示一个人在一个月内完成的工作量。它本质上是 “人力” 与 “时间” 的乘积,用于估算项目规模、规划资源或评估进度。
注意,这只是理论。与土木工程不同,软件工程的从业者更新换代很快。
一般来说,一个拥有5年实际经验的开发和一个2年经验的开发相差很大的。将来大家如果走上项目管理,记得不能单单使用人月来估算项目投入,还需要考虑每个人员的软件能力成熟度。
企业架构分布式集群解决方案
集群:多台服务器在一起做同样的事 。
分布式 :多台服务器在一起做不同的事 。(同一个事情进行了分解)
怎样理解集群与分布式?
讲个故事:
小饭店原来只有一个厨师,切菜洗菜备料炒菜全干。后来客人多了,厨房一个厨师忙不过来,又请了一个厨师,两个厨师都能炒一样的菜,这两个厨师的关系是集群。
为了让厨师专心炒菜,把菜做到极致,又请了个配菜师负责切菜,备菜,备料;厨师和配菜师的关系是分布式。
一个配菜师也忙不过来了,又请了一个配菜师,两个配菜师关系是集群。
| 维度 | 集群 | 分布式 |
|---|---|---|
| 任务分配 | 执行相同任务 | 执行不同任务 |
| 任务类型 | 复制、冗余备份 | 模块拆分 |
| 典型场景 | 数据库集群 | 微服务架构(先作为了解即可) |
企业架构图示
实现负载均衡LB、高可用HA、数据库主从复制M-S、读写分离R-W、缓存中间件[Memcached、Redis]、NoSQL[MongoDB]...

企业级 Web 架构
☆ ASP 架构:IIS 服务器软件
ASP(Active Server Pages,动态服务器页面)是微软推出的早期服务器端脚本技术(后续发展为 ASP.NET),用于生成动态网页内容(如用户登录、数据库查询结果展示)。
默认服务器软件:IIS(Internet Information Services)——微软 Windows 操作系统内置的 Web 服务器,深度集成于 Windows Server 环境,专为 ASP/ASP.NET 设计。
☆ LNMP 架构
LNMP = Linux + Nginx + MySQL + PHP(独立软件,占用9000端口)
| 组合 | Web 服务器 | 核心优势 | 典型场景 |
|---|---|---|---|
| LAMP | Apache | 历史悠久、配置简单(通过 .htaccess灵活控制)、模块化设计(如 mod_rewrite支持 URL 重写) | 早期 PHP 网站(如 2010 年前的企业官网)、依赖 Apache 特定功能的场景(如 .htaccess 规则) |
| LNMP | Nginx | 高并发、性能强(单机能处理数万并发连接)、低内存占用(适合云服务器)、反向代理灵活(可同时代理 PHP、静态资源、API 等) | 现代 PHP 应用(如电商网站、博客系统)、需要高并发或混合服务(如 Nginx 同时托管静态文件 + PHP + Node.js) |

Nginx:接收用户请求,请求处理后返回结果给用户
注意:Nginx本身只能处理静态文件(.htm/.html、css、javascript),无法处理动态文件(.php、.py、.java),动态文件Nginx会通过反向代理
PHP程序(底层进程:PHP-FPM):专门用于处理.php动态文件
MySQL:负责整个项目中数据的存储(用户数据、产品数据、订单数据、发货数据等等)
☆ JSP 架构:Nginx + Tomcat 组合
JSP(Java Server Pages)是基于 Java 的服务器端技术(如企业级 ERP、金融系统常使用 JSP),其运行依赖 Java 容器(负责解析 JSP 代码并转换为 Servlet 执行)。
由于 Nginx 本身不支持直接解析 JSP,因此需要与 Tomcat(Java 应用服务器)配合。
形成 Nginx(前端代理) + Tomcat(后端 Java 容器) 的架构。
业务背景
年份:2014-2016(互联网蓬勃发展)
发布产品类型:在线电商平台(CRMEB)
用户数量: 500左右(20% ~ 70%)
PV : 1000-3000
DAU: 100-300(日活,每天的独立访客数量)
-
2020年
-
- 注册用户数:8,000–12,000
- DAU(日活):600–1,000
- PV(日页面浏览):4,000–8,000
- 日活占用户比:7.5%–8.3%
- 人均PV:6–8
-
2021年
-
- 注册用户数:12,000–18,000
- DAU(日活):800–1,400
- PV(日页面浏览):5,000–11,000
- 日活占用户比:6.5%–7.8%
- 人均PV:6–8
-
2022年
-
- 注册用户数:15,000–22,000
- DAU(日活):900–1,600
- PV(日页面浏览):6,000–13,000
- 日活占用户比:6%–7.3%
- 人均PV:6.5–8
-
2023年
-
- 注册用户数:17,000–26,000
- DAU(日活):900–1,700
- PV(日页面浏览):6,000–14,000
- 日活占用户比:5.3%–6.5%
- 人均PV:6–8
-
2024年
-
- 注册用户数:18,000–28,000
- DAU(日活):850–1,600
- PV(日页面浏览):5,500–13,000
- 日活占用户比:4.7%–5.7%
- 人均PV:6–8
-
2025年
-
- 注册用户数:18,500–30,000
- DAU(日活):800–1,500
- PV(日页面浏览):5,000–12,000
- 日活占用户比:4.3%–5.0%
- 人均PV:6–8
-
2026年
-
- 注册用户数:19,000–31,000
- DAU(日活):750–1,400
- PV(日页面浏览):4,500–11,000
- 日活占用户比:3.9%–4.5%
- 人均PV:6–7.5
参数解析:
PV(Page View):页面访问量,即页面浏览量或点击量,用户每次刷新一次即被计算一次
UV(Unique Visitor):独立访客,统计1天内访问某站点的用户数
DAU(Daily Active User),日活跃用户数量。常用于反映网站、互联网应用或网络游戏的运营情况
吞吐量:应用系统每秒钟最大能接受的用户访问量或者每秒钟最大能处理的请求数
QPS(Query Per Second):每秒钟处理完请求的次数,注意这里是处理完。具体是指发出请求到服务器处理完成功返回结果。可以理解在Server中有个Counter,每处理一个请求加1,1秒后Counter=QPS
TPS(Transactions Per Second):每秒钟处理完的事务次数,一般TPS是对整个系统来讲的。一个应用系统1s能完成多少事务处理,一个事务在分布式处理中,可能会对应多个请求,对于衡量单个接口服务的处理能力,用QPS比较多
并发量:系统能同时处理的请求数
RT(Response Time):响应时间,处理一次请求所需要的平均处理时间
计算公式:
QPS = 并发量 / 平均响应时间 并发量:同一时刻到达服务器的请求数
并发量 = QPS * 平均响应时间
100w * 100 = 10亿 /8w6秒 = 1300 QPS
案例:
假设服务并发量为1500,RT为150ms,那么该服务的QPS :
10000 = 1500(并发数)/ 0.15 (RT)
假如通过压测一台机器的QPS为500,那么该服务需要20+台这样的机器。
课下作业 - QPS
业界常见的企业级业务,我们的QPS一般是多少?
根据 DAU 评估 QPS
根据 QPS 评估所需要的机器
LNMP 企业架构服务器准备
CPU 核数建议 -> 4核
内存建议 -> 4G
存储建议 -> 20G
| 编号 | 主机名称 | IP地址 | 角色 |
|---|---|---|---|
| 1 | lnmp.itcast.cn | 192.168.88.101 | lnmp |
修改 IP 地址、主机名、域名解析
操作系统选择 CentOS Stream 9
hostnamectl set-hostname lnmp.itcast.cn && bash
[root@lnmp ~]# ls /etc/NetworkManager/system-connections/
ens160.nmconnection
[root@lnmp ~]# vim /etc/NetworkManager/system-connections/ens160.nmconnection
------------------------------------------------------ 设置开始 -------------------------------------------------------------
[ipv4]
method=manual
addresses=192.168.88.101/24
gateway=192.168.88.2
dns=192.168.88.2;114.114.114.114;
[ipv6]
#method=ignore
method=disabled
------------------------------------------------------ 设置结束 -------------------------------------------------------------
[root@lnmp ~]# cat /etc/NetworkManager/system-connections/ens160.nmconnection
[connection]
id=ens160
#uuid=39fc68b0-865c-3bd3-a42d-3e1998f8e2cd
type=ethernet
autoconnect-priority=-999
interface-name=ens160
timestamp=1752853607
[ethernet]
[ipv4]
#method=auto
method=manual
addresses=192.168.88.101/24
gateway=192.168.88.2
dns=192.168.88.2;114.114.114.114;
[ipv6]
#addr-gen-mode=eui64
#method=auto
method=disabled
[proxy]
[root@lnmp ~]#
[root@lnmp ~]# systemctl restart NetworkManager
或者
[root@lnmp ~]# nmcli connection reload
[root@lnmp ~]# nmcli connection down ens33 && nmcli connection up ens33
[root@lnmp ~]# nmcli c up ens160
[root@lnmp ~]# nmcli device show ens160
如果不想重启整个 NetworkManager 服务,可以只重新激活特定的网络连接:
nmcli connection down <连接名称>
nmcli connection up <连接名称>
nmcli connection down ens33 && nmcli connection up ens33
如果想重启所有网络接口,可以使用以下命令:
nmcli networking off
nmcli networking on
配置/etc/hosts解析
# hostnamectl set-hostname lnmp.itcast.cn
vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.88.101 lnmp lnmp.itcast.cn
关闭防火墙与 SELinux
扩展:CentOS Stream 9 => systemctl
服务管理:启动/停止/重启/查看状态
systemctl start/stop/restart/status 服务名称
开机启动项管理:
systemctl enable 服务名称 => 开机启动
systemctl disable 服务名称 => 开机不启动 千万不要忘记
关闭防火墙与SELinux:
iptables -F
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i '/SELINUX=enforcing/cSELINUX=disabled' /etc/selinux/config
配置 yum 源
阿里源(推荐)
cat >/etc/yum.repos.d/aliyun.repo<<EOF
[baseos]
name=CentOS Stream \$releasever - BaseOS
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[baseos-debug]
name=CentOS Stream \$releasever - BaseOS - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[baseos-source]
name=CentOS Stream \$releasever - BaseOS - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream]
name=CentOS Stream \$releasever - AppStream
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[appstream-debug]
name=CentOS Stream \$releasever - AppStream - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[appstream-source]
name=CentOS Stream \$releasever - AppStream - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb]
name=CentOS Stream \$releasever - CRB
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[crb-debug]
name=CentOS Stream \$releasever - CRB - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[crb-source]
name=CentOS Stream \$releasever - CRB - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability]
name=CentOS Stream \$releasever - HighAvailability
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[highavailability-debug]
name=CentOS Stream \$releasever - HighAvailability - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[highavailability-source]
name=CentOS Stream \$releasever - HighAvailability - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv]
name=CentOS Stream \$releasever - NFV
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[nfv-debug]
name=CentOS Stream \$releasever - NFV - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[nfv-source]
name=CentOS Stream \$releasever - NFV - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt]
name=CentOS Stream \$releasever - RT
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[rt-debug]
name=CentOS Stream \$releasever - RT - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[rt-source]
name=CentOS Stream \$releasever - RT - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage]
name=CentOS Stream \$releasever - ResilientStorage
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0
[resilientstorage-debug]
name=CentOS Stream \$releasever - ResilientStorage - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[resilientstorage-source]
name=CentOS Stream \$releasever - ResilientStorage - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
[extras-common]
name=CentOS Stream \$releasever - Extras packages
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/\$basearch/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1
[extras-common-source]
name=CentOS Stream \$releasever - Extras packages - Source
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/source/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
EOF
清华源(了解)
帮助手册:https://mirrors.tuna.tsinghua.edu.cn/help/centos-stream/
yum或者dnf => 系统/etc/yum.repos.d目录,找到镜像仓库配置文件 => 请求远程仓库
配置方案:阿里镜像站、腾讯镜像站、华为镜像站、清华镜像站(推荐)
CentOS Stream 9 默认启用了包管理工具 dnf,其是 yum 包管理工具的替代品。dnf 与 yum 大部分的命令都是通用的,dnf 也使用 /etc/yum.repos.d/ 进行镜像配置。
CentOS Stream 9 中源被整合入两个文件 centos.repo 和 centos-addons.repo,由于文件中不包含 baseurl 字段,需要手动插入,通过文本替换修改源的方法较为复杂,也可以选择直接复制最后的替换结果覆盖源文件。
将这段代码保存为一个文件,放在家目录下,例如 update_mirror.pl
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
my $mirrors = 'https://mirrors.tuna.tsinghua.edu.cn/centos-stream';
if (@ARGV < 1) {
die "Usage: $0 <filename1> <filename2> ...\n";
}
while (my $filename = shift @ARGV) {
my $backup_filename = $filename . '.bak';
rename $filename, $backup_filename;
open my $input, "<", $backup_filename;
open my $output, ">", $filename;
while (<$input>) {
s/^metalink/# metalink/;
if (m/^name/) {
my (undef, $repo, $arch) = split /-/;
$repo =~ s/^\s+|\s+$//g;
($arch = defined $arch ? lc($arch) : '') =~ s/^\s+|\s+$//g;
if ($repo =~ /^Extras/) {
$_ .= "baseurl=${mirrors}/SIGs/\$releasever-stream/extras" . ($arch eq 'source' ? "/${arch}/" : "/\$basearch/") . "extras-common\n";
} else {
$_ .= "baseurl=${mirrors}/\$releasever-stream/$repo" . ($arch eq 'source' ? "/" : "/\$basearch/") . ($arch ne '' ? "${arch}/tree/" : "os") . "\n";
}
}
print $output $_;
}
}
然后,在命令行中使用以下命令来执行它:
dnf install perl-autodie -y
perl ./update_mirror.pl /etc/yum.repos.d/centos*.repo
最后,更新软件包缓存:
# 使用 dnf
dnf clean all && dnf makecache
注意,如果需要启用其中一些 repo,需要将其中的 enabled=0 改为 enabled=1。
ntpdate 时间同步(可选)
CentOS 镜像源有很多种,centos-base.repo 基础源,epel-release 扩展源
ntpdate 手工同步操作 => 人为实现时间同步
dnf install epel-release -y
dnf install ntpsec -y
ntpdate cn.ntp.org.cn
-----------------------------------------
yum install chrony -y
systemctl enable chronyd --now
systemctl status chronyd
自行配置chrony时间同步
LNMP 架构环境搭建(重点)
Nginx 软件安装
编译安装
软件的编译安装过程:编译安装三步走(配置 + 编译 + 安装)
① 配置软件 ./configure
② 编译,生成可执行的软件包make
③ 安装make install
1 安装依赖库
[root@lnmp ~] # dnf -y install pcre-devel zlib-devel openssl-devel
devel是什么意思?
Development Libraries,开发库,简写devel
| 开发库 | 核心功能 | 典型依赖软件 |
|---|---|---|
| pcre-devel | 正则表达式解析 | Nginx、Apache、PHP |
| zlib-devel | 数据压缩 | Nginx、MySQL、Python |
| openssl-devel | SSL/TLS 加密、数字证书处理 | Nginx、MySQL、Python |
2 创建账号
[root@lnmp ~] # useradd -r -s /sbin/nologin www
3 配置/编译与安装
安装gcc
yum install -y gcc
GCC 是 Linux 世界的“基础设施级工具”
它不仅是编译器,更是优化、调试、跨平台的核心工具
下载Nginx源码包
wget https://nginx.org/download/nginx-1.28.0.tar.gz
解压Nginx源码包
tar xvf nginx-1.28.0.tar.gz
预编译(环境检测 + 生成编译配置)
cd nginx-1.28.0
./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module
源码编译及安装Nginx
make -j$(nproc) && make install
-j$(nproc) 多进程并行编译
-j 允许 make 同时执行多个任务
echo $(nproc) 返回 CPU 核心数
配置Nginx环境变量
echo 'PATH=$PATH:/usr/local/nginx/sbin/' >> /etc/profile && source /etc/profile
更改/usr/local/nginx目录权限
chown -Rf www:www /usr/local/nginx
查看Nginx版本信息
nginx -v

常见报错

# 需要下载库
dnf install -y pcre-devel
编译参数说明
| 参数 | 作用 |
|---|---|
| --prefix | 编译安装到的软件目录 |
| --user | worker进程运行用户 |
| --group | worker进程运行用户组 |
| --with-http_ssl_module | 支持https 需要pcel-devel依赖 |
| --with-http_stub_status_module | 基本状态信息显示 查看请求数、连接数等 |
| --with-http_realip_module | 定义客户端地址和端口为header头信息 常用于反向代理后的真实IP获取 |
启动与停止 Nginx 服务
启动nginx
[root@lnmp ~] # nginx
停止nginx
[root@lnmp ~] # nginx -s quit


配置 systemd 服务管理 nginx
CentOS Stream 9 配置:
# 注意:一定要提前把Nginx停止掉 ----省略操作
nginx -s stop
# Nginx服务配置到该文件中 ----省略操作
cat >/usr/lib/systemd/system/nginx.service <<EOF
[Unit]
Description=Nginx Web Server
After=network.target
[Service]
Type=forking
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s quit
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
启动 Nginx 服务
[root@nginx ~]# systemctl daemon-reload
[root@nginx ~]# systemctl start nginx
[root@nginx ~]# systemctl status nginx
设置 Nginx 开机启动
[root@nginx ~]# systemctl enable nginx
stop vs quit
思考:nginx -s stop 和 nginx -s quit 的区别?
stop:强制终止,会直接终止请求
quit:平滑停止,不中断现有连接,停止较慢
MySQL 软件安装
安装
MySQL 最初由瑞典 MySQL AB 公司开发(2008 年被 Sun 收购,2010 年 Sun 被甲骨文 Oracle 收购)。
| 安装目录 | 数据目录 | 默认端口 | 套接字(关键) |
|---|---|---|---|
| /usr/local/mysql | /usr/local/mysql/data | 3306 | /tmp/mysql.sock |
安装路径:/usr/local/mysql
数据目录:/usr/local/mysql/data
端口:3306
socket文件存放路径:/tmp/mysql.sock
除了套接字问题,还需要注意的就是my.cnf配置文件,其加载顺序:
① 安装目录
② /etc目录
如果安装目录与/etc都有my.cnf,则/etc目录下的my.cnf会覆盖安装目录中的配置文件。
MySQL的配置文件加载,后加载的配置会覆盖前面的配置。

1 环境准备
准备工作,提前卸载与mariadb相关软件包
# 1 清空系统中的原有mariadb的配置文件(/etc/my.cnf)
rpm -qa | grep mariadb
rm -rf /etc/my.cnf
# 2 检查当前系统中,是否安装有 MySQL,避免软件冲突
dnf list installed | grep mysql
# 如果有,卸载
dnf remove -y mysql mysql-server
# 3 安装依赖
yum install libaio -y
libaio 是 Linux 的异步 I/O (Asynchronous Input/Output) 库,全称是 Linux Asynchronous I/O Library。
它的主要作用是允许程序在不阻塞 CPU 的情况下发起 I/O 操作,即 I/O 请求可以异步地进行,程序不需要等待 I/O 操作完成后再进行下一步操作,从而提高了 I/O 性能。在 MySQL 中,libaio 被用于处理磁盘的读写操作,尤其是在高负载和高并发的情况下,可以提高数据库的性能和响应速度。
2 创建 MySQL 账号
创建一个数据库专用账号 mysql(其所属组也为mysql) => -r 系统账号,-s 可以使用 shell
useradd -r -s /sbin/nologin mysql
id mysql
参数说明:
-r :系统参数
-s :shell缩写,用于指定shell解析器,需要登录系统账号,用/bin/bash;不需要登录系统的账号(系统账号),用/sbin/nologin
3 解压并拷贝软件包
# 1 解压软件包
tar xvf mysql-8.0.43-linux-glibc2.28-x86_64.tar.xz
ll mysql-8.0.43-linux-glibc2.28-x86_64
xvf:可以解压任何tar类型的压缩包,如.tar.gz或.tar.xz格式压缩包
提示:使用tab键进行自动补全操作。
# 2 把mysql解压后的压缩包(GBLIC版本)移动到 /usr/local/ 下,然后更名为mysql
mv mysql-8.0.43-linux-glibc2.28-x86_64 /usr/local/mysql
或者
cp -r mysql-8.0.43-linux-glibc2.28-x86_64 /usr/local/mysql

4 初始数据库(核心)
第三步:初始化数据库(可以实现数据库的初始化,而且会产生一个随机密码)
# 切换到mysql工作目录 /usr/local/mysql
cd /usr/local/mysql
./bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql &> /tmp/mysqld.log
等价于绝对路径
/usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql &>/tmp/mysqld.log
注意:
这些是等价的,只选择一个就可以,不能一股脑全部执行,哈哈。
'&>' 会把内容重定向到文件。使用 cat /tmp/mysqld.log 可以查看里面初始化的信息。
选项说明:
--initialize 初始化(真正开始干活)
--user=mysql 以mysql用户的身份初始化数据库,产生文件都是mysql作为拥有者
--basedir=xxx mysql其安装目录,非常重要
运行完毕后,观察 /tmp/mysqld.log 文件最后一行,保存root账号的密码,以备后期使用。
A temporary password is generated for root@localhost: synNE*skt4ts
经验之谈:想查看mysql软件有没有初始化成功,主要看mysql目录下有没有产生data文件夹且文件夹中至少要有一个mysql的文件夹。
延伸一下:有一个文件/tmp/mysqld.log,里面保存了数据库密码信息,如何提取出这个密码?
答:grep password /tmp/mysqld.log | awk '{print $NF}'
注:NF表示 Number of Fields,字段总数。因此,$NF就表示最后一列了。

初始化完成后,记得递归修改一下 mysql 文件夹权限。
chown -R mysql.mysql /usr/local/mysql

5 设置安全连接(了解)
第四步:设置安全加密连接(SSL),数据传输会采用加密形式,适合敏感数据(了解)
cd /usr/local/mysql
bin/mysql_ssl_rsa_setup --datadir=/usr/local/mysql/data
安装后配置
1 配置 my.cnf
删除默认配置文件my.cnf,然后初始化MySQL(如果全新系统,上面是没有这个配置文件的)
# rm -f /etc/my.cnf
# 创建my.cnf
cat >/etc/my.cnf<<EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/data
socket=/tmp/mysql.sock
port=3306
log-error=/usr/local/mysql/data/mysql.err
log-bin=/usr/local/mysql/data/binlog
server-id=10
character_set_server=utf8mb4
gtid-mode=on
log-slave-updates=1
enforce-gtid-consistency
sql_mode=NO_ENGINE_SUBSTITUTION
EOF
2 创建 Service
创建 mysqld.service(d 表示 daemon,守护,后台的意思)
cat >/usr/lib/systemd/system/mysqld.service<<EOF
[Unit]
Description=MySQL Server
After=network.target
[Service]
User=mysql
Group=mysql
Type=forking
# MySQL 执行命令及路径
ExecStart=/usr/local/mysql/bin/mysqld --daemonize --pid-file=/usr/local/mysql/data/mysqld.pid
ExecStop=/usr/local/mysql/bin/mysqladmin --defaults-file=/etc/my.cnf shutdown
# Ensure MySQL has sufficient time to start up
TimeoutSec=600
# PID 文件路径
PIDFile=/usr/local/mysql/data/mysqld.pid
# Enable these options to auto-restart the service if it crashes
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
服务创建完成后,重新加载 systemd 服务,并启动数据库
# 重载
systemctl daemon-reload
# 开机自启
systemctl enable mysqld
# 启动
systemctl start mysqld
# 查看状态
systemctl status mysqld
# 停止
systemctl stop mysqld
# 开机不自启
systemctl disable mysqld
验证测试
# 查看状态
systemctl status mysqld

3 添加环境变量,修改密码
添加环境变量,进入mysql,更改mysql的默认密码
echo 'export PATH=$PATH:/usr/local/mysql/bin' >> /etc/profile
source /etc/profile
mysql -uroot -p
Enter password: xxxxxxx # 初始默认密码
或者
mysql -uroot -p'初始默认密码'
mysql> set password='MySQL@666';
mysql> flush privileges;
[root@lnmp ~]# which mysql
/usr/bin/which: no mysql in (/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/nginx/sbin/)
[root@lnmp ~]# echo 'export PATH=$PATH:/usr/local/mysql/bin' >> /etc/profile
source /etc/profile
[root@lnmp ~]# which mysql
/usr/local/mysql/bin/mysql
[root@lnmp ~]# mysql -uroot -p
Enter password:初始默认密码
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.43
Copyright (c) 2000, 2025, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> set password='MySQL@666';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)
mysql> ^DBye
[root@lnmp ~]# mysql -uroot -pMySQL@666
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.43 MySQL Community Server - GPL
Copyright (c) 2000, 2025, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.01 sec)
mysql>
扩展:编写 MySQL 安装脚本
优化Linux系统
sed -i -r 's/SELINUX=[ep].*/SELINUX=disabled/g' /etc/selinux/config
# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config &> /dev/null
setenforce 0
systemctl stop firewalld &> /dev/null
systemctl disable firewalld &> /dev/null
iptables -F
iptables -t nat -F
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
vim mysql8_install.sh
#!/bin/bash
if rpm -q libaio &> /dev/null; then
echo "libaio已安装,跳过安装"
else
echo "开始安装依赖"
dnf -y install libaio &> /dev/null
if [ $? -ne 0 ];then
echo "libaio安装失败"
exit 1
fi
fi
echo "进行解压操作"
if ls -l mysql-8.0.43-linux-glibc2.28-x86_64 &> /dev/null; then
echo "已解压,跳过"
else
if [ -f mysql-8.0.43-linux-glibc2.28-x86_64.tar.xz ]; then
tar -xf mysql-8.0.43-linux-glibc2.28-x86_64.tar.xz
ls -l mysql-8.0.43-linux-glibc2.28-x86_64
fi
fi
echo "判断是否安装过MariaDB,进行清理"
rpm -qa | grep mariadb | xargs -r dnf remove -y
if [ -f /etc/my.cnf ]; then
rm -rf /etc/my.cnf
fi
id mysql &> /dev/null
[ $? -ne 0 ] && useradd -r -s /sbin/nologin mysql
rm -rf /export/server
mkdir -p /export/server
cp -r mysql-8.0.43-linux-glibc2.28-x86_64 /export/server/mysql
chown -R mysql:mysql /export/server/mysql
echo "正在进入mysql目录,对其进行初始化操作..."
cd /export/server/mysql
bin/mysqld --initialize --user=mysql --basedir=/export/server/mysql --datadir=/export/server/mysql/data 2>&1 | tee /tmp/mysqld.log | grep password | awk '{print $NF}' > /tmp/mysql_temp_password.txt
bin/mysql_ssl_rsa_setup --datadir=/export/server/mysql/data &> /dev/null
cat >/etc/my.cnf<<EOF
[mysqld]
port=3306
basedir=/export/server/mysql
datadir=/export/server/mysql/data
socket=/tmp/mysql.sock
character_set_server=utf8
collation-server=utf8_unicode_ci
EOF
cat >/etc/systemd/system/mysqld.service<<EOF
[Unit]
Description=MySQL Server
After=network.target
[Service]
User=mysql
Group=mysql
Type=forking
# MySQL 执行命令及路径
ExecStart=/export/server/mysql/bin/mysqld --daemonize --pid-file=/export/server/mysql/data/mysqld.pid
ExecStop=/export/server/mysql/bin/mysqladmin --defaults-file=/export/server/mysql/my.cnf shutdown
# Ensure MySQL has sufficient time to start up
TimeoutSec=600
# PID 文件路径
PIDFile=/export/server/mysql/data/mysqld.pid
# Enable these options to auto-restart the service if it crashes
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
echo "正在刷新后台服务,然后启动mysqld..."
systemctl daemon-reload
systemctl start mysqld
systemctl enable mysqld
#10.重置mysql管理员密码为MySQL@666
echo "正在重置mysql管理员密码..."
cd /export/server/mysql
temp_password=`cat /tmp/mysql_temp_password.txt`
bin/mysqladmin -uroot password 'MySQL@666' -p"$temp_password"
echo 'export PATH=$PATH:/export/server/mysql/bin' >> /etc/profile
source /etc/profile
echo "MySQL8安装成功,安装路径:/export/server/mysql,数据库初始密码:MySQL@666"
执行mysql8_install.sh脚本安装MySQL8
chmod +x mysql8_install.sh
source mysql8_install.sh
[root@jaking ~]# mysql -uroot -pMySQL@666
mysql: [Warning] Using a password on the command line interface can be insecure .
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.43 MySQL Community Server - GPL
Copyright (c) 2000, 2025, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.01 sec)
mysql> ^DBye
[root@jaking ~]# cat /etc/redhat-release
CentOS Stream release 9
[root@jaking ~]# dmidecode -s system-manufacturer
Alibaba Cloud
[root@jaking ~]# dmidecode -s system-product-name
Alibaba Cloud ECS
[root@jaking ~]#

PHP 软件安装
相关介绍
☆ PHP
PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言,主要应用于Web领域。
PHP是将程序嵌入到HTML(标准通用标记语言下的一个应用)文档中去执行,执行效率比完全生成HTML标记的CGI要高许多
PHP还可以执行编译后代码,编译可以达到加密和优化代码运行,使代码运行更快。(新特性)
☆ PHP-FPM
Apache:Apache + PHP,容易崩溃,效率低
Nginx: Nginx + PHP,PHP-FPM 进程管理器,稳定,效率高
PHP-FPM(FastCGI Process Manager)是 PHP 的官方 FastCGI 进程管理器,提供更高效的进程控制和资源管理。
历史演进:
- PHP 5.3.3 之前需手动安装(作为补丁包),之后被官方集成。
核心优势:
- 资源控制更精准:相比传统的 Spawn-FCGI,PHP-FPM 能精确控制 CPU 和内存占用。
- 进程稳定性更强:内置进程监控机制,避免频繁崩溃(无需依赖 crontab 定时重启)。
- 平滑重载配置:支持不中断服务的情况下重新加载 PHP 配置(如修改 php.ini)。
使用场景:
- 高并发 Web 应用(如 WordPress、Laravel)与 Nginx/Apache 搭配时的首选方案。
在 ./configure 的时候带 –-enable-fpm 参数即可开启PHP-FPM
编译安装
php旧版本地址:https://www.php.net/eol.php
1 安装依赖库
[root@lnmp ~]# dnf -y install libxml2-devel libjpeg-devel libpng-devel libwebp-devel freetype-devel curl-devel openssl-devel sqlite sqlite-devel libtool pcre-devel gd-devel
- 安装 oniguruma 库(如果下载不了,直接上传压缩包到/usr/local/src目录即可)
oniguruma 库是 PHP 在启用多字节正则表达式支持时的必需库
cd /usr/local/src
wget https://github.com/kkos/oniguruma/releases/download/v6.9.8/onig-6.9.8.tar.gz
或者
curl -LO https://github.com/kkos/oniguruma/releases/download/v6.9.8/onig-6.9.8.tar.gz
tar xvf onig-6.9.8.tar.gz
cd onig-6.9.8
./configure
make
make install
设置 ONIG_CFLAGS 和 ONIG_LIBS 环境变量
cat >>/etc/profile<<EOF
export ONIG_CFLAGS="-I/usr/include"
export ONIG_LIBS="-L/usr/lib -lonig"
EOF
source 刷新环境变量
source /etc/profile
在 C/C++ 编译中,需要找到指定的源代码文件位置。
| 参数 | 功能 | 示例 |
|---|---|---|
| -I | 指定头文件(.h)路径 | -I/usr/include |
| -L | 指定库文件(.so)路径 | -L/usr/lib -lonig |
- 安装libsodium库(如果下载不了,直接上传压缩包到/usr/local/src目录即可)
libsodium 是“开箱即用”的现代密码学工具箱——把最常用、最难配、最容易踩坑的加密算法(ChaCha20-Poly1305、X25519、Argon2 …)全部封装成 几行 C 代码就能调用的安全 API
# 下载 libsodium 源码
cd /usr/local/src
dnf install wget -y
wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.20.tar.gz
tar xvf libsodium-1.0.20.tar.gz
cd libsodium-1.0.20
# 编译并安装
./configure && make -j$(nproc) && make install
# 更新库缓存
ldconfig
设置 LIBSODIUM_CFLAGS 和 LIBSODIUM_LIBS 环境变量
cat >>/etc/profile<<'EOF'
export LIBSODIUM_CFLAGS="-I/usr/local/include"
export LIBSODIUM_LIBS="-L/usr/local/lib -lsodium"
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
EOF
source刷新环境变量
source /etc/profile
2 下载并解压 PHP 源码包
[root@lnmp ~]# wget https://www.php.net/distributions/php-8.1.30.tar.gz
[root@lnmp ~]# tar xvf php-8.1.30.tar.gz -C /usr/local/src
[root@lnmp ~]# ls /usr/local/src
libsodium-1.0.20 onig-6.9.8 php-8.1.30
libsodium-1.0.20.tar.gz onig-6.9.8.tar.gz
[root@lnmp ~]# cd /usr/local/src/php-8.1.30/
[root@lnmp php-8.1.30]# ls
build docs php.ini-development tests
buildconf ext php.ini-production travis
buildconf.bat EXTENSIONS README.md TSRM
CODING_STANDARDS.md LICENSE README.REDIST.BINS UPGRADING
configure main run-tests.php UPGRADING.INTERNALS
configure.ac NEWS sapi win32
CONTRIBUTING.md pear scripts Zend
[root@lnmp php-8.1.30]#
3 编译安装 PHP -> php-fpm
PHP扩展,PHP连接MySQL,需要MySQL扩展
[root@lnmp php-8.1.30]# pwd
/usr/local/src/php-8.1.30
[root@lnmp php-8.1.30]# ./configure --prefix=/usr/local/php --with-config-file-path=/usr/local/php/etc --enable-fpm --with-fpm-user=www --with-fpm-group=www --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --with-iconv --with-freetype --with-jpeg --with-zlib --enable-gd --with-external-gd --with-xpm --with-webp --enable-xml --disable-rpath --enable-bcmath --enable-shmop --enable-sysvsem --with-curl --enable-mbregex --enable-mbstring --enable-ftp --with-openssl --with-mhash --enable-sockets --enable-soap --without-pear --with-gettext --enable-pcntl --with-sodium --enable-fileinfo
或者
[root@lnmp php-8.1.30]# ./configure \
--prefix=/usr/local/php \
--with-config-file-path=/usr/local/php/etc \
--enable-fpm \
--with-fpm-user=www \
--with-fpm-group=www \
\
# 数据库相关
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
\
# 字符与压缩
--with-iconv \
--with-zlib \
\
# 图像处理
--with-freetype \
--with-jpeg \
--enable-gd \
--with-external-gd \
--with-xpm \
--with-webp \
\
# 基础功能
--enable-xml \
--disable-rpath \
--enable-bcmath \
--enable-shmop \
--enable-sysvsem \
\
# 网络与协议
--with-curl \
--enable-ftp \
--with-openssl \
--with-mhash \
--enable-sockets \
--enable-soap \
\
# 其他功能
--without-pear \
--with-gettext \
--enable-pcntl \
--with-sodium \
--enable-fileinfo

编译并安装
make默认单核编译,可以通过make -j数字(核心数)
$(nproc) 会自动返回当前系统的 CPU 核心数,从而加速编译过程。
[root@lnmp php-8.1.30]# make -j$(nproc) && make install

优化 PHP 配置
使用 php-fpm 进行管理 php 服务,有三个配置文件:
① php.ini #默认php配置文件(/usr/local/src/php-8.1.30)
② php-fpm.conf #php-fpm.conf是 php-fpm 进程服务的配置文件 (默认已存在)
③ www.conf #www.conf这是 php-fpm 进程服务的扩展配置文件(默认以存在)
cp /usr/local/src/php-8.1.30/php.ini-development /usr/local/php/etc/php.ini
cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf
cp /usr/local/php/etc/php-fpm.d/www.conf.default /usr/local/php/etc/php-fpm.d/www.conf
注意:
development 配置项多一些 显示语法错误等等信息 适合于部署开发环境和测试环境
production 默认开启项少 生产环境是不要出现错误 不暴露服务器目录结构
☆ 修改配置文件,添加启动服务
vim /usr/local/php/etc/php-fpm.conf
------------- 修改如下 -------------
13 [global]
14 ; Pid file
15 ; Note: the default prefix is /usr/local/php/var
16 ; Default Value: none
17 pid = run/php-fpm.pid
...
99 daemonize = yes
注意事项:17、99行前面都有一个分号;必须要去除,因为在php-fpm.conf文件中,分号;代表注释!
vim /usr/local/php/etc/php-fpm.d/www.conf
------------- 修改如下 -------------
111 pm = dynamic 使用动态方式启动 # pm = static 使用静态方式启动
122 pm.max_children = 50 并发处理 50 个请求
127 pm.start_servers = 2 最开始启动的进程数量
132 pm.min_spare_servers = 1 备用的进程
137 pm.max_spare_servers = 3 最大可以启动的进程数量
---------------------------------------
配置 systemd 服务
cat >/usr/lib/systemd/system/php-fpm.service<<'EOF'
[Unit]
Description=PHP FastCGI Process Manager
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/php/var/run/php-fpm.pid
ExecStart=/usr/local/php/sbin/php-fpm --fpm-config /usr/local/php/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
ExecStop=/bin/kill -QUIT $MAINPID
TimeoutStartSec=180
LimitNOFILE=65535
LimitNPROC=500
PrivateTmp=true
User=www
Group=www
[Install]
WantedBy=multi-user.target
EOF
启动前,权限配置说明:
chown -Rf www:www /usr/local/php/var
systemctl daemon-reload
systemctl start php-fpm
systemctl status php-fpm
systemctl enable php-fpm
注意:php-fpm在计算机中默认会运行9000端口!
[root@lnmp php-8.1.30]# systemctl status php-fpm
● php-fpm.service - PHP FastCGI Process Manager
Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; disabled; preset>
Active: active (running) since Tue 2026-03-24 17:36:44 CST; 6s ago
Process: 240618 ExecStart=/usr/local/php/sbin/php-fpm --fpm-config /usr/lo>
Main PID: 240626 (php-fpm)
Tasks: 3 (limit: 22927)
Memory: 23.6M
CPU: 47ms
CGroup: /system.slice/php-fpm.service
├─240626 "php-fpm: master process (/usr/local/php/etc/php-fpm.con>
├─240627 "php-fpm: pool www"
└─240628 "php-fpm: pool www"
Mar 24 17:36:44 lnmp.itcast.cn systemd[1]: Starting PHP FastCGI Process Manage>
Mar 24 17:36:44 lnmp.itcast.cn php-fpm[240626]: [24-Mar-2026 17:36:44] NOTICE:>
Mar 24 17:36:44 lnmp.itcast.cn php-fpm[240626]: [24-Mar-2026 17:36:44] NOTICE:>
Mar 24 17:36:44 lnmp.itcast.cn systemd[1]: Started PHP FastCGI Process Manager.
[root@lnmp php-8.1.30]# systemctl enable php-fpm
Created symlink /etc/systemd/system/multi-user.target.wants/php-fpm.service → /usr/lib/systemd/system/php-fpm.service.
[root@lnmp php-8.1.30]# netstat -pantul|grep php
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 240626/php-fpm: mas
[root@lnmp php-8.1.30]#
☆ 添加环境变量
(方便php、phpize、phpconfig查找使用)
echo 'export PATH=$PATH:/usr/local/php/bin' >> /etc/profile
source /etc/profile

完整实战过程
[root@lnmp ~]# cat >/usr/lib/systemd/system/php-fpm.service<<'EOF'
[Unit]
Description=PHP FastCGI Process Manager
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/php/var/run/php-fpm.pid
ExecStart=/usr/local/php/sbin/php-fpm --fpm-config /usr/local/php/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
ExecStop=/bin/kill -QUIT $MAINPID
TimeoutStartSec=180
LimitNOFILE=65535
LimitNPROC=500
PrivateTmp=true
User=www
Group=www
[Install]
WantedBy=multi-user.target
EOF
[root@lnmp ~]# cat /usr/lib/systemd/system/php-fpm.service
[Unit]
Description=PHP FastCGI Process Manager
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/php/var/run/php-fpm.pid
ExecStart=/usr/local/php/sbin/php-fpm --fpm-config /usr/local/php/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
ExecStop=/bin/kill -QUIT $MAINPID
TimeoutStartSec=180
LimitNOFILE=65535
LimitNPROC=500
PrivateTmp=true
User=www
Group=www
[Install]
WantedBy=multi-user.target
[root@lnmp ~]# chown -Rf www:www /usr/local/php/var
[root@lnmp ~]# systemctl daemon-reload
[root@lnmp ~]# systemctl start php-fpm
[root@lnmp ~]# systemctl status php-fpm
● php-fpm.service - PHP FastCGI Process Manager
Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; disabled; preset>
Active: active (running) since Sun 2025-12-14 11:45:07 CST; 3s ago
Process: 205833 ExecStart=/usr/local/php/sbin/php-fpm --fpm-config /usr/lo>
Main PID: 205836 (php-fpm)
Tasks: 3 (limit: 48692)
Memory: 23.6M
CPU: 48ms
CGroup: /system.slice/php-fpm.service
├─205836 "php-fpm: master process (/usr/local/php/etc/php-fpm.con>
├─205837 "php-fpm: pool www"
└─205838 "php-fpm: pool www"
Dec 14 11:45:07 lnmp.itcast.cn systemd[1]: Starting PHP FastCGI Process Manage>
Dec 14 11:45:07 lnmp.itcast.cn php-fpm[205836]: [14-Dec-2025 11:45:07] NOTICE:>
Dec 14 11:45:07 lnmp.itcast.cn php-fpm[205836]: [14-Dec-2025 11:45:07] NOTICE:>
Dec 14 11:45:07 lnmp.itcast.cn systemd[1]: Started PHP FastCGI Process Manager.
[root@lnmp ~]# systemctl enable php-fpm
Created symlink /etc/systemd/system/multi-user.target.wants/php-fpm.service → /usr/lib/systemd/system/php-fpm.service.
[root@lnmp ~]# ss -ant|grep 9000
LISTEN 0 511 127.0.0.1:9000 0.0.0.0:*
[root@lnmp ~]# which php
/usr/bin/which: no php in (/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/nginx/sbin/:/usr/local/nginx/sbin/:/usr/local/mysql/bin:/usr/local/nginx/sbin/:/usr/local/mysql/bin:/usr/local/nginx/sbin/:/usr/local/mysql/bin)
[root@lnmp ~]# php -v
bash: php: command not found
[root@lnmp ~]# echo 'export PATH=$PATH:/usr/local/php/bin' >> /etc/profile
[root@lnmp ~]# source /etc/profile
[root@lnmp ~]# which php
/usr/local/php/bin/php
[root@lnmp ~]# php -v
PHP 8.1.30 (cli) (built: Dec 14 2025 11:22:59) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.30, Copyright (c) Zend Technologies
[root@lnmp ~]#
☆ 服务无法启动如何进行日志查看和排错
journalctl -u php-fpm -n 100 #-u 后面接着要排查的服务名称 -n 显示最后多少行的最新日志
Nginx 连接 PHP
核心思路
以下只是核心思路,目前不需要操作,具体配置看下一节
编写 PHP 文件
写入文件 vim /usr/local/nginx/html/demo.php
<?php
phpinfo();
?>
配置 Nginx 解析
nginx 和 php 进行关联,告诉 nginx,php 在哪里:
vim /usr/local/nginx/conf/nginx.conf
server {
listen 80;
server_name localhost;
root html; # 整个server只保留一个root选项
location / {
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
设置 nginx+php 关联,$document_root 就是加载root目录:

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
让 Nginx 可以转发 PHP 代码到 PHP-FPM

具体实现
要想让Nginx可以转发PHP代码到PHP解析器(PHP-FPM),必须在nginx.conf文件中进行配置,把所有后缀名为.php的文件转发到当前计算机的9000端口(PHP-FPM占用9000端口)。
第一步:进入/usr/local/nginx目录,然后把conf/nginx.conf文件进行备份
cd /usr/local/nginx
cp conf/nginx.conf conf/nginx.conf.bak
第二步:使用grep过滤conf/nginx.conf文件,只显示非注释内容
[root@lnmp nginx]# grep -Ev '#|^$' conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
[root@lnmp nginx]#
第三步:去除server模块中的root选项(项目目录),只在server模块中保留一个即可
[root@lnmp nginx]# grep -Ev '#|^$' conf/nginx.conf.bak > conf/nginx.conf
[root@lnmp nginx]# vim conf/nginx.conf
worker_processes auto;
events {
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
root html; # 整个server只保留一个root选项
location / {
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
第四步:添加PHP支持,让Nginx可以识别.php文件,然后转发给9000端口
[root@lnmp nginx]# vim conf/nginx.conf
worker_processes auto;
events {
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
root html; # 整个server只保留一个root选项
location / {
index index.html index.htm;
}
------------------ 分割线 --------------------
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
------------------ 分割线 --------------------
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
注意:
$document_root:指代我们的项目目录,这里就是root html指定html文件夹!
$fastcgi_script_name:指代url地址中请求的.php文件
配置完成后,重载Nginx服务
[root@lnmp nginx]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@lnmp nginx]# nginx -s reload
第五步:编写php测试文件,查看是否可以运行
[root@lnmp nginx]# vim /usr/local/nginx/html/demo.php
<?php
phpinfo();
?>
访问 http://192.168.88.101/demo.php
显示PHP信息界面:

查看LNMP架构各端口运行情况
[root@lnmp ~]# ss -ant
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 511 127.0.0.1:9000 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
ESTAB 0 0 192.168.88.101:22 192.168.88.1:11621
ESTAB 0 48 192.168.88.101:22 192.168.88.1:3840
LISTEN 0 70 *:33060 *:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 151 *:3306 *:*
[root@lnmp ~]# netstat -pantul
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 205836/php-fpm: mas
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 975/sshd: /usr/sbin
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 38472/nginx: master
tcp 0 0 192.168.88.101:22 192.168.88.1:11621 ESTABLISHED 205946/sshd: root [
tcp 0 208 192.168.88.101:22 192.168.88.1:3840 ESTABLISHED 1726/sshd: root [pr
tcp6 0 0 :::33060 :::* LISTEN 38676/mysqld
tcp6 0 0 :::22 :::* LISTEN 975/sshd: /usr/sbin
tcp6 0 0 :::3306 :::* LISTEN 38676/mysqld
udp 0 0 127.0.0.1:323 0.0.0.0:* 895/chronyd
udp6 0 0 ::1:323 :::* 895/chronyd
[root@lnmp ~]# ss -pantul
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.1:323 0.0.0.0:* users:(("chronyd",pid=895,fd=5))
udp UNCONN 0 0 [::1]:323 [::]:* users:(("chronyd",pid=895,fd=6))
tcp LISTEN 0 511 127.0.0.1:9000 0.0.0.0:* users:(("php-fpm",pid=205838,fd=5),("php-fpm",pid=205837,fd=5),("php-fpm",pid=205836,fd=7))
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=975,fd=3))
tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=205929,fd=6),("nginx",pid=205928,fd=6),("nginx",pid=205927,fd=6),("nginx",pid=205926,fd=6),("nginx",pid=38472,fd=6))
tcp LISTEN 0 70 *:33060 *:* users:(("mysqld",pid=38676,fd=21))
tcp LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=975,fd=4))
tcp LISTEN 0 151 *:3306 *:* users:(("mysqld",pid=38676,fd=24))
[root@lnmp ~]#

到此,LNMP环境就全部搭建完毕了!
项目实战:部署 CRMEB 购物商城
目标:能够通过搭建的 LNMP 环境部署各类 PHP 项目
- 注册并登录 https://gitee.com/
- 打开商城源代码仓库:https://gitee.com/ZhongBangKeJi/CRMEB
背景介绍


环境准备
版本约束
https://gitee.com/ZhongBangKeJi/CRMEB/blob/master/README.md

版本约束很重要吗?
在实际的企业生产中,不同的版本,会导致开发环境和生产环境的错配,从而造成上线发布隐患。
举个例子,面试中常问一道题:
在测试环境明明是部署好好的,为什么转到生产环境就报错,你现在协助上线运维,会考虑从哪几个
方面去定位?
卸载 PHP 8.1
对于源码编译的,进入编译目录,先停止服务,执行 make distclean卸载。
[root@lnmp ~]# systemctl stop php-fpm
[root@lnmp ~]# cd /usr/local/src/php-8.1.30/
[root@lnmp php-8.1.30]# make distclean
find . -name \*.gcno -o -name \*.gcda | xargs rm -f
find . -name \*.lo -o -name \*.o -o -name \*.dep | xargs rm -f
find . -name \*.la -o -name \*.a | xargs rm -f
find . -name \*.so | xargs rm -f
find . -name .libs -a -type d|xargs rm -rf
rm -f libphp.la sapi/cli/php sapi/cgi/php-cgi sapi/fpm/php-fpm modules/* libs/*
rm -f ext/opcache/jit/zend_jit_x86.c
rm -f ext/opcache/jit/zend_jit_arm64.c
rm -f ext/opcache/minilua
rm -f Makefile config.cache config.log config.status Makefile.objects Makefile.fragments libtool main/php_config.h main/internal_functions_cli.c main/internal_functions.c Zend/zend_dtrace_gen.h Zend/zend_dtrace_gen.h.bak Zend/zend_config.h
rm -f main/build-defs.h scripts/phpize
rm -f ext/date/lib/timelib_config.h ext/mbstring/libmbfl/config.h ext/oci8/oci8_dtrace_gen.h ext/oci8/oci8_dtrace_gen.h.bak
rm -f scripts/man1/phpize.1 scripts/php-config scripts/man1/php-config.1 sapi/cli/php.1 sapi/cgi/php-cgi.1 sapi/phpdbg/phpdbg.1 ext/phar/phar.1 ext/phar/phar.phar.1
rm -f sapi/fpm/php-fpm.conf sapi/fpm/init.d.php-fpm sapi/fpm/php-fpm.service sapi/fpm/php-fpm.8 sapi/fpm/status.html
rm -f ext/phar/phar.phar ext/phar/phar.php
if test "/usr/local/src/php-8.1.30" != "/usr/local/src/php-8.1.30"; then \
rm -f ext/phar/phar/phar.inc; \
fi
/usr/bin/grep -E define'.*include/php' /usr/local/src/php-8.1.30/configure | /usr/bin/sed 's/.*>//'|xargs rm -f
[root@lnmp php-8.1.30]# cd ..
[root@lnmp src]# rm -rf php-8.1.30/
[root@lnmp src]# sed -i '/php/d' /etc/profile
[root@lnmp src]# rm -rf /usr/local/php/
对于 dnf 包安装的,执行 dnf remove
[root@lnmp ~]# dnf remove -y php*
Make clean 和 Make distclean 的区别?
Clean 只会删除编译过程中生成的临时文件(如 .o目标文件、编译生成的中间文件),但保留 configure脚本生成的配置结果(如 Makefile);如果只是改了源代码,这样就能省很多实践;
DistClean 删除所有编译生成的文件(包括 make clean清理的内容),还会删除 ./configure 脚本生成的所有配置结果(如 Makefile、config.status、config.cache等)。相当于这个环境什么都没装,只是解压了软件包。
Nginx 服务
已安装好 Nginx 服务,并确保启动 80 端口

MySQL 服务
已安装好 MySQL 服务,并确保启动 3306 端口

克隆 CRMEB 源代码
回到要部署项目的 Nginx 服务器,进行代码克隆
[root@lnmp ~]# dnf install git -y # 先安装git工具
[root@lnmp ~]# mkdir /data && cd /data # 创建一个/data目录,准备存放CRMEB源代码
[root@lnmp data]# git clone https://gitee.com/ZhongBangKeJi/CRMEB.git # 克隆CRMEB源代码
修改用户和权限
# 如果是 dnf 安装的 nginx,用户权限改成 nginx:nginx
# 如果是 编译 安装的 nginx,用户权限改成 www:www
[root@lnmp ~]# chown -Rf www:www /data/CRMEB/crmeb
[root@lnmp ~]# chmod 755 -Rf /data/CRMEB/crmeb

部署 PHP 7.4
PHP 的版本要求是 7.4
我们之前安装的 PHP 是 8.1 版本,高了,需要卸载,安装 7.4版本。
PHP 官方版本相对陈旧,对不同的操作系统要求的依赖不尽相同。
为了兼容企业环境,简化依赖与部署,法国一名 PHP 开发者 Remi Collet 维护了 **Remi 仓库。**专为 RHEL/CentOS/Fedora 提供 最新/特定版本 PHP 及扩展。
Remi 仓库支持多版本共存、模块化管理(如 php:remi-7.4),在全球广受欢迎。
配置 PHP Remi 仓库
CentOS Stream 9 默认的 PHP 版本库通常比较新,因此需要使用 Remi 仓库来安装较旧的 PHP 版本。
- 安装 EPEL(Extra Packages for Enterprise Linux)仓库:
dnf install epel-release -y
- 安装 Remi 仓库:
dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm
- 启用 Remi 仓库:
dnf module enable php:remi-7.4 -y
安装 PHP 7.4
- 安装 PHP 7.4:
dnf install php -y
- PHP常用扩展(依赖包)
dnf install php-cli php-fpm php-mysqlnd php-xml php-mbstring php-json php-common php-opcache php-bcmath php-gd -y
- 检查 PHP 版本: 安装完成后,可以通过以下命令检查安装的 PHP 版本:
php -v

可能会遇到
-bash: /usr/local/php/bin/php: No such file or directory
这样的问题
解决方法:
hash -r # 让 bash 忘掉已缓存的路径
php -v # 现在就会用 /usr/bin/php

配置 PHP-FPM
PHP-FPM(FastCGI Process Manager)是 PHP 的官方 FastCGI 进程管理器,提供更高效的进程控制和资源管理。
修改用户,监听地址
[root@lnmp ~]# vim /etc/php-fpm.d/www.conf
20 ; Unix user/group of processes
21 ; Note: The user is mandatory. If the group is not set, the default user's group
22 ; will be used.
23 ; RPM: apache user chosen to provide access to the same directories as httpd
24 user = www # 如果你是编译安装的 nginx,就改成 www;如果你是 dnf 安装的 nginx,那就是 nginx
25 ; RPM: Keep a group allowed to write in log dir.
26 group = www # 如果你是编译安装的nginx,就改成 www;如果你是 dnf 安装的 nginx,那就是 nginx
27
28 ; The address on which to accept FastCGI requests.
29 ; Valid syntaxes are:
30 ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on
31 ; a specific port;
32 ; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on
33 ; a specific port;
34 ; 'port' - to listen on a TCP socket to all addresses
35 ; (IPv6 and IPv4-mapped) on a specific port;
36 ; '/path/to/unix/socket' - to listen on a unix socket.
37 ; Note: This value is mandatory.
38 listen = 0.0.0.0:9000 # 绑定9000端口号,这样即使 PHP-FPM 和 Nginx 不在同一台机器也可以通信
启动 php-fpm 服务
[root@lnmp ~]# systemctl start php-fpm
[root@lnmp ~]# systemctl status php-fpm
[root@lnmp ~]# systemctl enable php-fpm

查看 PHP 9000 端口与 PHP 进程
[root@lnmp ~]# ss -nlutp | grep 9000
[root@lnmp ~]# ss -ant | grep 9000
[root@lnmp ~]# netstat -pantul|grep 9000
[root@lnmp ~]# ps aux|grep php
[root@lnmp ~]# ps -ef|grep php


配置 Nginx + PHP-FPM
配置 Nginx 对接 PHP
我们编译安装的话,一般会选择 /usr/local/nginx/ 作为安装目录。
如果你是 dnf 包安装的话,配置文件一般在 /etc/nginx/ 目录下。
所以根据自己的情况,找到 nginx.conf 配置目录。
源码编译安装 Nginx:
[root@lnmp ~]# find / -name nginx.conf
/usr/lib/sysusers.d/nginx.conf
/usr/local/nginx/conf/nginx.conf
/data/CRMEB/readme/nginx.conf
[root@lnmp ~]# cd /usr/local/nginx/conf/
[root@lnmp conf]# ls
fastcgi.conf mime.types scgi_params.default
fastcgi.conf.default mime.types.default uwsgi_params
fastcgi_params nginx.conf uwsgi_params.default
fastcgi_params.default nginx.conf.bak win-utf
koi-utf nginx.conf.default
koi-win scgi_params
[root@lnmp conf]# cat nginx.conf
worker_processes auto;
events {
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
root html;
location / {
index index.html index.htm;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
[root@lnmp conf]# vim nginx.conf
[root@lnmp conf]# cat nginx.conf
worker_processes auto;
events {
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
root html;
location / {
index index.html index.htm;
}
location ~ \.php$ {
fastcgi_pass 0.0.0.0:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
[root@lnmp conf]#
dnf/yum安装Nginx:
[root@lnmp ~]# cd /etc/nginx
[root@lnmp conf]# grep -Ev '#|^$' nginx.conf.default > nginx.conf
[root@lnmp conf]# vi nginx.cnf
1 worker_processes 1;
2 events {
3 worker_connections 1024;
4 }
5 http {
6 include mime.types;
7 default_type application/octet-stream;
8 sendfile on;
9 keepalive_timeout 65;
10 server {
11 listen 80;
12 server_name localhost;
13 root html; # 暂定根目录为 html
14
15 location / {
16 index index.html index.htm;
17 }
18
19 location ~ \.php$ {
20 fastcgi_pass 0.0.0.0:9000; # 绑定 PHP-FPM
21 fastcgi_index index.php;
22 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
23 include fastcgi_params;
24 }
25
26 error_page 500 502 503 504 /50x.html;
27 location = /50x.html {
28 root html;
29 }
30 }
31 }
重新加载 Nginx
nginx -t
nginx -s reload
添加 demo.php
在 html 目录下,创建一个 demo.php 文件,测试一下
源码编译安装Nginx:
cat >/usr/local/nginx/html/demo.php<<EOF
<?php
phpinfo();
?>
EOF
dnf/yum安装Nginx:
cat >/usr/share/nginx/html/demo.php<<EOF
<?php
phpinfo();
?>
EOF
测试 phpinfo()
打开浏览器,输入 http://IP地址/demo.php
http://192.168.88.101/demo.php

配置 Nginx 对接 CRMEB 电商系统
我们编译安装的话,默认都会选择 /usr/local/nginx/ 作为安装目录;
如果你是 dnf/yum 安装的话,配置文件一般在 /etc/nginx/ 目录下;
所以根据自己的情况,查找 nginx.conf 配置。
指定网站目录并配置伪静态
伪静态作用:
伪静态把“/index.php?s=xxx”这种带问号的动态地址伪装成“/xxx.html”的静态路径,让搜索引擎认、缓存认、用户也认,同时保证所有请求仍能悄悄交给 PHP 统一入口处理,既好看又不掉链子。
[root@lnmp ~]# vim /usr/local/nginx/conf/nginx.conf
worker_processes auto;
events {
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
root /data/CRMEB/crmeb/public; # 配置CRMEB根目录
location / {
index index.html index.htm index.php; # 增加index.php首页
if (!-e $request_filename) { # 伪静态处理
rewrite ^(.*)$ /index.php?s=$1 last;
break;
}
}
location ~ \.php$ {
# root html;
fastcgi_pass 0.0.0.0:9000; # 绑定 PHP-FPM
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
[root@lnmp ~]# vim /usr/local/nginx/conf/nginx.conf
[root@lnmp ~]# cat /usr/local/nginx/conf/nginx.conf
worker_processes auto;
events {
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
root /data/CRMEB/crmeb/public;
location / {
index index.html index.htm index.php;
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
break;
}
}
location ~ \.php$ {
fastcgi_pass 0.0.0.0:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
[root@lnmp ~]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@lnmp ~]#
重载或重启Nginx
nginx -s reload
或者
systemctl restart nginx
配置 MySQL sql_mode=NO_ENGINE_SUBSTITUTION
sql_mode=NO_ENGINE_SUBSTITUTION
LNMP 环境常见的生产级配置,目的就是:严格、安全、不允许隐式替换引擎。
不让 MySQL 偷偷替换存储引擎,有错就直接报错;存储引擎不存在时,直接报错,不偷偷替换。
生产环境 必须开启,保证行为可预期。
vim /etc/my.cnf
sql_mode=NO_ENGINE_SUBSTITUTION
[root@lnmp ~]# cat /etc/my.cnf
[mysqld]
port=3306
basedir=/export/server/mysql
datadir=/export/server/mysql/data
socket=/tmp/mysql.sock
character_set_server=utf8
collation-server=utf8_unicode_ci
[root@lnmp ~]# vim /etc/my.cnf
[root@lnmp ~]# cat /etc/my.cnf
[mysqld]
port=3306
basedir=/export/server/mysql
datadir=/export/server/mysql/data
socket=/tmp/mysql.sock
character_set_server=utf8
collation-server=utf8_unicode_ci
sql_mode=NO_ENGINE_SUBSTITUTION
[root@lnmp ~]#
重启 MySQL
systemctl restart mysqld
[root@lnmp ~]# systemctl restart mysqld
[root@lnmp ~]# systemctl status mysqld
● mysqld.service - MySQL Server
Loaded: loaded (/etc/systemd/system/mysqld.service; enabled; preset: disabl>
Active: active (running) since Thu 2025-12-11 21:18:56 CST; 4s ago
Process: 213159 ExecStart=/export/server/mysql/bin/mysqld --daemonize --pid->
Main PID: 213162 (mysqld)
Tasks: 38 (limit: 48693)
Memory: 369.5M
CPU: 1.015s
CGroup: /system.slice/mysqld.service
└─213162 /export/server/mysql/bin/mysqld --daemonize --pid-file=/ex>
Dec 11 21:18:55 lnmp mysqld[213162]: 2025-12-11T13:18:55.505777Z 0 [System] [MY->
Dec 11 21:18:55 lnmp mysqld[213162]: 2025-12-11T13:18:55.510213Z 0 [Warning] [MY>
Dec 11 21:18:55 lnmp mysqld[213162]: 2025-12-11T13:18:55.510310Z 0 [Warning] [MY>
Dec 11 21:18:55 lnmp mysqld[213162]: 2025-12-11T13:18:55.525063Z 1 [System] [MY->
Dec 11 21:18:55 lnmp mysqld[213162]: 2025-12-11T13:18:55.798965Z 1 [System] [MY->
Dec 11 21:18:56 lnmp mysqld[213162]: 2025-12-11T13:18:56.064294Z 0 [Warning] [MY>
Dec 11 21:18:56 lnmp mysqld[213162]: 2025-12-11T13:18:56.064468Z 0 [System] [MY->
Dec 11 21:18:56 lnmp mysqld[213162]: 2025-12-11T13:18:56.093311Z 0 [System] [MY->
Dec 11 21:18:56 lnmp mysqld[213162]: 2025-12-11T13:18:56.093395Z 0 [System] [MY->
Dec 11 21:18:56 lnmp systemd[1]: Started MySQL Server.
[root@lnmp ~]# mysql -uroot -pMySQL@666
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.43 MySQL Community Server - GPL
Copyright (c) 2000, 2025, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)
mysql>
上线 CRMEB 电商系统
访问 http://IP地址,出现安装界面,按照步骤安装完成即可访问
或者
http://192.168.88.101/install/index.php


mysql -uroot -pMySQL@666

数据库用户名 root
数据库密码用之前自定义的 MySQL@666
数据库名用默认的 crmeb
高级设置,确认一下默认的信息即可
管理员信息
管理员账号用默认的 admin
管理员密码自定义,比如 admin@666




至此,基于LNMP企业架构部署CRMEB电商系统成功!
为了您站点的安全,安装完成后即可将网站根目录下的“install”文件夹下的所有文件删除,防止重复安装。
[root@lnmp public]# pwd
/data/CRMEB/crmeb/public
[root@lnmp public]# ls
admin install product_migration.xlsx static
assets install.lock README.md statics
favicon.ico mobile.html robots.txt upgrade
index.html nginx.htaccess router.php uploads
index.php pages service_pay_result.html
[root@lnmp public]# rm -rf install
[root@lnmp public]# ls
admin install.lock README.md statics
assets mobile.html robots.txt upgrade
favicon.ico nginx.htaccess router.php uploads
index.html pages service_pay_result.html
index.php product_migration.xlsx static
[root@lnmp public]#
通过浏览器http://IP地址,即可访问。



后端访问地址:http://IP地址/admin
后端登录账号密码,就是安装阶段设置的admin和密码





查看MySQL数据库的数据变化
[root@lnmp ~]# mysql -uroot -pMySQL@666
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 228
Server version: 8.0.43 MySQL Community Server - GPL
Copyright (c) 2000, 2025, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| crmeb |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> use crmeb
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+-----------------------------------+
| Tables_in_crmeb |
+-----------------------------------+
| eb_agent_level |
| eb_agent_level_task |
| eb_agent_level_task_record |
| eb_agreement |
| eb_app_version |
| eb_article |
| eb_article_category |
| eb_article_content |
| eb_auxiliary |
| eb_cache |
| eb_capital_flow |
| eb_category |
| eb_delivery_service |
| eb_division_agent_apply |
| eb_diy |
| eb_express |
| eb_lang_code |
| eb_lang_country |
| eb_lang_type |
| eb_live_anchor |
| eb_live_goods |
| eb_live_room |
| eb_live_room_goods |
| eb_luck_lottery |
| eb_luck_lottery_record |
| eb_luck_prize |
| eb_member_card |
| eb_member_card_batch |
| eb_member_right |
| eb_member_ship |
| eb_message_system |
| eb_other_order |
| eb_other_order_status |
| eb_out_account |
| eb_out_interface |
| eb_page_categroy |
| eb_page_link |
| eb_qrcode |
| eb_routine_scheme |
| eb_shipping_templates |
| eb_shipping_templates_free |
| eb_shipping_templates_no_delivery |
| eb_shipping_templates_region |
| eb_sms_record |
| eb_spread_apply |
| eb_store_activity |
| eb_store_advance |
| eb_store_bargain |
| eb_store_bargain_user |
| eb_store_bargain_user_help |
| eb_store_cart |
| eb_store_category |
| eb_store_combination |
| eb_store_coupon_issue |
| eb_store_coupon_issue_user |
| eb_store_coupon_product |
| eb_store_coupon_user |
| eb_store_integral |
| eb_store_integral_order |
| eb_store_integral_order_status |
| eb_store_order |
| eb_store_order_cart_info |
| eb_store_order_economize |
| eb_store_order_invoice |
| eb_store_order_refund |
| eb_store_order_status |
| eb_store_pink |
| eb_store_product |
| eb_store_product_attr |
| eb_store_product_attr_result |
| eb_store_product_attr_value |
| eb_store_product_cate |
| eb_store_product_coupon |
| eb_store_product_description |
| eb_store_product_label |
| eb_store_product_label_cate |
| eb_store_product_log |
| eb_store_product_param |
| eb_store_product_protection |
| eb_store_product_relation |
| eb_store_product_reply |
| eb_store_product_rule |
| eb_store_product_virtual |
| eb_store_seckill |
| eb_store_seckill_time |
| eb_store_service |
| eb_store_service_feedback |
| eb_store_service_log |
| eb_store_service_record |
| eb_store_service_speechcraft |
| eb_store_visit |
| eb_system_admin |
| eb_system_attachment |
| eb_system_attachment_category |
| eb_system_city |
| eb_system_config |
| eb_system_config_tab |
| eb_system_crud |
| eb_system_crud_data |
| eb_system_crud_list |
| eb_system_event |
| eb_system_event_data |
| eb_system_file |
| eb_system_file_info |
| eb_system_group |
| eb_system_group_data |
| eb_system_log |
| eb_system_menus |
| eb_system_notice |
| eb_system_notice_admin |
| eb_system_notification |
| eb_system_pem |
| eb_system_role |
| eb_system_route |
| eb_system_route_cate |
| eb_system_sign_reward |
| eb_system_storage |
| eb_system_store |
| eb_system_store_staff |
| eb_system_ticket |
| eb_system_timer |
| eb_system_user_level |
| eb_upgrade_log |
| eb_user |
| eb_user_address |
| eb_user_bill |
| eb_user_brokerage |
| eb_user_brokerage_frozen |
| eb_user_cancel |
| eb_user_enter |
| eb_user_extract |
| eb_user_friends |
| eb_user_group |
| eb_user_invoice |
| eb_user_label |
| eb_user_label_relation |
| eb_user_level |
| eb_user_money |
| eb_user_notice |
| eb_user_notice_see |
| eb_user_recharge |
| eb_user_search |
| eb_user_sign |
| eb_user_spread |
| eb_user_visit |
| eb_wechat_key |
| eb_wechat_media |
| eb_wechat_message |
| eb_wechat_news_category |
| eb_wechat_qrcode |
| eb_wechat_qrcode_cate |
| eb_wechat_qrcode_record |
| eb_wechat_reply |
| eb_wechat_user |
+-----------------------------------+
154 rows in set (0.00 sec)
mysql>



拓展:忘记管理员 admin 的密码该怎么办?

解决方法:
确认加密方式
cd /data/CRMEB/crmeb
cat app/services/system/admin/SystemAdminServices.php | grep -A 15 "verifyLogin\|passwordHash"|grep password

bcrypt 加密
| 攻击方式 | 对 MD5 | 对 bcrypt |
|---|---|---|
| 彩虹表 | 秒破(常见密码有预计算表) | 无效(每个 salt 都不同) |
| GPU 暴力破解 | RTX 4090 可达 800亿次/秒 | 同硬件仅 1万次/秒(成本=10) |
| 8位复杂密码 | 几小时破解 | 数百年 |
| 成本升级 | 无法升级,只能换算法 | 直接改成本因子,重新哈希即可 |
关键命令:
# === 第1步:生成 bcrypt 哈希(把 admin2026 换成你要的密码)===
cd /data/CRMEB/crmeb && php -r "echo password_hash('admin2026', PASSWORD_BCRYPT) . PHP_EOL;"
# === 第2步:更新数据库(把单引号里的哈希替换成上面输出的)===
mysql -u root -pMySQL@666 -e "USE crmeb; UPDATE eb_system_admin SET pwd = '\$2y\$10\$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' WHERE account = 'admin';"
# === 第3步:清缓存 ===
rm -rf /data/CRMEB/crmeb/runtime/* && systemctl restart php-fpm
# === 第4步:查看密码是否改成功 ===
mysql -u root -pMySQL@666 -D crmeb -e "SELECT account, pwd, status, is_del FROM eb_system_admin WHERE account = 'admin';"
# === 第5步:清除浏览器缓存再登录 ===
按 Ctrl + Shift + Delete 清除浏览器缓存,访问 http://IP地址/admin,用 admin / admin2026 登录。



至此,重置管理员 admin 密码成功!
拓展:新增子配置目录 + 子配置文件
[root@lnmp ~]# mkdir -p /usr/local/nginx/conf/conf.d
[root@lnmp ~]# vim /usr/local/nginx/conf/nginx.conf
[root@lnmp ~]# cat /usr/local/nginx/conf/nginx.conf
worker_processes auto;
events {
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
include /usr/local/nginx/conf/conf.d/*.conf;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
root /data/CRMEB/crmeb/public;
location / {
index index.html index.htm index.php;
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
break;
}
}
location ~ \.php$ {
fastcgi_pass 0.0.0.0:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
[root@lnmp ~]# ls -dl /usr/local/nginx/conf/conf.d/
drwxr-xr-x 2 root root 6 Mar 25 11:23 /usr/local/nginx/conf/conf.d/
[root@lnmp ~]# chown www:www /usr/local/nginx/conf/conf.d
[root@lnmp ~]# ls -dl /usr/local/nginx/conf/conf.d/
drwxr-xr-x 2 www www 6 Mar 25 11:23 /usr/local/nginx/conf/conf.d/
[root@lnmp ~]# vim /usr/local/nginx/conf/conf.d/game_2026.conf
[root@lnmp ~]# cat /usr/local/nginx/conf/conf.d/game_2026.conf
server {
listen 2026;
server_name localhost;
root /data/games;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源缓存优化
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|ttf)$ {
expires 7d;
access_log off;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
}
[root@lnmp ~]# mkdir -p /data/games
[root@lnmp ~]# ls -dl /data/games/
drwxr-xr-x 2 root root 6 Mar 25 11:25 /data/games/
[root@lnmp ~]# chown -Rf www:www /data/games/
drwxr-xr-x 2 www www 6 Mar 25 11:25 /data/games/
[root@lnmp ~]# ls -dl /data/games/
drwxr-xr-x 2 www www 24 Mar 25 11:27 /data/games/
[root@lnmp ~]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@lnmp ~]# nginx -s reload
[root@lnmp ~]# echo "games test" > /data/games/index.html
[root@lnmp ~]# cat /data/games/index.html
games test
[root@lnmp ~]#

[root@lnmp ~]# cd /data/games/
[root@lnmp games]# ls
index.html
[root@lnmp games]# rm -rf *
[root@lnmp games]# mv /root/jaking-cloud-platform.tar.gz ./
[root@lnmp games]# ls
jaking-cloud-platform.tar.gz
[root@lnmp games]# tar xf jaking-cloud-platform.tar.gz
[root@lnmp games]# ls
404.html css index.html js screenshots
backup images jaking-cloud-platform.tar.gz link yxmb
[root@lnmp games]# netstat -pantul|grep 2026
tcp 0 0 0.0.0.0:2026 0.0.0.0:* LISTEN 949/nginx: master p
[root@lnmp games]#

只改主配置
[root@lnmp html]# cat /usr/local/nginx/conf/nginx.conf
worker_processes auto;
events {
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name 192.168.88.101;
root /data/CRMEB/crmeb/public;
location / {
index index.html index.htm index.php;
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
break;
}
}
location ~ \.php$ {
fastcgi_pass 0.0.0.0:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
# root html;
}
}
server {
listen 8080;
server_name 192.168.88.101;
root /usr/local/nginx/html/itheimadevops;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
# root html;
index index.html index.htm;
}
}
}
[root@lnmp html]#
总结
1、掌握 MySQL、Nginx 的部署和配置步骤
2、掌握 PHP-FPM 和 Nginx 进行联调需要在 nginx.cnf 修改的关键配置
3、熟悉 LNMP 从0到1的搭建思路