使用 Nginx 部署 PHP 项目

Nginx(读作 “engine-x”)是一款高性能的 Web 服务器 + 反向代理服务器。Nginx 不会直接执行 PHP 脚本。它只懂得发送文件、转发请求,不会解析 .php 文件里的逻辑代码。所以 Nginx 必须结合 PHP 解析器才能很好的处理 PHP 请求,而且 NGINX 也只懂得如何响应和转发请求,它也不太懂如何管理 PHP 进程以及调用,连接 nginx 和 PHP 解析器的桥梁则是 FastCGI 协议,这里简单介绍一下 FastCGI ,FastCGI(Fast Common Gateway Interface)
是一种用于 Web 服务器(Nginx 或 Apache)与应用程序(如 PHP、Python、Perl)之间通信的协议。而 PHP-FPM 则是 FastCGI 的一种具体实现,拥有处理 Web 服务器和 PHP 应用程序之间的通信。

工作原理

1
2
3
4
5
6
7
8
9
10
11
12
13

浏览器请求 index.php

Nginx 收到请求

Nginx 将请求转发给 PHP-FPM(FastCGI 协议)

PHP-FPM 调用 PHP 解释器执行代码

执行结果(HTML)返回给 Nginx

Nginx 返回响应给浏览器

构建应用程序

很多教程都按照部署的顺序进行讲解,首先讲解 Nginx 的部署,PHP-FPM 的安装,PHP 环境安装等等的顺序进行讲解,并没有将各部件之间的关系讲解清楚。所以我打算以开发的角度讲解如何使用 Nginx 部署 PHP 应用程序。首先讲解如何构建一个简单的 php 程序,然后运行程序需要的环境,然后讲解如何透过 FastCGI 将其封装成为一个 web 服务,最后讲解如何借助 nginx 的能力将其完善成为一个完整的 web 应用。

let’s start from small, 一个经典的 hello world 程序

第一个 PHP 脚本:hello.php

1
2
3
4
5
6
7

<?php

echo "Hello World!";

?>

要执行字段 php 脚本,我们需要安装 php 基础包,用于解释和执行 php 脚本。这里以 REHL 系列 linux 为例,讲解如何安装 php 基础包:

1
2
3

sudo dnf -y php

注意:在安装 php 基础包的时候就自动帮我们安装了 php-fpm, 后续我们需要使用到 php-fpm 的时候就不必再次安装了

接着我们使用 php 脚本解析执行器来运行这段脚本

1
2
3
4
5

user@server $ php hello.php

Hello World!

一个简单的 php 程序就完成了,接着我们在此基础上完善一下应用程序,创建一个完整的 index.php, 里面包括大部分的 web 元素,超链接,图片,css, javascript 等等。将其保存为 index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

<?php
// index.php 示例
$title = "欢迎来到我的网站";
$subtitle = "一个由 PHP 动态生成的页面";
$date = date("Y年m月d日 H:i:s");
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title><?php echo $title; ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- CSS 样式 -->
<style>
body {
font-family: "Microsoft YaHei", sans-serif;
margin: 0;
background: #f7f8fa;
color: #333;
}
header {
background: #0078ff;
color: white;
padding: 20px;
text-align: center;
}
nav {
background: #005fcc;
display: flex;
justify-content: center;
gap: 20px;
padding: 10px 0;
}
nav a {
color: white;
text-decoration: none;
font-weight: bold;
}
nav a:hover {
text-decoration: underline;
}
main {
max-width: 900px;
margin: 40px auto;
background: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
}
h1 { color: #0078ff; }
img {
max-width: 100%;
border-radius: 8px;
}
.gallery {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.gallery img {
width: 30%;
transition: transform .2s;
}
.gallery img:hover {
transform: scale(1.05);
}
footer {
background: #222;
color: #ccc;
text-align: center;
padding: 15px 0;
margin-top: 40px;
}
button {
background: #0078ff;
color: white;
border: none;
padding: 10px 16px;
border-radius: 6px;
cursor: pointer;
}
button:hover {
background: #005fcc;
}
</style>
</head>
<body>

<header>
<h1><?php echo $title; ?></h1>
<p><?php echo $subtitle; ?></p>
</header>

<nav>
<a href="#home">首页</a>
<a href="#gallery">图片</a>
<a href="#about">关于我们</a>
<a href="#contact">联系我们</a>
</nav>

<main id="home">
<h2>欢迎光临!</h2>
<p>当前服务器时间:<strong><?php echo $date; ?></strong></p>
<p>这是一个包含 PHP、HTML、CSS、JavaScript 的完整网页示例。你可以在此基础上扩展自己的功能。</p>

<hr>

<section id="gallery">
<h3>📸 图片展示</h3>
<div class="gallery">
<img src="https://picsum.photos/300/200?random=1" alt="图片1">
<img src="https://picsum.photos/300/200?random=2" alt="图片2">
<img src="https://picsum.photos/300/200?random=3" alt="图片3">
</div>
</section>

<hr>

<section id="about">
<h3>💡 关于我们</h3>
<p>我们是一家专注于 Web 技术与网络加速的团队。我们的目标是让全球访问更快速、更稳定。</p>
<p><a href="https://www.php.net/" target="_blank">了解更多 PHP 技术 →</a></p>
</section>

<hr>

<section id="contact">
<h3>📬 联系我们</h3>
<form id="contactForm">
<label>姓名:</label><br>
<input type="text" id="name" placeholder="请输入您的名字" required><br><br>
<label>留言:</label><br>
<textarea id="message" rows="4" cols="40" placeholder="请输入留言内容" required></textarea><br><br>
<button type="submit">提交留言</button>
</form>
<p id="formResponse" style="color:green; display:none;">✅ 已收到您的留言,谢谢!</p>
</section>
</main>

<footer>
<p>© <?php echo date("Y"); ?> 我的 PHP 网站 | Powered by PHP & Nginx</p>
</footer>

<!-- JavaScript -->
<script>
document.getElementById("contactForm").addEventListener("submit", function(e) {
e.preventDefault();
document.getElementById("formResponse").style.display = "block";
});

// 动态按钮提示
document.addEventListener("DOMContentLoaded", () => {
const btn = document.createElement("button");
btn.textContent = "点击显示当前时间";
btn.onclick = () => alert("当前时间是:" + new Date().toLocaleString());
document.body.appendChild(btn);
});
</script>

</body>
</html>

使用 php 脚本解析执行器测试一下脚本,并将内容输出为 index.html, 打开 index.html 就能看到我们制作的首页的效果。

1
2
3

user@server $ php hello.php > index.html

浏览器打开 index.html,就能看到首页效果了。

Hello world php demo

这样一个包含 css, javascipt, 超文本等等 web 元素的首页就制作完成了,如果我们要进一步探索,可以将 css 样式做成外部样式,javascript 都移动到 index.php 外部。但是这些静态文件的管理就属于 nginx 所擅长的了,所以这里不继续展开了。另外我们也可以加入 php 连接数据库脚本,这样就更加完善了。由于这是一篇讲解 php 应用部署的文章,所以这部分也不进一步展开讲解了。

使用 PHP-cli 内置 web server 运行 index.html

PHP 内置了一个轻量开发服务器。适合快速测试或本地开发使用,不适合生产环境。我们可以使用它来测试我们的 index.php 脚本,这样就不用手动拷贝生成的 index.html 查看效果了。

1
2
3

php -S 0.0.0.0:8080 -t /var/www/html

🔹 启动一个 PHP 内置开发服务器
🔹 监听 0.0.0.0:8080 所有网卡请求(内网 + 外网)
🔹 将 /var/www/html 作为网站根目录,
🔹 静态文件直接返回,.php 文件交给 PHP 解析执行

这样我们将 index.php 放入到/var/www/html 文件夹下,然后使用浏览器打开 http://your_server_id:8080/index.php 即可看到首页内容。

使用 PHP-FPM 将 php 应用包装成一个 web 应用

PHP-cli 内置 web server 只适合在测试和本地开发中使用,在生产环境我们还是要使用 PHP-FPM 将 php 应用包装成为一个 web 应用。

CGI(Common Gateway Interface)全称是“通用网关接口”,是一种让客户端(web 浏览器)与 Web 服务器(nginx 等)程序进行通信(数据传输)的协议。FastCGI(Fast Common Gateway Interface)全称是“快速通用网关接口”是通用网关接口(CGI)的增强版本,由 CGI 发展改进而来,主要用来提高 CGI 程序性能,
类似于 CGI,FastCGI 也是一种让交互程序与 Web 服务器通信的协议。

安装与配置 PHP-FPM

PHP 在 5.3.3 之后已经把 php-fpm 并入到 php 的核心代码中了。 所以 php-fpm 不需要单独的下载安装。由于是关联安装的,所以这里也不用太担心 php 与 php-fpm 的版本问题。

运行rpm -ql php-fpm, 可以看到 PHP-FPM 的主配置文件是 /etc/php-fpm.conf

首先我们来直接启动 php-fpm

1
2
3
4
5
6

user@server $ sudo php-fpm

[01-Nov-2025 16:26:26] ERROR: unable to bind listening socket for address '/run/php-fpm/www.sock': No such file or directory (2)
[01-Nov-2025 16:26:26] ERROR: FPM initialization failed

此时系统会报错,原因是 php-fpm 的配置文件中指定的 user 默认为 apache, 而 apache 用户没有权限在/run/php-fpm 目录下创建 www.sock 文件

1
2
3
4

user@server $ grep "^user" /etc/php-fpm.d/www.conf
user = apache

由于我们要使用 Nginx 结合 php-fpm 来部署 PHP 应用,为了避免在 SELinux 开启以后的一些权限问题,我让 php-fpm 以 Nginx 用户运行,此时我们修改 www.conf 将用户设置为 nginx, 用户组设置为 nginx。然后为 nginx 用户创建/run/php-fpm 文件夹。

1
2
3
4

sudo mkdir -p /run/php-fpm
sudo chown -R nginx:nginx /run/php-fpm

再次以 nginx 身份启动 php-fpm,即可成功启动 php-fpm 了

1
2
3

user@server $ sudo -u nginx php-fpm

为了验证此步骤是否成功,我们可以安装 fastcgi 测试工具 fcgi

1
2
3

sudo dnf install fcgi

然后切换为 nginx 用户

1
sudo -u nginx bash

执行测试脚本,如果能正确的生成首页的 html 内容则表示 php-fpm 配置成功。

1
2
3
4
5
6

SCRIPT_FILENAME=/var/www/html/index.php \
REQUEST_METHOD=GET \
QUERY_STRING="" \
cgi-fcgi -bind -connect /run/php-fpm/www.sock

将 php-fpm 设置为开机自启动

首先将之前手动启动的 php-fpm 关闭

1
2
3

sudo kill -QUIT $(cat /run/php-fpm/php-fpm.pid)

设置 php-fpm 为开机自启动

1
2
3
4
5
6
7
8
9
10

# 设置为开机自启动
sudo systemctl enable php-fpm

# 启动 php-fpm
sudo systemctl start php-fpm

# 查看 php-fpm状态
systemctl status php-fpm

至此 php-fpm 就安装并配置完成,如果有些参数需要调整,可以阅读 php-fpm 相关文档进行调整。

安装并配置 Nginx

安装 nginx

1
2
3
4
5
6
7
8
9
10

# 安装nginx
dnf install -y nginx

# 设置为开机启动,并立即启动nginx
systemctl enable --now nginx

# 查看nginx状态
systemctl status nginx

转发请求给 PHP-FPM

在 /etc/nginx/conf.d 新增一个配置文件,例如:your_domain.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# 443端口:真正提供服务
server {

server_name www.your_domain.com;
listen 443 ssl;

root /var/www/html/;
index index.html index.htm index.php;

location / {
# 这行配置是 Nginx 与 PHP 应用(如 WordPress、Laravel、Discuz 等)配合时最常见的“URL 重写”写法之一。
# 按顺序检查文件是否存在,找到第一个存在的就使用它,如果都不存在,就使用最后一个 fallback(回退)目标即/index.php?q=$uri&$args。
try_files $uri $uri/ /index.php?q=$uri&$args;
}

# ~ 表示使用 正则匹配;\.php?.*$ 这个正则可以匹配所有以 .php 结尾的路径(以及可能带参数的形式);
location ~ \.php?.*$ {
# Nginx 会将请求内容(URL、Header、POST 数据等)打包成 FastCGI 请求,
# 然后通过这个 socket 发给 PHP-FPM 进程,让它去执行 PHP 脚本。
# 它在 PHP-FPM 的 www.conf 中由 listen = /run/php-fpm/www.sock 决定,这里 Nginx 的配置需要与其相匹配。
fastcgi_pass unix:/run/php-fpm/www.sock;
# 当请求路径是目录时(例如 /blog/),
# 如果目录下有 index.php,则默认执行该文件。
fastcgi_index index.php;
# 这是最关键的一行, “你要执行的 PHP 文件的完整绝对路径是:$document_root + $fastcgi_script_name”
# 例如:在本例中 $document_root 是 /var/www/html (由 root 指令决定)$fastcgi_script_name 是 index.php
# PHP-FPM 收到这个路径后,加载并执行/var/www/html/index.php 这个脚本文件。
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# 导入一份系统默认的 FastCGI 参数模板文件,
include fastcgi_params;
}

ssl_certificate /etc/letsencrypt/live/www.your_domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.your_domain.com/privkey.pem;

include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}

# 80端口:只负责跳转到HTTPS
server {

listen 80;
server_name www.your_domain.com;
return 301 https://$host$request_uri;

}

这是一个完整的使用域名和 https 方式访问 php 应用的示例 nginx 配置文件。关于如何申请免费的 ssl 证书和配置 ssl 证书可以参考我之前的文章如何在 Almalinux 上为 Nginx 安装 TLS/SSL 证书并开启自动续订 或者 一篇文章搞懂 HTTPS 协议。这里重点关注两个 location 部分的配置, 注释部分已经做了详细解释。

另外需要加一条将 DNS 解析将域名和服务器公网 ip 进行绑定,这样通过域名方式就可以访问 php 应用了,在本例中为https://www.your_domain.com/index.php

参考文档

第一课:服务器环境部署(Nginx+PHP-FPM)

关于 CGI 和 FastCGI 的理解

PHP-FPM 详解

作者

鹏叔

发布于

2025-11-01

更新于

2025-11-01

许可协议

评论