Automating Blog Hosting With Ansible


This blog post is a hands down tutorial on provisioning a server by hosting a blog using Git and nginx with Ansible.

Ansible is a configuration management system. Ansible by default uses the SSH protocol to manage machines. There are other configuration tools like Puppet and Chef, however these require you to install a small piece of software on the client server. Hence, my preference to Ansible.

Installing Ansible#

We only need to install Ansible on the local computer. However make sure the server has Python 2.7 installed.

If you have brew installed on a Mac OS. You can simply do

$ brew install ansible

For Ubuntu,

$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible

Please refer to Ansible Installation Docs to install on more OS’s

Ansible Basics#

There are two ways you can use Ansible depending on your use case. Firstly, use can use Ansible like bash scripts. These will be lists of tasks that you use to provision the server.

Secondly, we can use Ansible to create roles. Ansible uses roles to seperate it’s blocks of tasks. This allows you to copy blocks from one playbook to another without any hassle. A playbook in essence is how your tasks and roles are executed. Addtionally, it can be uploaded into Ansible Galaxy for other people to use it.

An Ansible Role needs to have a specific directory structure. You can manually create this directory structure; an easier way is to use ansible-galaxy init newrole.

This command creates the follwing directory strcuture.

├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
└── vars
    └── main.yml

Now lets explain each of these.

files: This directory contains files that will be copied to the host.

handlers: These are basically tasks which are can be notified to be run after tasks are completed.

meta: This file cotains the meta information and dependency roles.

templates: This directory contains templates that use variable subsitution and, then copy it in your host.

tasks: It contains all of the tasks that the playbook needs to run.

vars: These are variables that you can use in your roles.


  1. Make sure you have access to a remote or local Ubuntu Server. I use DigitalOcean to cater for all my server needs since it is quick and easy to spin up machines. Quick Bonus: if you sign up throught this link you get $10 in DigitalOcean credit.

  2. Also make sure you have a static website or a webpage as a git repository.

All Ansible Playbooks are written in YAML.

Now lets get the ball rolling,

Clone the static website from the git respository. But, make sure you change the repo url. Additionally, make sure you set approriate variables in the vars folder. The {{ user }} variable has no default value so make sure you add one to the vars file.

- name: Clone Blog From Github using HTTPS
    dest: /home/{{ user }}/blog
    version: master
    update: yes

We will use nginx as a webserver. You can also use Apache as well, however the following configuration is for nginx.

- name: Install nginx
    package: nginx
    state: latest

Now, lets create a template configuration for nginx virtual host.

server {
   listen 80;
   listen [::]:80;

   server_name {{ domain }}  www.{{ domain }};

    root /home/{{ user }}/blog;
    index index.html;

   location / {
       try_files $uri $uri/ =404;

All variables are replaced using variables defined in the vars directory so make sure these are defined.

Copy this template and configure the nginx symlink. Also make sure that you have removed the default symlink which can cause confliting issues between two nginx configuration.

- name: Copy Nginx Config for Blog to Host
    src: blog.conf.http.j2
    dest: /etc/nginx/sites-available/blog.nginx.conf

- name: Add Symlink to Host
    src: /etc/nginx/sites-available/blog.nginx.conf
    dest: /etc/nginx/sites-enabled/blog
    state: link
  notify: restart nginx

- name: Remove default symlink
    path: /etc/nginx/sites-enabled/default
    state: absent

Now lets create a handler to restart nginx. If there are any changes to the file the notify tag is executed and nginx is reloaded.

- name: reload nginx
  service: name=nginx state=reloaded

  # basically you are doing -> sudo service nginx [options]

Now, your website should be running on your {{ domain }} as listed on your vars directory.