---
title: Setting up Sonarqube with Ansible - Matt v.d. Westhuizen
updated: 2019-09-09 15:03:11Z
created: 2019-09-09 15:03:11Z
tags:
  - IT
  - Development/Ansible
  - Sonarqube
source: https://medium.com/@mattpwest/setting-up-sonarqube-with-ansible-fcabadee6953
---

[![Matt v.d. Westhuizen](https://miro.medium.com/fit/c/96/96/0*Wqv3SPSz4qf-XvcE.)](https://medium.com/@mattpwest?source=post_page-----fcabadee6953----------------------)

Early last year (2017) I was embarking on a new project for a client and was setting up code quality measurements with [Sonarqube](https://www.sonarqube.org/) when I noticed that our Sonarqube server at work was a bit out of date.

We were running 5.1 which at the time was about 2 years old. It seemed it had been setup a few years ago by an employee that had since left the company and no-one really had enough of an idea of what was going on there to make an upgrade viable.

Fortunately the contract with the client required setting up build infrastructure for them in their environment, so we were able to spin up a Sonarqube server on their infrastructure to use for the project, but I still wanted to upgrade or replace the old server for the next project and for all other teams to use. Unfortunately the project I was on got a bit crazy plus the way we set it up for the client used a Docker instance, which wasn’t quite the approach we wanted to take with our server.

The result is that I’m only revisiting this side-project now a full year later. My requirements are simple:

*   Sonarqube 7.1
*   Ubuntu Server 18.04 (latest LTS)
*   [Infrastructure as code](https://en.wikipedia.org/wiki/Infrastructure_as_Code) approach to ensure the new server will be maintainable for years to come

Here’s a diagram that shows what we’ll be building:

![](https://miro.medium.com/max/60/1*Ofk2DNSW4Ds2lvJGDYzu0A.png?q=20)

![](https://miro.medium.com/max/930/1*Ofk2DNSW4Ds2lvJGDYzu0A.png)

My day job as software engineer only occasionally allows me to play with infrastructure, so my toolbox is limited to what I’ve been exposed in my 12 years of working to or have had time to learn on my own:

*   **Linux:** 15+ years of experience, mostly Debian flavours
*   **Docker:** 2+ years of experience, not a master, but I haven’t yet run into any problems I couldn’t surmount.
*   **Ansible:** 1+ years of experience, again not a master, but I’ve been able to solve most problems I’ve run across.

If I only used Linux I would probably have stopped at Docker and Docker Compose and called it good enough, but unfortunately I tend to spend a lot of time in Windows between projects requiring SQL Server databases and project administration. SQL Server is less of a problem now that that’s [available on Linux as a Docker image](https://docs.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-linux-2017), but Linux is still not officially supported by the IT department at work, so unless I want to spend my weekends fiddling with Linux I have to use Windows at work.

While Docker in theory has Windows support, I ran into a brick wall last time I tried to use it, with a long-standing showstopper bug that prevented me from just using Docker... I ended up with a Vagrant virtual machine running Ubuntu and running Docker in there to get around it. At first this was very annoying…

Eventually I realised that this is a crucial aspect of maintainable infrastructure as code… With normal software development projects one of the first things we consider when setting up our project is how people on the team will run it locally for doing development — something which is often overlooked with infrastructure projects.

Someone will set up a new server by hand and everything will be awesome for 6–12 months, when someone else decides they want to upgrade the server to the latest version of the software, but then can’t because there’s no development environment where they can test their changes.

![](https://miro.medium.com/max/60/1*D_HGCVvwkUfQsAOw1S1Iyg.png?q=20)

![](https://miro.medium.com/max/900/1*D_HGCVvwkUfQsAOw1S1Iyg.png)

> **Principle 1:** **Testability** is the key to **maintainability**. For an infrastructure project this means Vagrant VMs that imitate the target environment as closely as possible to allow testing of changes without risking production data or stability.

Putting the issues of running Docker on anything other than Linux aside, it’s an awesome tool! Docker Hub has an image for just about anything you can imagine and I’ve been able to leverage this many times to get new bits of infrastructure up and running quickly so we could try them out.

However once you enter an enterprise context a few cracks begin to appear. On my last project the client required us to use SuSE Enterprise Linux, which isn’t supported by the open-source version of Docker, so we had to get an expensive license. On top of that client infrastructure teams rarely have experience with Docker, so servers don’t have Docker installed in the first place leaving you with some manual setup to do before you can deploy. Alternatively you can automate this step with Ansible, but then you probably just end up with two things that the client infrastructure team don’t understand.

![](https://miro.medium.com/max/60/1*dcWH00fIc_e5Jeg0IMJL1w.jpeg?q=20)

![](https://miro.medium.com/max/500/1*dcWH00fIc_e5Jeg0IMJL1w.jpeg)

> **Principle 2:** **KISS**. Keep it simple stupid. Try not to use all the things if you can avoid it. Use Docker **or** Ansible - not both.

Docker is awesome for putting everything you need to run your application into nice little package that you can distribute to your servers, but what if those servers don’t have Docker and Docker Compose already installed for you? Do you manually install them on all of the servers that make up DEV, QA and PROD?

How do you handle other tasks that crop up from time to time like changing configuration across all your servers, showing a down for maintenance page during deployments or backing up the database before a deployment?

Here my answer is to use an automated provisioning and deployment tool like Ansible. I am biased towards preferring Ansible, because of my love of Linux and thanks to its light-weight nature — Ansible simply uses SSH to connect to your servers and run commands, whereas Puppet and Chef require you to install an agent on the server before they can be managed.

![](https://miro.medium.com/max/60/1*DZTts_K5lJAZ2YwhPgorIQ.jpeg?q=20)

![](https://miro.medium.com/max/500/1*DZTts_K5lJAZ2YwhPgorIQ.jpeg)

> **Principle 3: Automate all the things!** Don’t become the key person dependency on your team — automate everything to empower your team to help themselves.

With those 3 principles in mind let’s move on to setting up our Sonarqube server. There will be roughly 2 steps:

1.  Create a `Vagrantfile` to provide a local test environment.
2.  Create an Ansible play to set up the target VM with PostgreSQL and Sonarqube (using the [official Docker image](https://hub.docker.com/_/sonarqube/) would be much less work, but it means maintainers would need to know Docker as well, so it violates the KISS principle in that sense).

Throughout the remainder of this article I’ll be referring to code examples from the [GitHub repository](https://github.com/entelect/sonarqube-server) I created for this project.

The first thing to do is to create a development environment that we can use for developing our infrastructure by testing our changes on our local machine. To do this we’ll use [Vagrant](https://www.vagrantup.com/downloads.html) (2.1.1 at the time of writing).

By this point I’ve mentioned Vagrant about 5 times — in case you’re still wondering what Vagrant is, their website defines it as follows:

> Vagrant is a tool for building and managing virtual machine environments in a single workflow. With an easy-to-use workflow and focus on automation, Vagrant lowers development environment setup time, increases production parity, and makes the “works on my machine” excuse a relic of the past.
> 
> — [Vagrant Getting Started](https://www.vagrantup.com/intro/index.html)

What this equates to in real terms is that you write a small Ruby script that defines a group of virtual machines and how they should be set up. You can then simply run `vagrant up` from the command line, which will download the necessary VM images, start them up in your virtualisation tool of choice (I usually use the default Oracle Virtualbox) and then applies your scripted customisation to them. You can then simply SSH into these hosts with `vagrant ssh {hostname}` or just `vagrant ssh` to SSH into the default host (which is the first one in your `Vagrantfile`).

The `Vagrantfile` for this project looks as follows:

Line 16 selects the VM image from [Vagrant Cloud](https://app.vagrantup.com/boxes/search) to use as a base. In our case we’re using the latest Ubuntu Server 18.04 LTS (code-name bionic64).

Lines 18–22 define the control host that we’ll use to run Ansible plays.

Line 21 sets up the control host using `files/vagrant/control.ubuntu.sh`.

Lines 24–36 define the sonar01 host which is the target host we‘ll be setting up to run Sonarqube.

Lines 25–27 customise the sonar01 host to have more RAM than the default 512 MB.

Lines 31–34 expose the Sonarqube, PostgreSQL and NGINX HTTP(S) ports to the localhost, which allows you to access Sonarqube at [http://localhost:9000](http://localhost:9000/) or at [https://sonar.entelect.co.za/](https://sonar.entelect.co.za/) — the latter provided that you have a hosts file entry pointing `sonar.entelect.co.za` at `127.0.0.1`.

Line 35 sets up the sonar01 host using `files/vagrant/generic.ubuntu.sh`.

* * *

The `control.ubuntu.sh` script is responsible for setting up our Ansible control host, using the following bash script:

Lines 1–3 ensure that the control host has an RSA key pair for identifying itself.

Line 5 copies the public key out of the VM into the host OS so we can later copy it into the trusted hosts file of the target host.

Lines 7–11 configure SSH on the control host to not prompt the user to trust a new host they are SSHing into.

Lines 15–17 install Python 3, Python 3 PIP and then Ansible via Python 3 PIP, which gets us the version of Ansible that uses Python 3 instead of Python 2.

Lines 19–22 install some roles from defined in `requirements.yml` from Ansible Galaxy. In particular I am using [jdauphant.nginx](https://galaxy.ansible.com/jdauphant/nginx/) to install NGINX and [jdauphant.ssl-certs](https://galaxy.ansible.com/jdauphant/ssl-certs/) for generating the self-signed certificates.

* * *

The `files/vagrant/generic.ubuntu.sh` script is responsible for setting up our sonar01 target host, using the following simple bash script that just authorizes your control host to SSH into sonar01:

That covers setting up our development environment. To use it execute the following from the command line:

*   `vagrant up` will start all the hosts defined in the `Vagrantfile`.
*   `vagrant ssh` will SSH you into the control host.
*   `cd /vagrant` will put you in the VM folder that maps the host OS folder you are running from, so this is where you can access your Ansible plays later on to run them.

Before we dive into how we’re going to use Ansible, let’s quickly go over what Ansible is. On their website they describe the product as:

> **Ansible** is the simplest way to automate apps and IT infrastructure. Application Deployment + Configuration Management + Continuous Delivery.

What this equates to in real terms is that you write relatively simple [YAML](https://en.wikipedia.org/wiki/YAML) scripts called **Plays** in Ansible parlance. These scripts are made up of commands which are executed on target machines over SSH. The commands in Ansible can come from one of two places:

*   [**Modules**](http://docs.ansible.com/ansible/latest/user_guide/modules_intro.html)  which are mostly provided by Ansible (you can build your own as well).
*   [**Roles**](http://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html)  which are themselves essentially just more Plays designed with re-usability in mind.

The last part of the puzzle is called an **Inventory**. An inventory file defines groups of servers and configuration and you’ll typically have an inventory file per environment that you want to work with (for example DEV, QA and PRD).

When you want to perform a task you automated with Ansible, you run a **Play** against an **Inventory** from your **Control** host, which should have SSH access into all of the servers you are managing. The diagram below attempts to illustrate how this might be set up:

![](https://miro.medium.com/max/60/1*H99yXrEzaP1jljLyb3v5Wg.png?q=20)

![](https://miro.medium.com/max/822/1*H99yXrEzaP1jljLyb3v5Wg.png)

A better setup from a security point-of-view would be to have a Control host in your infrastructure layers instead of using the developer’s VM as a control host, but the approach shown above is probably the simplest setup you can use to get started short of using your laptop directly as a Control host (this is only viable on Linux though, Ansible doesn’t support Windows Control hosts).

Since I chose to set up Sonarqube myself instead of using a packaged version from Docker or a role shared on Ansible Galaxy, I needed a guide for how to set up Sonarqube. I couldn’t find one for the latest version of Sonarqube (7.1.1) and Ubuntu (18.04), so I used [this one](https://www.vultr.com/docs/how-to-install-sonarqube-on-ubuntu-16-04) for Sonarqube 6.4 on Ubuntu 16.04 to give me some basic guidance.

Let’s start with the inventory file as that’s the simplest:

Lines 3–4 define a group of servers called `sonar`, containing a single server with a host name of `sonar01`. In more production or QA scenarios this is often multiple servers for clustering.

Lines 6–7 define a group of servers called `control`, containing a single server with a host name of `control`. This is to allow us to use Ansible scripts to automate changes to the control host itself.

Lines 9–10 configure Ansible to use Python 3 instead of the default Python 2. This reduces the amount of setup we need to do on our target hosts.

Lines 12–13 tell Ansible that when it’s operating on the control host, it’s working on localhost, so it doesn’t need to SSH.

Lines 15–19 define various configuration variables that will allow us to configure our Sonarqube setup.

Line 20 defines the server DNS name.

* * *

The Ansible playbook I wrote for setting up Sonarqube is nearly 130 lines long, so to simplify explaining it I’ve broken it up into smaller bite sized chunks.

The first part is the header of the play along with 3 tasks for installing Oracle Java 8 and PostgreSQL on the target hosts:

Line 2 defines the target group of this play. In this case it will execute on the group `sonar` which if you remember the inventory file, includes a single host called `sonar01` in our local development environment.

Line 3 tells Ansible that this play should be run with `root` user privileges. Since we are not connecting to our target host using the root user, that implies that Ansible will use `sudo` to execute our commands with escalated privileges.

Lines 4–14 use the additional roles downloaded from Ansible Galaxy to set up NGINX as a reverse proxy with SSL.

Line 13 defines the an NGINX configuration template to use for configuring NGINX.

Lines 16–18 install the `ppa:webupd8team/java` PPA as an additional package sources and runs `apt-get update` to refresh the list of available packages.

Lines 20–21 is a bit of magic I got off [Stack Exchange](https://askubuntu.com/questions/190582/installing-java-automatically-with-silent-option) to turn off the interactive license prompts that occur when you install the `oracle-java8-installer` package.

Lines 23–30 install all of the OS packages we need for Sonarqube and/or our Ansible play to work using `apt-get install`. Specifically lines 17–19 are installing tools used by our Ansible scripts rather than things that are strictly necessary for running Sonarqube.

* * *

The second part of the play takes care of setting up PostgreSQL:

Lines 1–12 are how you should setup Sonarqube with Ansible… unfortunately I ran into a bug with the PostgreSQL commands not working properly when using `sudo` on newer version of Ubuntu, so I had to get a bit creative.

Lines 14–19 copy a Bash script to the server that I used to manually setup our Sonarqube PostgreSQL DB user and password and to create a Sonarqube database.

Lines 21–25 strips carriage returns out of the file — a problem you should only run into when running scripts you copied from a Windows host as we’re doing in this case. If you don’t do this the Bash interpreter chokes on the carriage returns causing your script to fail.

Lines 27–30 executes the script, creating the user and database.

The script I used to hack around the problem was quite simple:

* * *

The third and final part of the play takes care of installing and setting up Sonarqube:

Lines 1–4 create a non-root user for running Sonarqube. This was necessary, because Sonarqube uses ElasticSearch for some of its functionality and the version included in Sonarqube 7.x cannot run as the `root` user (presumably for security reasons).

Lines 6–9 downloads the Sonarqube distribution configured by the `sonar_version` variable in the inventory file.

Lines 11–16 unzips the file.

Lines 18–23 creates a symbolic link `/srv/sonarqube` to whatever Sonarqube version we extracted (for example `/srv/sonarqube-7.1.1`) — this allows us to simplify our service configuration by assuming that `/srv/sonarqube` is the current version that should be running.

Lines 25–44 configure Sonarqube with our database settings by editing the default files included in the installation zip file.

Lines 46–51 edit the launch script to configure it run with the non-root user we set up earlier.

Lines 53–56 copies over our service configuration file that will allow us to manage Sonarqube as we do other Ubuntu services with `service {name} start`, `service {name} status` and `service {name} stop`.

Lines 58–66 configure some operating system limits to the values recommended by the Sonarqube installation documentation.

Lines 68–73 starts our Sonarqube service and enables it, which means it will start automatically on boot.

That covers the main points of setting up this project. To try it out on your machine you can simply clone the repository:

`git clone [https://github.com/entelect/sonarqube-server](https://github.com/entelect/sonarqube-server)`

Using a Git Bash shell on Windows or your regular shell on Linux run the following from the project directory:

vagrant plugin install vagrant-hostmanager  
vagrant up  
vagrant ssh  
cd /vagrant  
ansible-playbook -i inventories/dev/local plays/sonar.yml

Wait a little bit after the play finishes to give everything time to start up, then try to hit: [http://localhost:9000](http://localhost:9000/). You should see your very own Sonarqube running locally in a VM:

![](https://miro.medium.com/max/60/1*3cJyWZvEBzLma3YdXyeWCg.png?q=20)

That’s it! Hopefully this will be helpful to anyone else looking to set up Sonarqube on a VM.

Some of the further enhancements I plan to make in the near future are:

*   Configure LDAP authentication so users can log in with their domain credentials.