How to Deploy Multiple Wordpress Sites Using Virtualmin and Ansible on Ubuntu 16.04

Last Updated: Mon, Jan 29, 2018
Blogging Linux Guides Ubuntu
Archived content

This article is outdated and may not work correctly for current operating systems or software.

A common usage of a Vultr virtual server is to host Wordpress websites. This guide shows you how to automate the configuration of a virtual server from scratch (using Ansible) and deploy multiple independent Wordpress websites (using Webmin/Virtualmin). Virtualmin/Webmin is a graphical user interface that allows you to manage deployment of multiple virtual server accounts on the same machine (complete with LAMP/LEMP stack). Virtualmin is very similar to cPanel and Plesk, and in this tutorial we'll be using the free GPL edition.

After initial setup of the Vultr server and installation of Virtualmin, you can very quickly setup multiple virtual servers from within the Virtualmin interface and directly install Wordpress on that virtual server complete with its own domain name.

In this tutorial, instead of manually entering a long list of commands, we'll instead use Ansible. Ansible is a python based automation tool which allows you to reliably and repeatedly automate server tasks. This means once you've followed this tutorial, you'll be able to deploy another server in the same way with just a couple of commands.

Prerequisites

  • At least one Fully-Qualified Domain Name and access to the DNS records

  • A Vultr account

Step 1 - Installing Ansible on your local machine

Install Ansible on your local machine or another server.

mkdir ansible

cd ansible

virtualenv env

source env/bin/activate

pip install ansible

Step 2 - Generate SSH keys and deploy server

Ansible works by logging into your server via SSH. SSH access is most secure if we use keys rather than a password. Let's first generate a public and private key pair.

mkdir ssh_keys

ssh-keygen -t rsa -b 2048 -f ./ssh_keys

In the ssh_keys directory there will now be two files, ssh_keys and ssh_keys.pub. ssh_keys is your private key file and should be kept safe. You can now open the ssh_keys.pub, which contains the public key.

Login to the Vultr web dashboard and click Deploy New Server.

Select a region, Server type (Ubuntu 16.04), Server size, and then in part 6 (SSH keys), click Add New. On the next page paste your public key and give it a name, and click Add SSH key. Finally ensure that key is selected and click Deploy now.

Once the server has finished deploying you'll be shown its ip address. You'll need to login to your domain name's DNS server and point it to this address.

Step 3 - Create a basic Ansible configuration

Ansible's automation files are called roles. We'll first setup the directory structure (inside the ansible directory you just created in step 1), and the basic files.

mkdir -p group_vars roles/common/tasks/ roles/common/handlers

touch hosts group_vars/all deploy.yml roles/common/handlers/main.yml

Edit the hosts file to contain the following, substituting the ip address for the server you just created. Ansible uses python 2, which Ubuntu 16.04 doesn't have installed by default. In the hosts file we tell Ansible to use python 3.

[common]  

192.0.2.1 ansible_python_interpreter=/usr/bin/python3

Edit the deploy.yml file to contain the following. We are going to be using the root user.

- name: apply common configuration to server

  hosts: all

  user: root

  roles:

    - common

Edit the /group_vars/all file to contain the following. These variables tell Ansible the location of your SSH keys, swap file parameters, your Fully Qualified Domain Name and the root password. Please remember not to include the file in source control as it contains your password in clear text.

ssh_dir: ./ssh_keys

swap_file_path: /swapfile

swap_file_size: 1G

swappiness: 1

hostname: example.com

new_password: YOUR_PASSWORD_HERE

Edit the common/handlers/main.yml file to contain the following.

- name: restart sshd

  service: name=ssh state=restarted

Step 4 - Create Ansible tasks for basic server setup

Ansible automation is easier to understand if we break it down into tasks. Let's create files for each of our tasks in the process.

cd roles/common/tasks

touch hosts main.yml setup.yml users.yml ufw.yml swap.yml virtualmin.yml

main.yml should point to each file containing the Ansible commands, so edit it to contain the following.

- include: setup.yml

- include: users.yml

- include: ufw.yml

- include: swap.yml

- include: virtualmin.yml

The first step in setting up a new server is to update the repo cache and set the timezone. Edit the common/handlers/setup.yml file to contain the following.

- apt: update_cache=yes

  sudo: yes



- name: set timezone to Europe/London

  timezone:

    name: Europe/London

Now, we'll give the root user a password (which we will need to access the virtualmin web interface), but disable password logins over SSH (since we are using the more secure keys method of authentication). Edit users.yml to contain the following.

- name: Change passwd

  user: name=root password={{ new_password | password_hash('sha512') }} update_password=always



- name: Disable SSH password login

  lineinfile: dest=/etc/ssh/sshd_config regexp="^#?PasswordAuthentication" line="PasswordAuthentication no"

  notify: restart sshd

For security, we need a firewall. We'll use the Uncomplicated Firewall to allow SSH access on port 22, web access on port 80 and secure web access on port 443. Edit the ufw.yml file to contain the following.

- name: Set default firewall policy to deny all

  become: True

  ufw: state=enabled direction=incoming policy=deny

  tags: firewall



- name: enable SSH in firewall

  ufw: rule=allow port=22

  sudo: yes



- name: enable HTTP connections for web server

  ufw: rule=allow port=80

  sudo: yes



- name: enable HTTPS connections for web server

  ufw: rule=allow port=443

  sudo: yes



- name: enable firewall

  ufw: state=enabled

  sudo: yes

Optionally, you can include a swap file. This is essential if your server has less than 2GB RAM to avoid out of memory crashes. Edit swap.yml to contain the following.

- name: Set swap_file variable

  set_fact:

    swap_file: "{{swap_file_path}}"

  tags:

    - swap.set.file.path



- name: Check if swap file exists

  stat:

    path: "{{swap_file}}"

  register: swap_file_check

  tags:

    - swap.file.check



- name: Create swap file

  command: fallocate -l {{swap_file_size}} {{swap_file}}

  when: not swap_file_check.stat.exists

  tags:

    - swap.file.create



- name: Change swap file permissions

  file: path="{{swap_file}}"

        owner=root

        group=root

        mode=0600

  tags:

    - swap.file.permissions



- name: Format swap file

  sudo: yes

  command: "mkswap {{swap_file}}"

  when: not swap_file_check.stat.exists

  tags:

    - swap.file.mkswap



- name: Write swap entry in fstab

  mount: name=none

         src={{swap_file}}

         fstype=swap

         opts=sw

         passno=0

         dump=0

         state=present

  tags:

    - swap.fstab



- name: Turn on swap

  sudo: yes

  command: swapon -a

  when: not swap_file_check.stat.exists

  tags:

    - swap.turn.on



- name: Set swappiness

  sudo: yes

  sysctl:

    name: vm.swappiness

    value: "{{swappiness}}"

  tags:

    - swap.set.swappiness

Step 5 - Add Ansible task for virtualmin setup

Virtualmin has its own installer file which can be downloaded and run by Ansible. Here we are using the minimal install (LINK). The additional items are to configure the MySQL server password which is not set when installed by Virtualmin. We need to temporarily stop MySQL and add the authentication directory prior to changing the password. Edit virtualmin.yml to contain the following.

- name: download virtualmin install script

  get_url: >

    url=http://software.virtualmin.com/gpl/scripts/install.sh

    dest=/root/install.sh

    mode=0755



- name: virtualmin install (takes around 10 mins) you can see progress using $ sudo tail -f /root/virtualmin-install.log

  tags: non-idem

  shell: ~/install.sh --force --hostname {{ hostname }} --minimal --yes

  args:

    chdir: /root



- name: temp stop mysql

  service:

    name: mysql

    state: stopped



- name: change owner (and group) of mysqld dir

  file:

    path: "/var/run/mysqld"

    state: directory

    owner: mysql

    group: mysql



- name: virtualmin set mysql password

  shell: virtualmin set-mysql-pass --user root --pass {{ new_password }}



- name: restart mysql

  service:

    name: mysql

    state: started

The Ansible role is now finished and we're ready to deploy.

Step 6 - Perform install with Ansible

From the ansible folder, we can now simply run the following command, and Ansible will carry out all of the tasks we have created automatically. The first time you connect you'll get an SSH key warning, just type "yes" at the prompt.

ansible-playbook deploy.yml --private-key=ssh_keys/ssh_keys -i hosts

If we wish to use another server, we can simply change the ip address in the hosts file and run that command again to complete exactly the same setup.

Step 7 - Virtualmin post-installation wizard

The installation is complete and we can now go to https://192.0.2.1:10000 (use the ip address of your server). Your browser will issue a security warning because the certificate is self signed, so click advanced and add an exception. You will be presented with a login page. The username is root, and the password is the one you entered into group_vars/all file in step 3. The first time you enter Virtualmin you'll be presented with the post-installation wizard. You can either go through these settings manually or click cancel to accept the defaults.

Step 8 - Create a server and install WordPress

To get your first Wordpress server up and running, from the Virtualmin dashboard click Create Virtual Server. You'll need to enter a domain name, description and an administrators password. The domain name should be different from the Virtualmin fully qualified domain name, and you'll need to point the DNS record to the ip address of your server.

Click Create Server. Once Virtualmin has finished creating your server, click Install Scripts on the left hand menu. Select Wordpress, click Show install options, and on the following page choose the location of the Wordpress install. Just choose At top level and click Install Now.

That's all you need to do - you can complete the Wordpress install by visiting your http://example.net/wp-admin/install.php (where example.net is this virtual servers domain name). If your DNS records haven't propagated yet you can go to Services > Preview Website from the Virtualmin menu.

You can repeat this step multiple times to create multiple Wordpress sites all on the same Vultr server.

Want to contribute?

You could earn up to $600 by adding new articles.