Skip to content

Installation guide

Installation guide for OpenOlat 21.0 and greater

This guide walks you through installing OpenOlat Version 21.0.x or newer on a local GNU/Linux or similar system using Tomcat 10.1, Java 17 and PostgreSQL 18. If you already have an up and running installation, see our Update Guide

If you really want to install OpenOlat using MySQL as database, have a look at the Special topics -> MySQL DB section and try mixing it with the information found in here. Please keep in mind that this is not recommended.

Supported releases

Currently supported releases are:

Supported releases

  • 20.3.x and 21.0.x
  • Other releases are not supported anymore

Older releases are not supported anymore and don't get any security updates. Long term releases are normally not under active development, but will get critical security updates.

Please upgrade as soon as possible if you have an older unsuppored release installed.

Note

Security relevant issues are only visible to members of the OpenOlat partner program. Make sure you always update to the latest release to get all security patches.

Create a user for OpenOlat

The username is openolat in this guide with home directory in /home/openolat/. From here onwards, do everything as the user openolat (unless pointed out differently). To create the user, you can simply use the command

useradd -m -s /bin/bash openolat

Download software

We recommend using the following software packages:

Create a directory downloads and keep the downloaded files there:

openolat~$ cd && mkdir downloads && cd downloads
openolat~$ ls -l downloads
-rw-rw-r-- 1 openolat openolat  12127326 Feb  9 10:51 apache-tomcat-10.1.57.tar.gz
-rw-rw-r-- 1 openolat openolat 191502157 Feb  9 10:51 OpenJDK17U-jdk_x64_linux_hotspot_17.0.19_10.tar.gz
-rw-rw-r-- 1 openolat openolat 181853117 Mar 17 15:41 openolat_2101.war

You do not need to use the exact versions from this manual, this is just an example. We recommend that you use the newest version within the given major version: Java 17, Tomcat 10.1. As for OpenOlat, please use the newest release. If not, make sure to use a version 20.3.x or newer. Note that you do not need a JDK to run OpenOlat, a JRE will work as well.

Prepare home directory

In the home directory:

openolat~$ cd
openolat~$ tar xvf downloads/apache-tomcat-10.1.57.tar.gz
openolat~$ ln -s apache-tomcat-10.1.57 tomcat

openolat~$ tar xvf downloads/OpenJDK17U-jdk_x64_linux_hotspot_17.0.19_10.tar.gz
openolat~$ ln -s jdk-17.0.19+10 jre

openolat~$ unzip -d openolat-21.0.1 downloads/openolat_2101.war
openolat~$ ln -s openolat-21.0.1 webapp

Note that this setup allows you to switch between different versions of JRE and tomcat by adjusting the symlinks jre and tomcat. An update works the same way, just stop OpenOlat, remove the symlink to webapp, unzip a new version and make a new symbolic webapp link.

Create tomcat dirs

Set up tomcat in home directory

openolat~$ mkdir bin conf lib run logs

web.xml and catalina.sh

Link the following files:

openolat~$ cd ~/conf
openolat~$ ln -s ../tomcat/conf/web.xml web.xml
openolat~$ cd ~/bin
openolat~$ ln -s ../tomcat/bin/catalina.sh catalina.sh

Create additional, handy links:

openolat~$ cd
openolat~$ ln -s tomcat/bin/startup.sh start
openolat~$ ln -s tomcat/bin/shutdown.sh stop

setenv.sh

Create the file ~/bin/setenv.sh containing

CATALINA_HOME=~/tomcat
CATALINA_BASE=~
JRE_HOME=~/jre
CATALINA_PID=~/run/openolat.pid
CATALINA_TMPDIR=/tmp/openolat
mkdir -p $CATALINA_TMPDIR

CATALINA_OPTS=" \
-Xmx1024m -Xms512m -XX:MaxMetaspaceSize=512m \
-Duser.name=openolat \
-Duser.timezone=Europe/Zurich \
-Dspring.profiles.active=myprofile \
-Djava.awt.headless=true \
-Djava.net.preferIPv4Stack=true \
-Djava.security.egd=file:/dev/urandom \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=. \
"

The scripts of tomcat will parse this file at startup.

What this does

This file tells Tomcat how to start OpenOlat. The first line of CATALINA_OPTS is the one that matters most: it gives the Java process at most 1 GB of memory for the application data (-Xmx1024m) and 512 MB for the loaded program code (-XX:MaxMetaspaceSize=512m). These values are sized for a local test installation. For a production server, raise them according to the expected number of concurrent users, and add memory for PostgreSQL and the operating system on top. The remaining lines set the time zone and the configuration profile, and write a memory dump to disk if OpenOlat runs out of memory, which helps to analyse the problem.

server.xml

Create the file ~/conf/server.xml

<?xml version='1.0' encoding='utf-8'?>
<Server port="8085" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <Connector port="8088" protocol="HTTP/1.1" maxPartCount="-1" maxParameterCount="-1" />
    <Engine name="Catalina" defaultHost="localhost">
      <Host name="localhost"  appBase="webapps" />
    </Engine>
  </Service>
</Server>

What this does

This file configures Tomcat, the web server that runs OpenOlat. Port 8088 is where the browser reaches OpenOlat, port 8085 is an internal port that Tomcat uses to shut down. The two -1 values remove the default limits on the number of uploaded file parts and form fields per request. OpenOlat needs this for large forms and uploads with many files.

Make sure the chosen ports (8085 and 8088 in this example) are available. Set the environment variables CATALINA_HOME and JRE_HOME, for example by appending the following to your ~/.bashrc

export CATALINA_BASE=~
export CATALINA_HOME=~/tomcat
export JRE_HOME=~/jre

and activate them by issuing

openolat~$ . .bashrc

Test tomcat

openolat~$ ./start

... should output look something like this:

Using CATALINA_BASE:   /home/openolat
Using CATALINA_HOME:   /home/openolat/tomcat
Using CATALINA_TMPDIR: /tmp/openolat
Using JRE_HOME:        /home/openolat/jre
Using CLASSPATH:       /home/openolat/tomcat/bin/bootstrap.jar:/home/openolat/  tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:   -Xmx1024m -Xms512m -XX:MaxMetaspaceSize=512m     -Duser.name=openolat -Duser.timezone=Europe/Zurich      -Djava.security.egd=file:/dev/urandom   -Dspring.profiles.active=myprofile -Djava.awt.headless=true     -Djava.net.preferIPv4Stack=true -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=.
Using CATALINA_PID:    /home/openolat/run/openolat.pid
Existing PID file found during start.
Removing/clearing stale PID file.
Tomcat started.

Check whether these values make sense, then stop tomcat again

openolat~$ ./stop

Set up postgresql

This setupguide should work with all PostgreSQL Versions from 9.1 on. Our recommendation is to use the most recent, stable version. This manual has been tested with versions up to 18.

User and DB

Do the following as root user:

root~# su - postgres

and then as user postgres (you may need the postgresql db password, but usually not):

postgres~$ psql

Now while logged in to postgresql, we create the user and the database:

postgres=# create user oodbu with password 'oodbpasswd';
postgres=# create database oodb with owner oodbu;

What this does

OpenOlat stores all structured data such as users, courses and assessment results in a PostgreSQL database. These two commands create a database user oodbu with the password oodbpasswd and an empty database oodb that belongs to this user. Replace the password with your own. You enter the same three values later in the application context descriptor ROOT.xml, so that OpenOlat can connect to its database. Files that users upload are not stored in the database but in the folder set as userdata.dir in the OpenOlat configuration.

Test DB access

Test the account as openolat user:

openolat~$ psql oodb -U oodbu -h localhost

You should get the postgresql client prompt after providing your password.

Optional: pgvector for AI-powered taxonomy matching

OpenOlat 21.0's embedding-based taxonomy matching feature (taxonomy.matching.enabled) needs PostgreSQL 18 with the pgvector extension installed:

postgres=# \c oodb
oodb=# create extension if not exists vector;

Create DB schema

The database schema is created automatically when starting OpenOlat the first time. If you want to have more control over the process you can setup it yourself:

Create the openolat database schema, as user openolat:

oodb=> \i /home/openolat/webapp/WEB-INF/classes/database/postgresql/setupDatabase.sql

Note

As of 17.2.2 the database files are not in the compiled war file anymore as all files in the classes directory are delivered in a jar. You can unpack the openolat/WEB-INF/lib/openolat-lms-xx.x-SNAPSHOT file to find the files or download it from GitHub.

Optionally

Create a file named ~/.pgpass containing

#hostname:port:database:username:password
localhost:5432:oodb:oodbu:oodbpasswd

This way you can access the database by typing psql -h localhost and will connect to the right db without pw

OpenOlat configuration

Create the file ~/lib/olat.local.properties

db.source=jndi
db.jndi=java:comp/env/jdbc/openolatDS
db.vendor=postgresql
installation.dir=/home/openolat
log.dir=/home/openolat/logs
server.contextpath=/openolat
server.domainname=localhost
server.port=8088
server.port.ssl=0
smtp.host=disabled
tomcat.id=1
userdata.dir=/home/openolat/olatdata

What this does

This is the main configuration file of OpenOlat. Every setting you change for your installation goes here, the built-in defaults stay untouched inside the application. The example tells OpenOlat where to find its database (through Tomcat, db.source=jndi), where to write logs and user files, under which domain and port it runs, and switches mail sending off (smtp.host=disabled). For a real installation, replace localhost with your domain name and configure a mail server, otherwise OpenOlat cannot send registration and notification mails.

OpenOlat can deliver user provided content (HTML single pages, CPs, SCORM packages, documents etc.) from a second domain. The browser same-origin policy then prevents this content from accessing the OpenOlat session cookie. We strongly recommend this setup for production installations.

Add the following to olat.local.properties:

# Deliver user content from a second domain for more security
server.content.domainname=olat-content.yourdomain.com

The content domain must point to the same OpenOlat server, for example via an additional virtual host in your reverse proxy.

Warning

Use a completely separate domain that does not share cookies with your OpenOlat domain. A subdomain of server.domainname will not work.

If server.content.domainname is not set, user content is delivered from the main domain without this protection.

Application context descriptor

Create the directory ~/conf/Catalina/localhost/ for the OpenOlat Application context descriptor:

openolat~$ mkdir -p ~/conf/Catalina/localhost/

and create the file ~/conf/Catalina/localhost/ROOT.xml containing:

<?xml version="1.0" encoding="UTF-8" ?>
<Context path="" docBase="/home/openolat/webapp" debug="0" reloadable="false" allowLinking="true">
     <Resource name="jdbc/openolatDS" auth="Container" type="javax.sql.DataSource"
         maxTotal="16" maxIdle="4" maxWaitMillis="60000"
         username="oodbu" password="oodbpasswd"
         driverClassName="org.postgresql.Driver"
         validationQuery="SELECT 1" 
         validationQueryTimeout="-1" 
         testOnBorrow="true" 
         testOnReturn="false"
         url="jdbc:postgresql://localhost:5432/oodb"/>
</Context>

Make sure the values of username, password and the localhost:5432/oodb part in the url value are the ones of your postgresql account for openolat.

Configure log4j2

Create the file ~/lib/log4j2.xml containing

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
   <Appenders>
       <RollingFile name="RollingFile" fileName="/home/openolat/logs/olat.log"
           filePattern="/home/openolat/logs/olat.log.%d{yyyy-MM-dd}">
           <PatternLayout
                   pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %marker %c{1} ^%%^ I%X{ref}-J%sn ^%%^ %logger{36} ^%%^ %X{identityKey} ^%%^ %X{ip} ^%%^ %X{referer} ^%%^ %X{userAgent} ^%%^ %msg%ex{full,separator( )}%n" />
           <Policies>
               <TimeBasedTriggeringPolicy interval="1" />
           </Policies>
       </RollingFile>
   </Appenders>
   <Loggers>
       <Logger name="org.apache.commons.httpclient" additivity="false" level="warn">
           <AppenderRef ref="RollingFile" />
       </Logger>
       <Logger name="org.apache.pdfbox" additivity="false" level="fatal">
           <AppenderRef ref="RollingFile" />
       </Logger>
       <Logger name="org.apache.fontbox" additivity="false" level="fatal">
           <AppenderRef ref="RollingFile" />
       </Logger>
       <Logger name="org.hibernate.engine.internal.StatisticalLoggingSessionEventListener" additivity="false" level="fatal">
           <AppenderRef ref="RollingFile" />
       </Logger>
       <!-- Change the level to debug to see the SQL statements generated by Hibernate -->
       <Logger name="org.hibernate.SQL" additivity="false" level="fatal">
           <AppenderRef ref="RollingFile" />
       </Logger>
        <Logger name="org.hibernate.type.descriptor.sql.BasicBinder" additivity="false" level="fatal">
            <AppenderRef ref="RollingFile" />
        </Logger>
        <Logger name="org.apache.activemq.audit" additivity="false" level="warn">
           <AppenderRef ref="RollingFile" />
        </Logger>
        <Root level="info">
            <AppenderRef ref="RollingFile" />
        </Root>
   </Loggers>
</Configuration>

Done

Start OpenOlat

./start

The file ~/log/catalina.out should say

INFO: Server startup in [19696] milliseconds

near the end (your numbers will vary).

The next file to check would be ~/logs/olat.log. It should say:

Velocity cache filled with 1517 templates in (ms): 5847

but again, your numbers will vary.

Try OpenOlat

Point your browser to:

http://localhost:8088
username: administrator
password: openolat

Happy testing!

Help

If you have problems or questions please use the public mailing list or ask for commercial support

Professional hosting

OpenOlat is a complex application. Installing and operating requires in-depth Java and OpenOlat application knowledge.

frentix is the company behind OpenOlat, we are not only specialists in developing OpenOlat but also for hosting and operating OpenOlat in our own infrastructure or on-premises. Let us do what we can do best so you can concentrate on your actual learning scenarios.

Learn more about the OpenOlat services on the OpenOlat website