In a nutshell, handlers are special tasks that only get executed when triggered via the notify
directive. Handlers are executed at the end of the play, once all tasks are finished.
In Ansible, handlers are typically used to start, reload, restart, and stop services. If your playbook involves changing configuration files, there is a high chance that you’ll need to restart a service so that the changes take effect. In this case, you’ll need to define a handler for that service and include the notify
directive in any tasks that require that service handler.
In a previous section of this series, you’ve seen how to use a template to replace the default Nginx page with a custom HTML landing page. In practice, when setting up your Nginx web server, you’re most likely going to include new server block files in your sites-available
directory, create symbolic links, or change settings that require a server reload or restart.
Considering such a scenario, this is how a handler to restart the Nginx service would look like:
...
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
To trigger this handler, you’ll need to include a notify
directive in any task that requires a restart on the Nginx server.
The following playbook replaces the default document root in Nginx’s configuration file using the built-in Ansible module replace. This module looks for patterns in a file based on a regular expression defined by regexp
, and then replaces any matches found with the content defined by replace
. The task then sends a notification to the Restart Nginx
handler for a restart as soon as possible. What that means is, it doesn’t matter how many times you trigger the restart, it will only happen when all tasks are already finished executing and the handlers start running. Additionally, when no matches are found, no changes are made to the system, and for that reason the handler is not triggered.
Create a new file called playbook-12.yml
in your ansible-practice
directory:
- nano ~/ansible-practice/playbook-12.yml
Add the following lines to the new playbook file:
---
- hosts: all
become: yes
vars:
page_title: My Second Landing Page
page_description: This is my second landing page description.
doc_root: /var/www/mypage
tasks:
- name: Install Nginx
apt:
name: nginx
state: latest
- name: Make sure new doc root exists
file:
path: "{{ doc_root }}"
state: directory
mode: '0755'
- name: Apply Page Template
template:
src: files/landing-page.html.j2
dest: "{{ doc_root }}/index.html"
- name: Replace document root on default Nginx configuration
replace:
path: /etc/nginx/sites-available/default
regexp: '(\s+)root /var/www/html;(\s+.*)?$'
replace: \g<1>root {{ doc_root }};\g<2>
notify: Restart Nginx
- name: Allow all access to tcp port 80
ufw:
rule: allow
port: '80'
proto: tcp
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
Save and close the file when you’re done.
One important thing to keep in mind when using handlers is that they are only triggered when the task that defines the notify
trigger causes a change in the server. Taking this playbook into account, the first time it runs the replace
task it will change the Nginx configuration file and thus the restart will run. In subsequent executions, however, since the string to be replaced is not present in the file anymore, the task won’t cause any changes and won’t trigger the handler execution.
Remember to provide the -K
option if you run this playbook, since it requires sudo
permissions:
- ansible-playbook -i inventory playbook-12.yml -u sammy -K
OutputBECOME password:
PLAY [all] **********************************************************************************************
TASK [Gathering Facts] **********************************************************************************
ok: [203.0.113.10]
TASK [Install Nginx] ************************************************************************************
ok: [203.0.113.10]
TASK [Make sure new doc root exists] ********************************************************************
changed: [203.0.113.10]
TASK [Apply Page Template] ******************************************************************************
changed: [203.0.113.10]
TASK [Replace document root on default Nginx configuration] *********************************************
changed: [203.0.113.10]
TASK [Allow all access to tcp port 80] ******************************************************************
ok: [203.0.113.10]
RUNNING HANDLER [Restart Nginx] *************************************************************************
changed: [203.0.113.10]
PLAY RECAP **********************************************************************************************
203.0.113.10 : ok=7 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
If you look at the output, you’ll see the “Restart Nginx” handler being executed just before the end of the play. If you go to your browser and access the server’s IP address now, you’ll see the following page:
In the next and final part of this series, we’ll connect all the dots and put together a playbook that automates setting up a remote Nginx server to host a static HTML website.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Ansible is a modern configuration management tool that doesn’t require the use of an agent software on remote nodes, using only SSH and Python to communicate and execute commands on managed servers. This series will walk you through the main Ansible features that you can use to write playbooks for server automation. At the end, we’ll see a practical example of how to create a playbook to automate setting up a remote Nginx web server and deploy a static HTML website to it.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!