Commands to install DHIS2 2.38 on an AWS t2.medium EC2 instance with ubuntu 18.04 LTS with 2 vCPUs and 4GB of RAM

Alright, if you are new, be forewarned before installing DHIS2 for your needs. There are a ton of links on this forum, but many of them are now dead and just forward you to the general documentation page (which also only seems to contain general and non-specific information)

If you are not new, I welcome any feedback to my ubuntu DHIS2 install cheat sheet and if I get time I’d be happy to update this thread with the latest, or I’ll incorporate it into my next version if I ever get to that.

I also found the academy clunky, but the official DHIS2 youtube channel (@DHIS2org) far easier to just burn through content.

If you need a specific thing done in your DHIS2 implementation, I’ve also had a lot of success just comparing stuff (org units, data elements, data sets, programs, users, etc) with how stuff has been setup in the demo server.

That being said, you first have to get a working server going first, so hopefully this guide helps a few folks before it also becomes out of date.

My next few goals are to actually get https to work, and to re-do this guide except for using Ubuntu, 22.04 LTS, Tomcat 9, DHIS2 2.39. Having the latest ubuntu would be really nice as it also just has the AWS command line built into the AWS gui which isn’t something that is setup by default in 18.04.

Without further ado, my guide mostly follows this super helpful but also outdated guide:

But started by trying to use this more official but also outdated guide:

My specific cheat sheet installs DHIS2 2.38 on an AWS t2.medium EC2 instance with ubuntu 18.04 LTS with 2 vCPUs and 4GB of RAM.

The first hurdle after creating the AWS EC2 instance is you need to get logged in. The IP to connect to is the public IP of the EC2 instance and the username will just be lowercase ubuntu. There won’t be a text password because you will authenticate using the keyfile that you either generated or uploaded.

Log in using ssh ubuntu@publicIPofEC2InstanceHere and and keyfile. I used a windows computer to connect to the AWS ubuntu instance using a with a putty key that I generated upon server install. If you are familiar with putty, you can add a profile and setup the key by going to the SSH > Auth > Credentials > Private key file for authentication > browse to .ppk file here. Then name and save the session so you don’t need to do this again before hitting connect.

Setting server time zone

sudo dpkg-reconfigure tzdata

(used PST for this server)

— Creating an Ubuntu user to run DHIS2 —
Create a new user called ‘dhis’ by invoking:

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

Then set the password for the account by invoking:

sudo passwd dhis

Make sure you set a strong password


Creating the configuration directory

sudo mkdir /home/dhis/config

Set ownership of the directory to ‘dhis’ user created above

sudo chown dhis:dhis /home/dhis/config

PostgreSQL installation

sudo apt update
sudo apt install postgresql postgresql-contrib

Create a non-privileged PostgreSQL user called ‘dhis’ by invoking:

sudo -u postgres createuser -SDRP dhis

Give a password for the new PostgreSQL user when prompted.


Create a database by invoking:

sudo -u postgres createdb -O dhis dhis2

Found on Installing PostGIS after PostgreSQL Ubuntu 18.04 - Geographic Information Systems Stack Exchange

sudo add-apt-repository ppa:ubuntugis/ppa

Once this is done, you should be able to install postgis in the typical way:

sudo apt install postgis

Create the PostGIS extension, and 2 other extensions (found these by watching catalina.out for errors)

sudo -u postgres psql -c "create extension postgis;" dhis2
sudo -u postgres psql -c "create extension pg_trgm;" dhis2
sudo -u postgres psql -c "create extension btree_gin;" dhis2

Creating DHIS2 configuration file

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

Insert following lines to the file (update database PostgreSQL dhis password according what you set for the database password above):

# 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 = StrongDatabasePasswordHere

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

# Encryption password (sensitive)
encryption.password = StrongEncryptionPasswordHere

— Java installation —
To install OpenJDK run below command:

sudo apt-get install openjdk-11-jdk

The usual location of installation is /usr/lib/jvm/java-11-openjdk-amd64 which may change depending on the java version. Run below command to check the exact directory:

ls /usr/lib/jvm

— Tomcat and DHIS2 installation —

sudo apt-get install tomcat8-user

To create a Tomcat instance for DHIS2 move to the dhis folder created above:

cd /home/dhis/

Create a Tomcat instance:

sudo tomcat8-instance-create tomcat-dhis

Set ownership of the created folder to dhis user

sudo chown -R dhis:dhis /home/dhis/tomcat-dhis/


sudo nano /home/dhis/tomcat-dhis/bin/

Add the following lines to the bottom of the file:

export JAVA_HOME='/usr/lib/jvm/java-11-openjdk-amd64/'
export JAVA_OPTS='-Xmx2056m -Xmx2056m'
export DHIS2_HOME='/home/dhis/config'

Please make sure the java installation directory matches the path given in JAVA_HOME above.

Extra info on why I set the Xms/Xmx how I chose to. Also take with a grain of salt because the official documentation says something different and there might be better info on these settings somewhere else. Also I didn’t touch the PostgreSQL settings that the official docs actually do go into. If you leave it to the defaults, it’ll at least get you up and running and future tweaks can be made from there, however I don’t feel confident making those tweaks to my live server just yet.

# -Xms/Xmx
#  Xms Sets the initial size of the Heap
#  Xmx sets the Maximum size of the Heap.

For 4gb ram, just reserved half for java:
    export JAVA_OPTS='-Xmx2056m -Xmx2056m'

For 8gb ram, also just reserved half for java:
    export JAVA_OPTS='-Xms4096m -Xmx4096m'

The Tomcat configuration 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. The relaxedQueryChars attribute is necessary to allow certain characters in URLs used by the DHIS2 front-end.

sudo nano /home/dhis/tomcat-dhis/conf/server.xml
<Connector port="8080" protocol="HTTP/1.1"
  relaxedQueryChars="[]" />

The next step is to download the DHIS2 WAR file and place it into the webapps directory of Tomcat:
The 2.39 version seems to display a blank page, so moved back to the 2.38 version

cd /home/dhis/
sudo wget

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:

sudo mv dhis2-stable-latest.war /home/dhis/tomcat-dhis/webapps/ROOT.war

DHIS2 should never be run as a privileged user, so edit the

sudo nano /home/dhis/tomcat-dhis/bin/

Replace everything in the file with the following lines:

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"

— Running DHIS2 —
DHIS2 can now be started by invoking:

cd /home/dhis/
sudo -u dhis /home/dhis/tomcat-dhis/bin/

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

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

To just output everything in the log to the terminal do:

sudo cat /home/dhis/tomcat-dhis/logs/catalina.out

DHIS2 can be stopped by invoking:

cd /home/dhis/
sudo -u dhis tomcat-dhis/bin/

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


Default login details:

Username: admin
Password: district

— Basic nginx setup —
We recommend using nginx as a reverse proxy due to its low memory footprint and ease of use. To install invoke the following:

sudo apt-get install nginx

Now that we have installed nginx we will now continue to configure regular proxying of requests to our Tomcat instance, which we assume runs at


To configure nginx you can open the configuration file by invoking:

sudo nano /etc/nginx/nginx.conf

Replace the http { section with this:

http {
	gzip on; # Enables compression, incl Web API content-types
		"application/json;charset=utf-8" application/json
		"application/javascript;charset=utf-8" application/javascript text/javascript
		"application/xml;charset=utf-8" application/xml text/xml
		"text/css;charset=utf-8" text/css
		"text/plain;charset=utf-8" text/plain;
		server {
		listen               80;
		client_max_body_size 10M;
		# Proxy pass to servlet container
		location / {
			proxy_pass                http://localhost:8080/;
			proxy_redirect            off;
			proxy_set_header          Host               $host;
			proxy_set_header          X-Real-IP          $remote_addr;
			proxy_set_header          X-Forwarded-For    $proxy_add_x_forwarded_for;
			proxy_set_header          X-Forwarded-Proto  http;
			proxy_buffer_size         128k;
			proxy_buffers             8 128k;
			proxy_busy_buffers_size   256k;
			proxy_cookie_path         ~*^/(.*) "/$1; SameSite=Lax";

nginx can now be started, reloaded and stopped with the following commands:

sudo /etc/init.d/nginx start
sudo /etc/init.d/nginx reload
sudo /etc/init.d/nginx stop

---- To make sure nginx boots upon startup or reboot, do this: ----

sudo systemctl edit nginx

then paste in:



To check to make sure this was applied use this command:

sudo service --status-all

To verify nginx is running with:

systemctl status nginx

To test nginx’s restart capablities kill it via

pkill -f nginx

If NGINX is down due to, e.g. the OOM killer, it will be restarted after dying. If you have a configuration error in NGINX, it will not be restarted, of course. Used the 2nd answer here: amazon web services - How to automatically restart Nginx when it goes down - Server Fault

— To start DHIS2 at server startup or reboot use crontab Crontab Reboot: Execute a Job Automatically at Boot | phoenixNAP ----

crontab -e
1 (Choose your fav text editor, in my case nano) 

@reboot sudo -u dhis /home/dhis/tomcat-dhis/bin/

— Last but not least, make sure to log into the new DHIS2 instance and changed admin password to be something other than the default —

Default login details:
Username: admin
Password: district
1 Like

Thank you for sharing your experience and knowledge with the community. Every contribution counts. :clap::tada:

Your feedback is also important if there’s a specific thing that you believe could be improved, please feel free to open a topic in the #forum-feedback category. :pray: