Operations 20 min read

Automate LNMP Deployment with Ansible Playbooks: Step‑by‑Step Guide

This tutorial walks through installing Ansible on CentOS, preparing inventory and SSH keys, creating variable files, and writing a comprehensive Ansible playbook that automates the installation and configuration of Nginx, MySQL, and PHP on multiple hosts, complete with service setup and verification.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Automate LNMP Deployment with Ansible Playbooks: Step‑by‑Step Guide

Install Ansible

Configure the Alibaba yum repository, install the EPEL release package, and then install Ansible on a CentOS 8 system.

/etc/yum.repos.d# rm -rf *
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo
yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-8.noarch.rpm
sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo
sed -i 's|^#baseurl=https://download.example/pub|baseurl=https://mirrors.aliyun.com|' /etc/yum.repos.d/epel*
sed -i 's|^metalink|#metalink|' /etc/yum.repos.d/epel*
cd / && dnf -y install platform-python
dnf -y install centos-release-ansible
dnf -y install ansible --nobest
ansible --version

Prepare Basic Environment with Ansible

Create an inventory file, map host IPs to groups, generate SSH keys, copy the public key to each managed host, and verify connectivity. Also disable firewalld and SELinux on the control node.

# vim /etc/hosts
127.0.0.1   localhost
192.168.222.137 nginx
192.168.222.138 mysql
192.168.222.139 php
mkdir playdemo && cd playdemo
cp /etc/ansible/ansible.cfg .
vim ansible.cfg   # set inventory = /etc/ansible/hosts
vim inventory   # define groups and hosts
ansible all --list-hosts
ssh-keygen -t rsa
ssh-copy-id 192.168.222.137
ssh-copy-id 192.168.222.138
ssh-copy-id 192.168.222.139
ansible all -m ping
systemctl stop firewalld.service
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
setenforce 0
systemctl disable --now firewalld.service

Write Playbook

Create a playbook directory, add lnmp.yml, and define tasks to stop firewalld, disable SELinux, install and configure Nginx, MySQL, and PHP, copy service files, set PATH variables, and start the services.

# mkdir playbook && cd playbook
vim lnmp.yml
---
- name: nginx mysql php stop firewalld and selinux
  hosts: all
  tasks:
    - name: stop firewalld
      service:
        name: firewalld.service
        state: stopped
        enabled: no
    - name: Ensure SELinux is disabled
      lineinfile:
        path: /etc/selinux/config
        regexp: '^SELINUX='
        line: SELINUX=disabled
- name: install nginx
  vars_files:
    - ../var/dir.yml
    - ../var/hos.yml
    - ../var/package.yml
  hosts: "{{ host_ip['nginx'] }}"
  tasks:
    - name: create nginx user
      user:
        name: nginx
        system: yes
        shell: /sbin/nologin
        create_home: no
        state: present
    - name: copy nginx tarball
      copy:
        src: "{{ url_dir }}{{ package['nginx'] }}.tar.gz"
        dest: "{{ dow_dir }}"
    - name: unarchive nginx
      unarchive:
        src: "{{ dow_dir }}{{ package['nginx'] }}.tar.gz"
        dest: "{{ una_dir }}"
        remote_src: yes
    - name: install build dependencies
      yum:
        name: pcre-devel,openssl,openssl-devel,gd-devel,make,gcc,gcc-c++,wget
        state: present
    - name: configure nginx
      shell: |
        cd {{ una_dir }}{{ package['nginx'] }} && \
        ./configure --prefix={{ ins_dir['nginx'] }} \
        --user=nginx --group=nginx --with-debug \
        --with-http_ssl_module --with-http_realip_module \
        --with-http_image_filter_module --with-http_gunzip_module \
        --with-http_gzip_static_module --with-http_stub_status_module
    - name: make and install nginx
      shell: |
        cd {{ una_dir }}{{ package['nginx'] }} && \
        make -j $(grep -c processor /proc/cpuinfo) && \
        make install
    - name: set nginx PATH
      copy:
        dest: /etc/profile.d/nginx.sh
        content: "export PATH=$PATH:{{ ins_dir['nginx'] }}/sbin"
    - name: create nginx service file
      copy:
        dest: /usr/lib/systemd/system/nginx.service
        content: |
          [Unit]
          Description=nginx server daemon
          After=network.target

          [Service]
          Type=forking
          ExecStart={{ ins_dir['nginx'] }}/sbin/nginx
          ExecStop={{ ins_dir['nginx'] }}/sbin/nginx -s stop
          ExecReload=/bin/kill -HUP $MAINPID

          [Install]
          WantedBy=multi-user.target
    - name: modify nginx configuration
      copy:
        dest: "{{ ins_dir['nginx'] }}/conf/nginx.conf"
        content: |
          user  nginx;
          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.php; }
              error_page 500 502 503 504 /50x.html;
              location = /50x.html { root html; }
              location ~ \.php$ {
                root /var/www;
                fastcgi_pass {{ host_ip['php'] }}:9000;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;
              }
            }
          }
    - name: create index.php
      file:
        path: "{{ ins_dir['nginx'] }}/html/index.php"
        state: touch
    - name: start nginx
      service:
        name: nginx.service
        state: restarted
        enabled: yes
# (Similar blocks for MySQL and PHP are defined below, using the same variable files and host groups.)

Use Variables

Define three variable files ( dir.yml, hos.yml, package.yml) that store directory paths, host IP mappings, and package names, then reference them in the playbook with Jinja2 syntax.

# dir.yml
url_dir: ../package/
 dow_dir: /usr/local/src/
 una_dir: /usr/src/
 ins_dir:
   nginx: /usr/local/nginx
   mysql: /usr/local/mysql
   php: /usr/local/php
# hos.yml
host_ip:
  nginx: 192.168.222.137
  mysql: 192.168.222.138
  php: 192.168.222.139
# package.yml
package:
  nginx: nginx-1.22.0
  mysql: mysql-5.7.38-linux-glibc2.12-x86_64
  php: php-8.1.11

After running ansible-playbook playbook/lnmp.yml -vv, the playbook reports successful execution on all three hosts, with tasks marked as ok and changed, confirming that Nginx, MySQL, and PHP are installed, configured, and running.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AutomationDeploymentPHPAnsibleLNMP
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.