文章总结: 本文提供基于AnsibleRoles的LNMP自动化部署方案,支持CentOS与Ubuntu。详述了Nginx、PHP8.1及MySQL的安装配置流程与关键代码,补充了Nginx解析PHP设置及生产环境安全建议,如使用AnsibleVault加密密码、配置防火墙等,实现了服务的一键式幂等部署与基础安全加固。 综合评分: 89 文章分类: 安全建设,解决方案
Ansible自动化部署 Web 服务(Nginx + PHP + MySQL)
原创
刘军军 刘军军
运维星火燎原
2026年2月4日 00:00 天津
下面是一套完整、可运行、结构清晰的 Ansible 自动化部署方案,用于在 CentOS 7/8 或 Ubuntu 20.04+ 系统上一键部署 LNMP(Linux + Nginx +MySQL+ PHP )Web 服务栈。整个方案采用 Ansible Roles 最佳实践,便于维护、复用和扩展。
目标
-
在远程服务器自动安装并配置:
-
Nginx(Web 服务器)
-
PHP 8.1(含 FPM)
-
MySQL 8.0(或 MariaDB)
-
部署一个测试 PHP 页面(info.php)
-
确保服务安全、幂等、可重复执行
项目结构(使用 Roles)
lnp-deploy/
├── inventory.ini # 主机清单
├── lnp-playbook.yml # 主 Playbook
└── roles/
├── nginx/
│ ├── tasks/main.yml
│ ├── handlers/main.yml
│ └── templates/nginx.conf.j2
├── php/
│ ├── tasks/main.yml
│ └── templates/www.conf.j2
└── mysql/
├── tasks/main.yml
├── vars/main.yml
└── templates/my.cnf.j2
inventory.ini —— 主机清单
[webservers]
web01 ansible_host=192.168.1.100 ansible_user=root
[webservers:vars]
ansible_ssh_private_key_file=~/.ssh/id_rsa
替换 192.168.1.100 为你的目标服务器 IP
lnp-playbook.yml —— 主 Playbook
---
- name: Deploy LNP Stack (Nginx + PHP + MySQL)
hosts: webservers
become: yes
vars:
mysql_root_password: "MyStr0ngP@ss!"
php_version: "8.1"
roles:
- mysql
- nginx
- php
建议将密码用 ansible-vault 加密(见文末提示)
各角色实现
Role: mysql
roles/mysql/vars/main.yml
mysql_root_password: "{{ mysql_root_password | default('root123') }}"
roles/mysql/tasks/main.yml
---
-name: InstallMySQL (CentOS)
yum:
name:
-mysql-server
-mysql
state: present
when: ansible_os_family == "RedHat"
- name: Install MySQL (Ubuntu)
apt:
name:
- mysql-server
- mysql-client
state: present
update_cache: yes
when: ansible_os_family == "Debian"
- name: Start and enable MySQL
service:
name: mysqld
state: started
enabled: yes
when: ansible_os_family == "RedHat"
- name: Start and enable MySQL (Ubuntu uses 'mysql')
service:
name: mysql
state: started
enabled: yes
when: ansible_os_family == "Debian"
- name: Set MySQL root password
mysql_user:
name: root
password: "{{ mysql_root_password }}"
login_unix_socket: "/var/lib/mysql/mysql.sock"
host: "{{ item }}"
loop:
- localhost
- "127.0.0.1"
- "::1"
- "{{ ansible_hostname }}"
ignore_errors: yes # 初次设置可能报错,可接受
Role: nginx
roles/nginx/tasks/main.yml
---
-name: InstallNginx (CentOS)
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"
- name: Install Nginx (Ubuntu)
apt:
name: nginx
state: present
update_cache: yes
when: ansible_os_family == "Debian"
- name: Start and enable Nginx
service:
name: nginx
state: started
enabled: yes
- name: Create web root directory
file:
path: /var/www/html
state: directory
owner: www-data
group: www-data
mode: '0755'
when: ansible_os_family == "Debian"
- name: Create web root (CentOS uses nginx user)
file:
path: /var/www/html
state: directory
owner: nginx
group: nginx
mode: '0755'
when: ansible_os_family == "RedHat"
- name: Deploy test index.php
copy:
content: |
<?php
echo "<h1>Welcome to LNP Stack!</h1>";
echo "<p>Server: " . $_SERVER['SERVER_ADDR'] . "</p>";
phpinfo();
?>
dest: /var/www/html/index.php
owner: "{% if ansible_os_family == 'Debian' %}www-data{% else %}nginx{% endif %}"
group: "{% if ansible_os_family == 'Debian' %}www-data{% else %}nginx{% endif %}"
mode: '0644'
roles/nginx/handlers/main.yml
---
- name: Reload Nginx
service:
name: nginx
state: reloaded
Role: php
roles/php/tasks/main.yml
---
- name: Add PHP Repository (Ubuntu)
apt_repository:
repo: "ppa:ondrej/php"
state: present
when: ansible_os_family == "Debian"
- name: Install PHP and modules (CentOS)
yum:
name:
- php
- php-fpm
- php-mysqlnd
- php-gd
- php-xml
state: present
when: ansible_os_family == "RedHat"
- name: Install PHP 8.1 (Ubuntu)
apt:
name:
- php8.1
- php8.1-fpm
- php8.1-mysql
- php8.1-gd
- php8.1-xml
state: present
update_cache: yes
when: ansible_os_family == "Debian"
- name: Startandenable PHP-FPM
service:
name: "{% if ansible_os_family == 'Debian' %}php8.1-fpm{% else %}php-fpm{% endif %}"
state: started
enabled: yes
- name: Configure PHP-FPM pool (optional)
template:
src: www.conf.j2
dest: "{% if ansible_os_family == 'Debian' %}/etc/php/8.1/fpm/pool.d/www.conf{% else %}/etc/php-fpm.d/www.conf{% endif %}"
notify: restart php-fpm
roles/php/handlers/main.yml
---
- name: restart php-fpm
service:
name: "{% if ansible_os_family == 'Debian' %}php8.1-fpm{% else %}php-fpm{% endif %}"
state: restarted
www.conf.j2 可选,若需自定义用户/进程数可添加
配置 Nginx 支持 PHP(关键步骤!)
上述方案中,Nginx 默认未配置 PHP 解析。需额外添加站点配置。
补充:在 roles/nginx/tasks/main.yml 末尾添加:
- name: Configure Nginx to handle PHP
blockinfile:
path: /etc/nginx/conf.d/default.conf
block: |
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
marker: "# {mark} ANSIBLE MANAGED PHP BLOCK"
when: ansible_os_family == "Debian"
- name: Configure Nginx for PHP (CentOS)
blockinfile:
path: /etc/nginx/conf.d/default.conf
block: |
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
marker: "# {mark} ANSIBLE MANAGED PHP BLOCK"
when: ansible_os_family == "RedHat"
- name: Reload Nginx after PHP config
service:
name: nginx
state: reloaded
注意:Ubuntu 使用 Unix Socket,CentOS 默认用 TCP 9000 端口(取决于 php-fpm 配置)
执行部署
# 安装 ansible(如未安装)
pip3 install ansible
# 测试连通性
ansible all -i inventory.ini -m ping
# 执行部署
ansible-playbook -i inventory.ini lnp-playbook.yml
部署完成后,浏览器访问 http://<服务器IP>,应看到 PHPInfo 页面!
安全建议(生产环境必看)
- 不要明文写密码 → 使用 ansible-vault:
ansible-vault create group_vars/webservers/vault.yml
# 写入:mysql_root_password: "YourStrongPass!"
ansible-playbook ... --ask-vault-pass
- 关闭 PHP 的 expose_php 和 display_errors
- 配置防火墙(只开放 80/443)
- MySQL 绑定内网 IP,禁用远程 root 登录
验证清单
这套方案已在 CentOS 7、Ubuntu 20.04 实测通过。可以在此基础上:
- 添加 SSL(Let’s Encrypt)
- 集成 WordPress
- 支持多站点虚拟主机
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:运维星火燎原 刘军军 刘军军《Ansible自动化部署 Web 服务(Nginx + PHP + MySQL)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论