Ansible is an open-source automation tool that simplifies configuring and managing servers. It uses simple, human-readable YAML scripts, making them accessible to beginners and seasoned sysadmins.

In web development, having a reliable and efficient server setup is crucial. The combination of Linux, Apache, MySQL, and PHP, commonly known as LAMP, forms a powerful stack for hosting dynamic web applications.

In this blog post, we will explore installing and configuring a LAMP stack on Ubuntu 22.04 using Ansible, a powerful automation tool.


  • An Ubuntu 22.04 server for Ansible Management Node.
  • An Ubuntu 22.04 server for Ansible Target Node.
  • A valid, fully qualified domain name is pointed to the Target node’s IP address.

Step 1 – Install Ansible on the Management Node

By default, the latest version of Ansible is not available in Ubuntu’s default repository, so you will need to add it manually.

First, install the required packages using the following command.

apt update -y
apt install gnupg2 software-properties-common -y

Next, add the Ansible repository with the following command.

apt-add-repository ppa:ansible/ansible

Once the repository is updated, you can install Ansible using the following command.

apt install ansible -y

Step 2 – Setting Up SSH Password Less Authentication

Next, you will need to set up SSH passwordless authentication on the Ansible management node to connect to the target node without providing an SSH password.

First, generate an SSH key pair using the following command.

ssh-keygen -t rsa

You will see the following output:

Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/
The key fingerprint is:
SHA256:5AcJyNZCKPRb9US/wZz/5OWGBE9PcArZj+hd9P9fCuY root@ubuntu22
The key's randomart image is:
+---[RSA 3072]----+
|.. +.o...o  .o. .|
|. o = o.o.+ o..+.|
| . o o  +. *..o+o|
|    o  o .  =+.o+|
|   .    S .o ooo+|
|         .  ..=oo|
|            o .o=|
|           o . oo|
|            E . o|

Next, copy the generated key to the target node.

ssh-copy-id root@target-server-ip

Next, try to SSH into the target server without entering a password:

ssh root@target-server-ip

You should be able to log in without being prompted for a password.

Step 3 – Configure Ansible Inventory and Roles

Next, you must create an Ansible inventory file and roles on the management machine.

First, create a directory for your project.

mkdir lamp

Next, navigate inside the lamp directory.

cd lamp

Next, create an inventory file.

nano inventory

Add the following lines:


ansible_python_interpreter = /usr/bin/python3

Note: Replace target-server-ip with your target server IP.

Next, create directories to store Ansible variables and other configuration files.

mkdir files vars

Next, create a variable file inside the vars directory.

nano vars/default.yml

Define your MySQL root password, Apache user, domain name, and port as shown below:

mysql_root_password: "secure-password"
app_user: "www-data"
http_host: ""
http_conf: "lamp.example.conf"
http_port: "80"
disable_default: true

Then, create an Apache virtual host configuration file.

nano files/apache.conf

Add the following content:

<VirtualHost *:{{ http_port }}>
    ServerAdmin webmaster@localhost
    ServerName {{ http_host }}
    DocumentRoot /var/www/html
    ErrorLog /var/log/apache2/error.log
    CustomLog /var/log/apache2/access.log combined

    <Directory /var/www/html>
          Options -Indexes

    <IfModule mod_dir.c>
        DirectoryIndex index.php index.html index.cgi  index.xhtml index.htm


Next, create a info.php file:

nano files/info.php

Add the following PHP code:


Save and close the file when you are done.

Step 4 – Configure Ansible Playbook

Next, you will need to create an Ansible playbook to define all tasks to deploy the LAMP server on the target server.

First, create a playbook file:

nano playbook.yml

Add the following configuration:

- hosts: all
  become: true
    - vars/default.yml

    - name: Install prerequisites
      apt: name={{ item }} update_cache=yes state=latest force_apt_get=yes
      loop: [ 'aptitude' ]

  #Apache Configuration
    - name: Install LAMP Packages
      apt: name={{ item }} update_cache=yes state=latest
      loop: [ 'apache2', 'mariadb-server', 'python3-pymysql' 'php', 'mysql-python', 'libapache2-mod-php' ]

    - name: Create document root
        path: "/var/www/html/"
        state: directory
        owner: "{{ app_user }}"
        mode: '0755'

    - name: Set up Apache virtualhost
        src: "files/apache.conf"
        dest: "/etc/apache2/sites-available/{{ http_conf }}"
      notify: Reload Apache

    - name: Enable new site
      shell: /usr/sbin/a2ensite {{ http_conf }}
      notify: Reload Apache

    - name: Disable default Apache site
      shell: /usr/sbin/a2dissite 000-default.conf
      when: disable_default
      notify: Reload Apache

  # MySQL Configuration
    - name: Sets the root password
        name: root
        password: "{{ mysql_root_password }}"
        login_user: root
        login_password: ""
        login_unix_socket: /var/run/mysqld/mysqld.sock

    - name: Removes all anonymous user accounts
        name: ''
        host_all: yes
        state: absent
        login_user: root
        login_password: "{{ mysql_root_password }}"

    - name: Removes the MySQL test database
        name: test
        state: absent
        login_user: root
        login_password: "{{ mysql_root_password }}"

  # PHP Info Page
    - name: Sets Up PHP Info Page
        src: "files/info.php"
        dest: "/var/www/html/info.php"

    - name: Reload Apache
        name: apache2
        state: reloaded

    - name: Restart Apache
        name: apache2
        state: restarted

Save and close the file, then run the above playbook using the following command.

ansible-playbook -i inventory playbook.yml -u root

After the successful playbook execution, you will see the following output:

PLAY [all] *************************************************************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************************************************
ok: []

TASK [Install prerequisites] *******************************************************************************************************************************************
ok: [] => (item=aptitude)

TASK [Install LAMP Packages] *******************************************************************************************************************************************
ok: [] => (item=apache2)
changed: [] => (item=mariadb-server)
ok: [] => (item=php)
ok: [] => (item=python3-pymysql)
ok: [] => (item=php-mysql)
ok: [] => (item=libapache2-mod-php)

TASK [Create document root] ********************************************************************************************************************************************
ok: []

TASK [Set up Apache virtualhost] ***************************************************************************************************************************************
ok: []

TASK [Enable new site] *************************************************************************************************************************************************
changed: []

TASK [Disable default Apache site] *************************************************************************************************************************************
changed: []

TASK [Sets the root password] ******************************************************************************************************************************************
[WARNING]: Option column_case_sensitive is not provided. The default is now false, so the column's name will be uppercased. The default will be changed to true in
community.mysql 4.0.0.
changed: []

TASK [Removes all anonymous user accounts] *****************************************************************************************************************************
ok: []

TASK [Removes the MySQL test database] *********************************************************************************************************************************
ok: []

TASK [Sets Up PHP Info Page] *******************************************************************************************************************************************
ok: []

RUNNING HANDLER [Reload Apache] ****************************************************************************************************************************************
changed: []

PLAY RECAP *************************************************************************************************************************************************************               : ok=12   changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Step 5 – Verify LAMP Deployment

At this point, the LAMP server is deployed on the target server. You can now verify it using the URL You will see the output of info.php on the following screen.


Congratulations! You’ve successfully installed and configured a LAMP stack on Ubuntu 22.04 using Ansible. Automating the setup process with Ansible saves time and ensures consistency across multiple servers. As you continue exploring Ansible, you can adapt and expand your playbooks to suit the specific requirements of your web applications. This automation approach empowers developers to focus more on coding and less on manual server configurations. You can now use Ansible to automate LAMP server deployment on dedicated server hosting from Atlantic.Net!