8.3. Server setup

This section describes how to set up a server instance of DHIS2 on Ubuntu 16.04 64 bit with PostgreSQL as database system and Tomcat as Servlet container. This guide is not meant to be a step-by-step guide per se, but rather to serve as a reference to how DHIS2 can be deployed on a server. There are many possible deployment strategies, which will differ depending on the operating system and database you are using, and other factors. The term invoke refers to executing a given command in a terminal.

For a national server the recommended configuration is a quad-core 2 Ghz processor or higher and 12 Gb RAM or higher. Note that a 64 bit operating system is required for utilizing more than 4 Gb of RAM.

For this guide we assume that 8 Gb RAM is allocated for PostgreSQL and 8 GB RAM is allocated for Tomcat/JVM, and that a 64-bit operating system is used. If you are running a different configuration please adjust the suggested values accordingly! We recommend that the available memory is split roughly equally between the database and the JVM. Remember to leave some of the physical memory to the operating system for it to perform its tasks, for instance around 2 GB. The steps marked as optional, like the step for performance tuning, can be done at a later stage.

8.3.1. Creating a user to run DHIS2

You should create a dedicated user for running DHIS2. Under no circumstances, should you run the DHIS2 server as a privileged user such as root. Create a new user called dhis by invoking:

sudo useradd -d /home/dhis -m dhis -s /bin/false

Then to set the password for your account invoke:

sudo passwd dhis

Make sure you set a strong password with at least 15 random characters.

8.3.2. Creating the configuration directory

Start by creating a suitable directory for the DHIS2 configuration files. This directory will also be used for apps, files and log files. An example directory could be:

mkdir /home/dhis/config
chown dhis:dhis /home/dhis/config

DHIS2 will look for an environment variable called DHIS2_HOME to locate the DHIS2 configuration directory. This directory will be referred to as DHIS2_HOME in this installation guide. We will define the environment variable in a later step in the installation process.

8.3.3. Setting server time zone and locale

It may be necessary to reconfigure the time zone of the server to match the time zone of the location which the DHIS2 server will be covering. If you are using a virtual private server, the default time zone may not correspond to the time zone of your DHIS2 location. You can easily reconfigure the time zone by invoking the below and following the instructions.

sudo dpkg-reconfigure tzdata

PostgreSQL is sensitive to locales so you might have to install your locale first. To check existing locales and install new ones (e.g. Norwegian):

locale -a
sudo locale-gen nb_NO.UTF-8

8.3.4. PostgreSQL installation

Install PostgreSQL by invoking:

sudo apt-get install postgresql-9.5 postgresql-contrib-9.5 postgresql-9.5-postgis-2.2

Note: Alternatively you can consult the PostgreSQL documentation to install the latest version from the PostgreSQL APT repository: http://www.postgresql.org/download/linux/ubuntu/.

Create a non-privileged user called dhis by invoking:

sudo -u postgres createuser -SDRP dhis

Enter a secure password at the prompt. Create a database by invoking:

sudo -u postgres createdb -O dhis dhis2

Return to your session by invoking exit You now have a PostgreSQL user called dhis and a database called dhis2.

The PostGIS extension is needed for several GIS/mapping features to work. DHIS 2 will attempt to install the PostGIS extension during startup. If the DHIS 2 database user does not have permission to create extensions you can create it from the console using the postgres user with the following commands:

sudo -u postgres psql -c "create extension postgis;" dhis

Exit the console and return to your previous user with \q followed by exit.

8.3.5. PostgreSQL performance tuning

Tuning PostgreSQL is necessary to achieve a high-performing system but is optional in terms of getting DHIS2 to run. PostgreSQL is configured and tuned through the postgresql.conf file which can be edited like this:

sudo nano /etc/postgresql/9.5/main/postgresql.conf

and set the following properties:

max_connections = 200

Determines maximum number of connections which PostgreSQL will allow.

shared_buffers = 3200MB

Determines how much memory should be allocated exclusively for PostgreSQL caching. This setting controls the size of the kernel shared memory which should be reserved for PostgreSQL. Should be set to around 40% of total memory dedicated for PostgreSQL.

work_mem = 20MB

Determines the amount of memory used for internal sort and hash operations. This setting is per connection, per query so a lot of memory may be consumed if raising this too high. Setting this value correctly is essential for DHIS2 aggregation performance.

maintenance_work_mem = 512MB

Determines the amount of memory PostgreSQL can use for maintenance operations such as creating indexes, running vacuum, adding foreign keys. Incresing this value might improve performance of index creation during the analytics generation processes.

effective_cache_size = 8000MB

An estimate of how much memory is available for disk caching by the operating system (not an allocation) and isdb.no used by PostgreSQL to determine whether a query plan will fit into memory or not. Setting it to a higher value than what is really available will result in poor performance. This value should be inclusive of the shared_buffers setting. PostgreSQL has two layers of caching: The first layer uses the kernel shared memory and is controlled by the shared_buffers setting. PostgreSQL delegates the second layer to the operating system disk cache and the size of available memory can be given with the effective_cache_size setting.

checkpoint_completion_target = 0.8

Sets the memory used for buffering during the WAL write process. Increasing this value might improve throughput in write-heavy systems.

synchronous_commit = off

Specifies whether transaction commits will wait for WAL records to be written to the disk before returning to the client or not. Setting this to off will improve performance considerably. It also implies that there is a slight delay between the transaction is reported successful to the client and it actually being safe, but the database state cannot be corrupted and this is a good alternative for performance-intensive and write-heavy systems like DHIS2.

wal_writer_delay = 10000ms

Specifies the delay between WAL write operations. Setting this to a high value will improve performance on write-heavy systems since potentially many write operations can be executed within a single flush to disk.

Restart PostgreSQL by invoking sudo /etc/init.d/postgresql restart

8.3.6. Database configuration

The database connection information is provided to DHIS2 through a configuration file called dhis.conf. Create this file and save it in the DHIS2_HOME directory. As an example this location could be:

sudo -u dhis nano /home/dhis/config/dhis.conf

A configuration file for PostgreSQL corresponding to the above setup has these properties:

# Hibernate SQL dialect
connection.dialect = org.hibernate.dialect.PostgreSQLDialect

# JDBC driver class
connection.driver_class = org.postgresql.Driver

# Database connection URL
connection.url = jdbc:postgresql:dhis2

# Database username
connection.username = dhis

# Database password
connection.password = xxxx

# Database schema behavior, can be validate, update, create, create-drop
connection.schema = update

# Encryption password (sensitive)
encryption.password = xxxx

The encryption.password property is the password used when encrypting and decrypting data in the database. Note that the password must not be changed once it has been set and data has been encrypted as the data can then no longer be decrypted. Remember to set a strong password of at least 24 characters.

Note that the configuration file supports environment variables. This means that you can set certain properties as environment variables and have them resolved by DHIS 2, e.g. like this where DB_PASSWD is the name of the environment variable:

connection.password = ${DB_PASSWD}

A common mistake is to have a white-space after the last property value so make sure there is no white-space at the end of any line. Also remember that this file contains the clear text password for your DHIS2 database so it needs to be protected from unauthorized access. To do this invoke the following command which ensures that only the dhis user which owns the file is allowed to read it:

chmod 0600 dhis.conf

8.3.7. Java installation

Oracle Java 8 JDK is the recommended Java option as it provides the greatest operating system support including Ubuntu LTS 14.04. The webupd8team Java PPA provides the necessary packages.

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer

Check that your installation is okay by invoking:

java -version

You can also ensure that the appropriate environment variables are set by installing this package:

sudo apt-get install oracle-java8-set-default

8.3.8. Tomcat and DHIS2 installation

To install the Tomcat servlet container we will utilize the Tomcat user package by invoking:

sudo apt-get install tomcat7-user

This package lets us easily create a new Tomcat instance. The instance will be created in the current directory. An appropriate location is the home directory of the dhis user:

cd /home/dhis/
sudo tomcat7-instance-create tomcat-dhis
sudo chown -R test:test test-dhis/

This will create an instance in a directory called tomcat-dhis. Note that the tomcat7-user package allows for creating any number of dhis instances if that is desired.

Next edit the file tomcat-dhis/bin/setenv.sh and add the lines below. The first line will set the location of your Java Runtime Environment, the second will dedicate memory to Tomcat and the third will set the location for where DHIS2 will search for the dhis.conf configuration file. Please check that the path the Java binaries are correct as they might vary from system to system, e.g. on AMD systems you might see /java-7-openjdk-amd64 Note that you should adjust this to your environment:

export JAVA_HOME='/usr/lib/jvm/java-8-oracle/'
export JAVA_OPTS='-Xmx7500m -Xms4000m'
export DHIS2_HOME='/home/dhis/config'

The Tomcat configiration file is located in tomcat-dhis/conf/server.xml. The element which defines the connection to DHIS is the Connector element with port 8080. You can change the port number in the Connector element to a desired port if necessary. If UTF-8 encoding of request data is needed, make sure that the URIEncoding attribute is set to UTF-8.

<Connector port="8080" protocol="HTTP/1.1"
  URIEncoding="UTF-8" />

The next step is to download the DHIS2 WAR file and place it into the webapps directory of Tomcat. You can download the DHIS2 version 2.23 WAR release like this (replace 2.23 with your preferred version if necessary):

wget https://www.dhis2.org/download/releases/2.26/dhis.war

Move the WAR file into the Tomcat webapps directory. We want to call the WAR file ROOT.war in order to make it available at localhost directly without a context path:

mv dhis.war tomcat-dhis/webapps/ROOT.war

DHIS2 should never be run as a privileged user. After you have modified the setenv.sh file, modify the startup script to check and see if the script has been invoked as root.

set -e

if [ "$(id -u)" -eq "0" ]; then
  echo "This script must NOT be run as root" 1>&2
  exit 1

export CATALINA_BASE="/home/dhis/tomcat-dhis"
echo "Tomcat started"

8.3.9. Running DHIS2

DHIS2 can now be started by invoking:

sudo -u dhis tomcat-dhis/bin/startup.sh

The DHIS2 server should never be run as root or other privileged user.

DHIS2 can be stopped by invoking:

sudo -u dhis tomcat-dhis/bin/shutdown.sh

To monitor the behavior of Tomcat the log is the primary source of information. The log can be viewed with the following command:

tail -f tomcat-dhis/logs/catalina.out

Assuming that the WAR file is called ROOT.war, you can now access your DHIS2 instance at the following URL: