Ansible Guide: Create Ansible Playbook for LEMP Stack
Ansible is a simple automation tool that automates software application deployment, cloud provisioning, and configuration management. It's a server orchestration tool that helps you to manage and control a large number of server nodes from single places called 'Control Machines'. Ansible was created by Michael DeHaan in 2012 and is written in Python and Powershell.
In this tutorial, we're going to show you how to create basic Ansible Playbook for provisioning the LEMP Stack on Ubuntu 18.04 Server. You will learn how to create basic Ansible Playbook that can be scaled for other PHP project applications such as WordPress, Nextcloud etc.
Prerequisite
- 2 Ubuntu OS.
- 10.5.5.20 ansible
- 10.5.5.26 provision
- Knowledge of basic usage Ansible
- Root privileges
What we will do:
- Setup Ansible Playbook Project
- Generate Ansible Playbook Roles Directory Structure
- Setup hosts and site.yml
- Setup 'common' Roles - Basic setup
- Setup 'web' Roles - Nginx and PHP-FPM Configuration
- Setup 'db' Roles - MySQL Database Configuration
- Testing
Step 1 - Setup Ansible Playbook Project
Ansible Playbook is a set of instructions that you send to run on a single or group of server hosts. It represents the ansible-provisioning, where the automation is defined as tasks, and all jobs like installing packages, editing files, will be done by ansible modules.
The Ansible Playbook contains some basic configuration, including hosts and user information of the provision servers, a task list that will be implemented to the provision servers, template and custom configurations, and a group of variables part of templates and tasks.
Firstly, create the master project directory on the 'ansible-control' machine. The master project directory will be stored all our playbook directories, files, and configurations.
Create the Ansible project directory called 'project-lemp' and go into it.
mkdir project-lemp/
cd project-lemp
Now create new configuration file 'hosts' and 'site.yml', then create a new directory called 'roles'.
touch hosts site.yml
mkdir -p roles/
Details about configurations:
hosts - It's an inventory file that contains pieces of information about managed servers by ansible. It allows you to create a group of servers that make you more easier to manage and scale the inventory file itself. The inventory file can be created with many different formats, including the INI and YAML formats.
site.yml - The master playbook file that contains which group of hosts that will be managed using our available roles.
roles - it's a group of Ansible playbooks that will be used to provision the server. The ansible roles have their own directory structures, each role will contain directories such as tasks, handlers, vars etc.
Step 2 - Generate Ansible Roles for the Directory Structure
In this step, we're going to generate ansible roles directory using the ansible-galaxy command. We will generate two of roles called 'common' roles and the 'web' roles.
Inside the 'project-lemp' directory, go to the directory 'roles'.
cd roles/
Generate roles structure directory and files for the 'common' and 'web' roles by running the ansible-galaxy command below.
ansible-galaxy init common
ansible-galaxy init web
ansible-galaxy init db
After that, check all available ansible roles directory structures using the following command.
tree .
You will be shown the result as below.
Step 3 - Setup hosts and site.yml
The 'hosts' file will contain list and group of the server managed by the Ansible. For this guide, we will create a group called 'lemp' with the member named 'server01' and the IP address 10.5.5.26.
Edit the 'hosts' file using vim editor.
vim hosts
Paste configuration below.
[lemp]
server01 ansible_host=10.5.5.26
Save and close.
Next, edit the site.yml configuration file.
vim site.yml
Paste configurations below.
---
- hosts: lemp
remote_user: hakase
become: yes
roles:
- common
- web
- db
Save and close.
Step 3 - Setup Common Roles
In this step, we're going to set up the common roles. And in order to do that, we need to create a list of tasks that we're going to do.
Below the list of tasks that we're going to do on the 'common' roles.
- Change repository
- Update repository
- Upgrade packages to the latest version
- Setup the server timezone
Now go to the 'common' directory and edit the 'tasks/main.yml' configuration.
cd common/
vim tasks/main.yml
Create a task for changing the repository, and we will be using the 'copy' module that will copy the base 'sources.list' on the 'files' directory to the remote host '/etc/apt/'.
- name: Change repository Ubuntu 18.04Step 4 - Setup 'web' Roles
copy:
src: sources.list
dest: /etc/apt/
backup: yes
Create a task for updating the repository and upgrade all packages to latest version using the 'apt' module.
- name: Update repository and Upgrade packages
apt:
upgrade: dist
update_cache: yes
Now create the task for configuring the system timezone using the ansible timezone module.
- name: Setup timezone to Asia/Jakarta
timezone:
name: Asia/Jakarta
state: latest
Save and close.
After that, create a new repository configuration 'sources.list' inside the 'files' directory.
vim files/sources.list
Choose the nearest repository of your server location, below is mine.
deb http://buaya.klas.or.id/ubuntu/ bionic main restricted
deb http://buaya.klas.or.id/ubuntu/ bionic-updates main restricted
deb http://buaya.klas.or.id/ubuntu/ bionic universe
deb http://buaya.klas.or.id/ubuntu/ bionic-updates universe
deb http://buaya.klas.or.id/ubuntu/ bionic multiverse
deb http://buaya.klas.or.id/ubuntu/ bionic-updates multiverse
deb http://buaya.klas.or.id/ubuntu/ bionic-backports main restricted universe multiverse
deb http://buaya.klas.or.id/ubuntu/ bionic-security main restricted
deb http://buaya.klas.or.id/ubuntu/ bionic-security universe
deb http://buaya.klas.or.id/ubuntu/ bionic-security multiverse
Save and close.
lastly, the 'common' roles configuration has been completed.
Step 4 - Setup 'web' Roles
In this step, we're going to set up the 'web' roles. It will do some tasks including install the Nginx web server, PHP-FPM with some basic extentions, and configuring the PHP-FPM with Nginx.
Below are details tasks that we will do on the 'web' roles:
- Install Nginx
- Install PHP-FPM
- Configure php.ini
- Create a virtual host
- Add file phpinfo
Goto the 'web' directory and edit the 'tasks/main.yml' file.
cd web/
vim tasks/main.yml
Create the first task for nginx installation using the apt module.
- name: Install Nginx
apt:
name: nginx
state: latest
Now create the task for installing PHP-FPM with some basic extensions. And for the multiple packages installation, we can use python 'list' format such as below.
- name: Instal PHP-FPM
apt:
name: ['php','php-fpm','php-common','php-cli','php-curl']
state: latest
Next, we will add new lines to the php.ini configuration using the 'blockinfile' module. And at the end of the line, we will notify the ansible to restart the php-fpm service after configuring the php.ini file.
- name: Configure php.ini
blockinfile:
dest: /etc/php/{{ php_version }}/fpm/php.ini
block: |
date.time = Asia/Jakarta
cgi-fix_pathinfo = 0
backup: yes
notify: restart php-fpm
Now we will copy the nginx virtual host configuration using the 'template' module. The template module will copy the configuration from the 'templates' directory to the remote server. We're going to copy the jinja2 virtual host template 'vhost.j2' to the '/etc/nginx/sites-enabled/' directory, and the last we will notify the ansible to restart the nginx service.
- name: Create Nginx virtual host
template:
src: vhost.j2
dest: /etc/nginx/sites-enabled/vhost-{{ domain_name }}
notify: restart nginx
After that, we will create new tasks for creating the web-root directory using the 'file' module and copy the index.php template into it.
- name: Create web-root directory
file:
path: /var/www/{{ domain_name }}
state: directory
- name: Upload index.html and info.php files
template:
src: index.php.j2
dest: /var/www/{{ domain_name }}/index.php
Save and close.
Now we're going to configure the handlers for restarting the nginx and php-fpm service. Edit the 'handlers/main.yml' configuration using vim editor.
vim handlers/main.yml
Paste configurations below.
- name: restart nginx
service:
name: nginx
state: restarted
enabled: yes
- name: restart php-fpm
service:
name: php{{ php_version }}-fpm
state: restarted
enabled: yes
Save and close.
Next, we will edit the 'vars/main.yml' configuration. At the top of configurations you will notice the variable configurations '{{ php_version }}' and '{{ domain_name }}'. Those variables represent our environment setup for the php version and the domain name that will be used. The variable makes ansible more reusable because we just need to edit the variable configuration 'vars/main.yml' and not editing the base configuration.
Edit the variables configuration 'vars/main.yml' using vim editor.
vim vars/main.yml
Paste configurations below.
php_version: 7.2
domain_name: hakase-labs.io
Save and close.
Now we will create jinja2 template configurations 'index.php.j2' and 'vhost.j2' on the 'templates/' directory.
vim templates/index.php.j2
Paste configuration below.
<html>
<body>
<h1><center>index.html for domain {{ domain_name }}</center></h1>
<p>
<p>
<?php
phpinfo();
?>
</body>
</html>
Save and close.
After that, create the template for nginx virtual host configuration 'vhost.j2'.
vim templates/vhost.j2
Paste configurations below.
server {
listen 80;
listen [::]:80;
root /var/www/{{ domain_name }};
index index.php index.html index.htm index.nginx-debian.html;
server_name {{ domain_name }};
location / {
try_files $uri $uri/ =404;
}
# pass PHP scripts to FastCGI server
#
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php{{ php_version }}-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Save and close the configuration, and we're finished the web roles configuration.
Step 5 - Setup 'db' Roles
At this step, we're going to configure the 'db' roles for the MySQL database installation and configuration.
Below are details tasks that will do on the 'db' roles.
- install mysql
- Create MySQL database
- Create MySQL user
- restart mysql
Goto the 'db' directory and edit the 'tasks/main.yml' configuration.
cd db/
vim tasks/main.yml
Now install the MySQL packages using the 'apt' module and python 'list' format for multiple packages installation.
- name: Install MySQL
apt:
name: ['mysql-server','mysql-client','python-mysqldb']
state: latest
notify: restart mysql
Then create new tasks for creating the MySQL database and user, then grant all privileges of the user to the database.
- name: Create database
mysql_db:
name: '{{ db_name }}'
state: present
- name: Create user for the database
mysql_user:
name: '{{ db_user }}'
password: '{{ db_pass }}'
encrypted: yes
priv: '{{ db_name }}.*:ALL'
state: present
Save and close.
Next, edit the 'handlers/main.yml' configuration.
vim handlers/main.yml
Paste the configuration of the task for restarting the MySQL service.
- name: restart mysql
service:
name: mysql
state: restarted
enabled: yes
Save and close.
After that, edit the vars variable configuration 'vars/main.yml'.
vim vars/main.yml
Paste these variables for MySQL database and user configuration below.
db_name: hakase-db
db_user: hakase
db_pass: '*C960D382DB42E57D3BAC33891CF87900DCB1A869'
Save and close.
The 'db_pass' variable has the MySQL encrypted password, and you can generate an encrypted MySQL password using online tools.
Step 6 - Run the Ansible Playbook
Goto the Ansible project directory.
cd project-lemp/
Run the ansible-playbook command below.
ansible-playbook -i hosts site.yml
Now the ansible will run all roles that we assign to the host. When it's complete, you will be shown the result as below.
Make sure you get no error.
Step 7 - Testing
Open your web browser and type the domain name on the address bar http://hakase-labs.io.
And you will be shown the index page with phpinfo as below.
The PHP-FPM and Nginx are working.
Next, back to the server terminal and log in to the MySQL server using the user and password that we've created on the 'mysql' roles variable.
mysql -u hakase -p
PASSWORD: hakasepass
check the list of database owned by the user.
show databases;
And you will be logged to the MySQL shell and will be shown the database named 'hakase-db' on the list.
Finally, the Ansible Playbook for the LEMP Stack installation and configuration has been created and tested successfully.