Developer Advocate
If you were following along with all parts of this series, at this point you should be familiar with installing system packages, applying templates, and using handlers in Ansible playbooks. In this part of the series, you’ll use what you’ve seen so far to create a playbook that automates setting up a remote Nginx server to host a static HTML website on Ubuntu 20.04.
Start by creating a new directory on your Ansible control node where you’ll set up the Ansible files and a demo static HTML website to be deployed to your remote server. This could be in any location of your choice within your home folder. In this example we’ll use ~/ansible-nginx-demo
.
- mkdir ~/ansible-nginx-demo
- cd ~/ansible-nginx-demo
Next, copy your existing inventory file into the new directory. In this example, we’ll use the same inventory you set up at the beginning of this series:
- cp ~/ansible-practice/inventory .
This will copy a file named inventory
from a folder named ansible-practice
in your home directory, and save it to the current directory.
For this demonstration, we’ll use a static HTML website that is the subject of our How To Code in HTML series. Start by downloading the demo website files by running the following command:
- curl -L https://github.com/do-community/html_demo_site/archive/refs/heads/main.zip -o html_demo.zip
You’ll need unzip
to unpack the contents of this download. To make sure you have this tool installed, run:
- sudo apt install unzip
Then, unpack the demo website files with:
- unzip html_demo.zip
This will create a new directory called html_demo_site-main
on your current working directory. You can check the contents of the directory with an ls -la
command:
- ls -la html_demo_site-main
Outputtotal 28
drwxrwxr-x 3 sammy sammy 4096 sep 18 2020 .
drwxrwxr-x 5 sammy sammy 4096 mrt 25 15:03 ..
-rw-rw-r-- 1 sammy sammy 1289 sep 18 2020 about.html
drwxrwxr-x 2 sammy sammy 4096 sep 18 2020 images
-rw-rw-r-- 1 sammy sammy 2455 sep 18 2020 index.html
-rw-rw-r-- 1 sammy sammy 1079 sep 18 2020 LICENSE
-rw-rw-r-- 1 sammy sammy 675 sep 18 2020 README.md
You’ll now set up the Nginx template that is necessary to configure the remote web server. Create a new folder within your ansible-demo
directory to hold non-playbook files:
- mkdir files
Then, open a new file called nginx.conf.j2
:
- nano files/nginx.conf.j2
This template file contains an Nginx server block configuration for a static HTML website. It uses three variables: document_root
, app_root
, and server_name
. We’ll define these variables later on when creating the playbook. Copy the following content to your template file:
server {
listen 80;
root {{ document_root }}/{{ app_root }};
index index.html index.htm;
server_name {{ server_name }};
location / {
default_type "text/html";
try_files $uri.html $uri $uri/ =404;
}
}
Save and close the file when you’re done.
Next, we’ll create a new Ansible playbook and set up the variables that we’ve used in the previous section of this guide. Open a new file named playbook.yml
:
- nano playbook.yml
This playbook starts with the hosts
definition set to all
and a become
directive that tells Ansible to run all tasks as the root user by default (the same as manually running commands with sudo
). Within this playbook’s var
section, we’ll create three variables: server_name
, document_root
, and app_root
. These variables are used in the Nginx configuration template to set up the domain name or IP address that this web server will respond to, and the full path to where the website files are located on the server. For this demo, we’ll use the ansible_default_ipv4.address
fact variable because it contains the remote server’s public IP address, but you can replace this value with your server’s hostname in case it has a domain name properly configured within a DNS service to point to this server:
---
- hosts: all
become: yes
vars:
server_name: "{{ ansible_default_ipv4.address }}"
document_root: /var/www/html
app_root: html_demo_site-main
tasks:
You can keep this file open for now. The next sections will walk you through all tasks that you’ll need to include in this playbook to make it fully functional.
The following task will update the apt
cache and then install the nginx
package on remote nodes:
. . .
- name: Update apt cache and install Nginx
apt:
name: nginx
state: latest
update_cache: yes
The next task will use the copy
built-in module to upload the website files to the remote document root. We’ll use the document_root
variable to set the destination on the server where the application folder should be created.
. . .
- name: Copy website files to the server's document root
copy:
src: "{{ app_root }}"
dest: "{{ document_root }}"
mode: preserve
We’ll now apply the Nginx template that will configure the web server to host your static HTML file. After the configuration file is set at /etc/nginx/sites-available
, we’ll create a symbolic link to that file inside /etc/nginx-sites-enabled
and notify the Nginx service for a posterior restart. The entire process will require two separate tasks:
. . .
- name: Apply Nginx template
template:
src: files/nginx.conf.j2
dest: /etc/nginx/sites-available/default
notify: Restart Nginx
- name: Enable new site
file:
src: /etc/nginx/sites-available/default
dest: /etc/nginx/sites-enabled/default
state: link
notify: Restart Nginx
Next, include the task that enables tcp access on port 80:
. . .
- name: Allow all access to tcp port 80
ufw:
rule: allow
port: '80'
proto: tcp
. . .
To finish this playbook, the only thing left to do is to set up the Restart Nginx
handler:
. . .
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
Once you’re finished including all the required tasks in your playbook file, it will look like this:
---
- hosts: all
become: yes
vars:
server_name: "{{ ansible_default_ipv4.address }}"
document_root: /var/www
app_root: html_demo_site-main
tasks:
- name: Update apt cache and install Nginx
apt:
name: nginx
state: latest
update_cache: yes
- name: Copy website files to the server's document root
copy:
src: "{{ app_root }}"
dest: "{{ document_root }}"
mode: preserve
- name: Apply Nginx template
template:
src: files/nginx.conf.j2
dest: /etc/nginx/sites-available/default
notify: Restart Nginx
- name: Enable new site
file:
src: /etc/nginx/sites-available/default
dest: /etc/nginx/sites-enabled/default
state: link
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
To execute this playbook on the server(s) that you set up in your inventory file, run ansible-playbook
with the same connection arguments you’ve used when running a connection test within the introduction of this series. Here, we’ll be using an inventory file named inventory
and the sammy user to connect to the remote server. Because the playbook requires sudo
to run, we’re also including the -K
argument to provide the remote user’s sudo
password when prompted by Ansible:
- ansible-playbook -i inventory playbook.yml -u sammy -K
You’ll see output like this:
OutputBECOME password:
PLAY [all] **********************************************************************************************
TASK [Gathering Facts] **********************************************************************************
ok: [203.0.113.10]
TASK [Update apt cache and install Nginx] ***************************************************************
ok: [203.0.113.10]
TASK [Copy website files to the server's document root] *************************************************
changed: [203.0.113.10]
TASK [Apply Nginx template] *****************************************************************************
changed: [203.0.113.10]
TASK [Enable new site] **********************************************************************************
ok: [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=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Once the playbook is finished, if you go to your browser and access your server’s hostname or IP address you should now see the following page:
Congratulations, you have successfully automated the deployment of a static HTML website to a remote Nginx server, using Ansible.
If you make changes to any of the files in the demo website, you can run the playbook again and the copy
task will make sure any file changes are reflected in the remote host. Because Ansible has an idempotent behavior, running the playbook multiple times will not trigger changes that were already made to the system.
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!