Ansible/Nginx Playbook
From charlesreid1
This article covers an example Ansible playbook to set up a secure Nginx server.
The page is organized as follows:
- Before You Begin: Vagrant setup
- Part 1: Setting up nginx HTTP server
- Part 2: Setting up nginx HTTPS server
Before you begin: Vagrant Setup
This page assumes that we are using Ansible to manage virtual machines created by Vagrant (which is like a Virtual Box wrapper for the command line).
See the example on the Vagrant page (spinning up a Ubuntu Xenial node) to get a Vagrant virtual machine started.
Next, we want to remap some ports.
We want to arrange the Vagrant machine so that we map the local port 8080 to the vagrant machine's port 80, and map the local port 8443 to the vagrant machine's port 443.
The Vagrantfile is a Ruby file that specifies how to start up and set up the Vagrant boxes. We can make modifications to it and ask Vagrant to reload/reboot the virtual machine using the new Vagrantfile. The Vagrantfile should be modified as follows:
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "ubuntu/xenial64" config.vm.network "forwarded_port", guest: 80, host: 8080 config.vm.network "forwarded_port", guest: 443, host: 8443 end
Now instruct vagrant to reload from the Vagrantfile:
$ vagrant reload
==> default: Forwarding ports...
default: 80 => 8080 (adapter 1)
default: 443 => 8443 (adapter 1)
default: 22 => 2222 (adapter 1)
Ansible Playbook Example 1: Nginx Server Playbook
Creating a simple playbook
The following simple playbook will set up an nginx web server on our fresh Ubuntu machine.
Here are the pieces in our playbook:
- The playbook itself (YAML file)
- nginx configuration file
- nginx HTML templates
- Create Ansible group webservers
The Playbook: YAML file
Here is a simple playbook for our secure nginx server:
web-notls.yml:
- name: Configure webserver with nginx
hosts: webservers
become: True
tasks:
- name: install nginx
apt: name=nginx update_cache=yes
- name: copy nginx config file
copy: src=files/nginx.conf dest=/etc/nginx/sites-available/default
- name: enable configuration
file: >
dest=/etc/nginx/sites-enabled/default
src=/etc/nginx/sites-available/default
state=link
- name: copy index.html
template: src=templates/index.html.j2 dest=/usr/share/nginx/html/index.html
mode=0644
- name: restart nginx
service: name=nginx state=restarted
Required files: /etc/nginx/sites-available/default, /usr/share/nginx/html/index.html
YAML truth-y values: true, True, TRUE, yes, Yes, YES, on, On, ON, y, Y
YAML false-y values: false, False, FALSE, no, No, NO, off, Off, OFF, n, N
nginx http config file
Here is the corresponding nginx configuration file, which serves HTTP requests only. We put in files/nginx.conf:
files/nginx.conf:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /usr/share/nginx/html;
index index.html index.htm;
server_name localhost;
location / {
try_files $uri $uri/ =404;
}
}
nginx index html page
Likewise, we want to create an index page for nginx to serve up, and we want to put template files into the playbook directory, in the templates subdirectory.
(NOTE: .j2 extension means it is a Jinja 2 template)
playbooks/templates/index.html.j2
<html>
<head>
<title>Welcome to ansible</title>
</head>
<body>
<h1>nginx, configured by Ansible</h1>
<p>If you can see this, Ansible successfully installed nginx.</p>
<p>Running on {{ inventory_hostname }}</p>
</body>
</html>
Creating webservers Ansible group
We will create a webservers Ansible group in the inventory file and refer to this group in the Ansible playbook.
In the playbooks/hosts file the "myvagrantbox" line is put under the heading [webservers]:
playbooks/hosts
[webservers] myvagrantbox ansible_host=127.0.0.1 ansible_port=2222
Now test it out: ping the webservers group with a single command:
$ ansible webservers -m ping
Output:
testserver | success >> {
"changed": false,
"ping": "pong"
}
Running a simple playbook
The ansible-playbook command is used to execute playbooks:
ansible-playbook web-notls.yml
Alternatively, to run a playbook directly, use the shebang line:
#!/usr/bin/env ansible-playbook
Then execute it directly:
./web-notls.yml
Anatomy of example playbook
Let's examine the example playbook in detail.
Plays
A playbook is a list of plays.
Every play has:
- a set of hosts to configure
- a set of tasks to run on those hosts
- the play is the thing that connects hosts to tasks
Optional play settings:
- name - a comment that describes what the play is about
- become - if true, Ansible will run each task by becoming the root user (useful for Ubuntu, where ssh as root is disabled by default)
- vars - list of variables and values
In our example, the play is this entire section:
- name: Configure webserver with nginx
hosts: webservers
become: True
tasks:
- name: install nginx
apt: name=nginx update_cache=yes
- name: copy nginx config file
copy: src=files/nginx.conf dest=/etc/nginx/sites-available/default
- name: enable configuration
file: >
dest=/etc/nginx/sites-enabled/default
src=/etc/nginx/sites-available/default
state=link
- name: copy index.html
template: src=templates/index.html.j2
dest=/usr/share/nginx/html/index.html mode=0644
- name: restart nginx
service: name=nginx state=restarted
Tasks
The tasks are the actions that are performed when the play is run.
The first task is to install nginx:
- name: install nginx apt: name=nginx update_cache=yes
This can also be written without the optional name parameter,
- apt: name=nginx update_cache=yes
Can also fold over multiple lines using >:
- name: install nginx
apt: >
name=nginx
update_cache=yes
Actions in tasks are composed of modules.
Modules
There are lots of useful modules that come with Ansible that can be used from playbooks.
- apt - installs/removes packages using aptitude package manager
- copy - copies files from local machine to host
- file - sets attributes of files/symlinks/directories
- service - starts/stops/restarts a service
- template - generates a file from a template and copies it to the hosts
Ansible Playbook Example 2: Secure Nginx Server Playbook
The second example introduces two new concepts:
- variables
- handlers
In example 2 we will generate a certificate on the machine that is running Ansible and distribute the certificate to the machines we're spinning up. (In this example we can use a self-signed certificate.)
The Playbook
Here is the YAML playbook file:
web-tls.yml
- name: Configure webserver with nginx and tls
hosts: webservers
become: True
vars:
key_file: /etc/nginx/ssl/nginx.key
cert_file: /etc/nginx/ssl/nginx.crt
conf_file: /etc/nginx/sites-available/default
server_name: localhost
tasks:
- name: Install nginx
apt: name=nginx update_cache=yes cache_valid_time=3600
- name: create directories for ssl certificates
file: path=/etc/nginx/ssl state=directory
- name: copy TLS key
copy: src=files/nginx.key dest={{ key_file }} owner=root mode=0600
notify: restart nginx
- name: copy TLS certificate
copy: src=files/nginx.crt dest={{ cert_file }}
notify: restart nginx
- name: copy nginx config file
template: src=templates/nginx.conf.j2 dest={{ conf_file }}
notify: restart nginx
- name: enable configuration
file: dest=/etc/nginx/sites-enabled/default src={{ conf_file }} state=link
notify: restart nginx
- name: copy index.html
template: src=templates/index.html.j2 dest=/usr/share/nginx/html/index.html
mode=0644
handlers:
- name: restart nginx
service: name=nginx state=restarted
End Result Files
This page walks through a procedure resulting in the following files:
playbooks/ansible.cfg
playbooks/hosts
playbooks/Vagrantfile
playbooks/web-notls.yml
playbooks/web-tls.yml
playbooks/files/nginx.key
playbooks/files/nginx.crt
playbooks/files/nginx.conf
playbooks/templates/index.html.j2
playbooks/templates/nginx.conf.j2