Ansible LAMP Stack Deployment on Ubuntu

By Raman Kumar

Updated on Sep 25, 2025

Learn how to set up and automate a full LAMP stack on Ubuntu 24.04 using Ansible. This step-by-step tutorial covers Apache, MySQL, and PHP with best practices.

Introduction:

Setting up a LAMP stack (Linux, Apache, MySQL/MariaDB, PHP) is still one of the most common starting points for web applications. Instead of installing everything manually, we can automate the entire process with Ansible. Automation ensures consistency, saves time, and makes scaling our infrastructure much easier.

When we automate a LAMP stack, a flat single-file playbook is fine for learning. But in real-world projects, that approach quickly becomes unmaintainable. The professional way is to use roles, each role dedicated to a component like Apache, MySQL, or PHP. This keeps our playbooks modular, reusable, and easier to extend.

In this section, we’ll learn how to organize an Ansible project with roles, and then deploy Apache, MySQL, and PHP on Ubuntu 24.04 with clarity and reliability.

Ansible LAMP Stack Deployment on Ubuntu

Step 1: Prepare Our Environment

Start with a fresh Ubuntu 24.04 server. Make sure it’s updated:

sudo apt update && sudo apt upgrade -y

Install Ansible on our control machine (this could be our local system or a separate management server):

sudo apt install ansible -y

Verify installation:

ansible --version

Step 2: Configure SSH Access

Ansible communicates over SSH. We need key-based authentication:

Generate SSH keys (on control machine):

ssh-keygen -t ed25519

Copy the public key to the target Ubuntu server:

ssh-copy-id user@server-ip

Now we can test the connection:

ansible all -i server-ip, -m ping -u user

If it returns pong, we are ready.

Step 3: Create Ansible Project Structure

Create a project folder:

mkdir lamp-ansible && cd lamp-ansible
touch inventory playbook.yml

Initialize the standard Ansible layout:

ansible-galaxy init roles/apache
ansible-galaxy init roles/mysql
ansible-galaxy init roles/php

Now we have:

lamp-ansible/
├── inventory
├── playbook.yml
└── roles/
    ├── apache/
    ├── mysql/
    └── php/

Edit inventory file and add servers:

nano inventory

Add following content:

[lamp_servers]
server1 ansible_host=server-ip ansible_user=user

Note: Add all the servers you want to install LAMP.

Step 4: Apache Role

Edit roles/apache/tasks/main.yml:

nano roles/apache/tasks/main.yml

Add following content:

---
- name: Install Apache
  apt:
    name: apache2
    state: present
    update_cache: yes

- name: Ensure Apache is enabled and running
  service:
    name: apache2
    state: started
    enabled: true

- name: Allow HTTP and HTTPS through UFW
  community.general.ufw:
    rule: allow
    port: "{{ item }}"
    proto: tcp
  loop:
    - 80
    - 443

- name: Deploy PHP info page for testing
  copy:
    dest: /var/www/html/info.php
    content: "<?php phpinfo(); ?>"
    owner: www-data
    group: www-data
    mode: '0644'
  notify: Restart Apache

Save and exit the file.

Add a handler roles/apache/handlers/main.yml:

nano roles/apache/handlers/main.yml

Add following content:

---
- name: Restart Apache
  service:
    name: apache2
    state: restarted

Save and exit the file.

Step 5: MySQL Role

Edit roles/mysql/tasks/main.yml:

nano roles/mysql/tasks/main.yml

Add following content:

---
- name: Install MySQL server and dependencies
  apt:
    name:
      - mysql-server
      - python3-mysqldb
    state: present
    update_cache: yes

- name: Ensure MySQL is enabled and started
  service:
    name: mysql
    state: started
    enabled: true

- name: Secure MySQL root user
  community.mysql.mysql_user:
    name: root
    host: localhost
    password: "{{ mysql_root_password }}"
    priv: "*.*:ALL,GRANT"
    login_unix_socket: /var/run/mysqld/mysqld.sock
    state: present

- name: Remove anonymous MySQL users
  community.mysql.mysql_user:
    name: ''
    host_all: true
    state: absent
    login_unix_socket: /var/run/mysqld/mysqld.sock

- name: Drop test database
  community.mysql.mysql_db:
    name: test
    state: absent
    login_unix_socket: /var/run/mysqld/mysqld.sock

Save and exit the file.

Step 6: PHP Role

Edit roles/php/tasks/main.yml:

nano roles/php/tasks/main.yml

Add following content:

---
- name: Install PHP and required extensions
  apt:
    name:
      - php
      - libapache2-mod-php
      - php-mysql
    state: present
    update_cache: yes
  notify: Restart Apache

Save and exit the file.

Step 7: Main Playbook

Finally, tie everything together in playbook.yml:

nano playbook.yml

Add following content:

---
- hosts: lamp_servers
  become: true
  roles:
    - apache
    - mysql
    - php

Save and exit the file.

Step 8: Run the Playbook

Execute:

ansible-galaxy collection install community.mysql community.general
ansible-playbook -i inventory playbook.yml

Step 9: Verify Deployment

Login into host server and check Apache status:

systemctl status apache2

Check PHP:

Visit http://server-ip/info.php and confirm PHP info page loads.

Check MySQL root login:

mysql

Final Thoughts

By automating the LAMP stack installation with Ansible on Ubuntu 24.04, we replace repetitive manual work with a clean, repeatable process. This approach ensures our web applications are deployed consistently and can easily scale across multiple servers.

Automation is not just a time-saver; it is a professional habit that makes our infrastructure more reliable and secure.

With this role-based Ansible setup, we not only automate a LAMP stack on Ubuntu 24.04 but also follow best practices for structure and maintainability. This is the same method teams use in production environments where clarity, repeatability, and modularity are non-negotiable.

Check out robust instant dedicated serversInstant KVM VPS, premium shared hosting and data center services in New Zealand