Introduction
Running a Learning Management System (LMS) can be very difficult for server administrators, since LMSs are usually made up of multiple components and require significant resources, as they are made to serve many people simultaneously in vastly different configurations. This tutorial will focus on how to host an LMS instance which can handle a few hundred or thousand users at most (highly dependent on the workload). As a result, this deployment is most appropriate for small educational environments with limited processing resources which nevertheless need an LMS.
Open edX is a good LMS solution because it is free, open source and is supported by many educational institutions. Docker is an excellent choice for deploying Open edX through the Tutor set of scripts. Tutor drastically simplifies the deployment of Open edX through the use of a unified interface for accessing configuration variables and the ability to one-click-install. Without it, administrators would have to handle over 780 configuration files. Docker further allows portability, upgradeability and decoupling of the many parts it takes to build an LMS.
This tutorial was tested on Ubuntu 22.04 running on an Arm64 instance. It will use apt
as the package manager, so make sure to replace it with your distro's package manager if you are using something else.
Prerequisites
-
A VPS that meets the hardware requirements:
- Minimum configuration: 4 GB RAM, 2 CPU, 8 GB disk space
- Recommended configuration: 8 GB RAM, 4 CPU, 25 GB disk space
-
Any 64-bit Linux OS (x86-64 or Arm64)
-
A domain and the ability to edit DNS records (through your domain name provider)
Example terminology
- Username:
holu
- Domain:
example.com
- Subdomain:
tutor.example.com
Step 1 - Installing Docker and Docker Compose
First, do a full system update and upgrade:
sudo apt update
sudo apt upgrade -y
If you do not have Docker yet, you can set it up now:
sudo apt install docker.io # Install Docker
sudo usermod -aG docker holu # Add your user to the docker group; replace "holu" with your own username
Log out and back in to update your groups. Then run the command groups
to see if your user is now in the "docker" group.
As of v16.0.0, the local deployment of Tutor requires Docker Compose v2, so you do not need to install docker-compose
(hyphenated). However, you will need to have the new docker compose
(non-hyphenated) command which is installed separately. The following commands will install the new Docker Compose as a Docker plugin:
mkdir -p ~/.docker/cli-plugins/
You can use uname -srm
to check your architecture before you choose one of the releases below.
-
VPS with x86 architecture
curl -SL https://github.com/docker/compose/releases/download/v2.21.0/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
-
VPS with Arm64 architecture
curl -SL https://github.com/docker/compose/releases/download/v2.21.0/docker-compose-linux-aarch64 -o ~/.docker/cli-plugins/docker-compose
Make sure to replace v2.21.0 with the most recent version of Docker Compose, which you can find on the official releases page.
To be able to use the downloaded binary through Docker, you need to make it executable with this command:
chmod +x ~/.docker/cli-plugins/docker-compose
To test if docker compose
works, simply run:
docker compose version
This command should return the version of docker compose
that you installed, which in my case is:
Docker Compose version v2.21.0
Now we can move on to the installation.
Step 2 - Installing the required packages
If you do not have the required packages, install them with the following command (on Ubuntu):
sudo apt install python3 python3-pip libyaml-dev
For other Linux distros, replace apt install
with the appropriate package manager for the distro.
Once you have the required packages, you can install the latest version of Tutor with the following command:
pip install "tutor[full]"
Using the syntax
"tutor[full]==16.1.1"
, you can install a specific version of Tutor. You can replace 16.1.1 with any version you want. You can find Tutor releases on the official GitHub page.
To check if the installation worked, run tutor --version
. You might need to log out and back in again.
Step 3 - Configuring the ports
Tutor uses Caddy as a web proxy. This makes adding SSL easy, but the default ports are 80 (for HTTP) and 443 (for HTTPS). These ports are often in use by other websites running on the same server, so Tutor has a command to change the default port. In my case, ports 80 to 83 were taken, so I had to use port 84. If you use different ports than the defaults, you only need to open up one port for both HTTP and HTTPS. All of this can be done with the following command:
To check which ports are in use, run:
sudo lsof -i -P -n | grep LISTEN
tutor config save --set ENABLE_WEB_PROXY=false --set CADDY_HTTP_PORT=84
Make sure to replace CADDY_HTTP_PORT=84
with the port you want to use.
Step 3.1 - Configuring firewalls
Since many firewalls exist, this tutorial will only cover two popular options — Hetzner Cloud Firewall and Ubuntu's default firewall ufw
(which is automatically installed).
Hetzner Cloud Firewall
In the Hetzner Cloud Console, select your server and in the navigation bar select "Firewalls". Select the active Firewall, click the three dots on the right and click "Edit Firewall". Then, in the top right of the site click on the "Add rule" button and select "Inbound". A box will appear where you need to add a description of the new Firewall rule, the type of IP you want to be able to access the site and the port. Leave the protocol on the default TCP. If you want to limit who can access the LMS, such as limiting it only to a certain IP range (only IPs on a particular campus, for example), you can do that here. The final box should look like the table below:
IPs | Protocol | Port | Port range |
---|---|---|---|
Any IPv4 Any IPv6 | TCP | <YOUR-PORT-NUMBER> |
ufw
-
Check if ufw is active
To check ifufw
is active, run:sudo ufw status
The exact output will be different depending on whether you have any rules added.
-
Active
The command should return the following output:Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6)
-
Inactive
The command should return the following output:Status: inactive
To activate ufw, simply run
sudo ufw enable
after you have finished the steps below. Make sure you allow OpenSSH before you enable ufw:sudo ufw allow OpenSSH
.
-
-
Allow incoming traffic to port
To allow incoming traffic to your port, you need to add it as a ufw rule with the following command:sudo ufw allow proto tcp to any port <YOUR-PORT-NUMBER>
-
Check if the rule was added
If the firewall was inactive, you can activate it now. Check if the rule was added with the following command:sudo ufw status
Example output:
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere <YOUR-PORT-NUMBER>/tcp ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) <YOUR-PORT-NUMBER>/tcp (v6) ALLOW Anywhere (v6)
If you are using another firewall, the steps to opening up the port will likely be similar.
Step 4 - The one-click-install
Now that you have downloaded Tutor and optionally set up the ports, simply run:
tutor local launch
First the command will ask you to answer a few questions about a contact email and the subdomains used for users and administrators/course creators. The final question will ask about SSL ("Activate SSL/TLS certificates for HTTPS access?"), which I highly recommend you answer yes ("y") to. After this, the installation will begin. This should take 5-15 minutes, depending on your VPS's CPU power and download speed. This one command will create the aforementioned 780+ configuration files, download and install all the necessary Docker containers.
If you get an error such as
Command failed with status 1: docker compose ...
, you might not have enough RAM.
Step 5 - DNS setup
For this step you need to have a domain name. This tutorial will use the example domain example.com
. If you want your domain to be publicly accessible, you need to add DNS records which state that all subdomains of your main Open edX instance are associated with your domain name. Browsers treat each subdomain as a completely separate website, so you need to add records which both point the subdomain to your server, and show that all subdomains are associated with Open edX. This process is different for all domain name providers. I use Namecheap, and it is a common provider, so I will illustrate the process for adding records.
-
Run this command to get the main subdomain for Open edX:
tutor config printvalue LMS_HOST
-
Run this command to get the IP address of your server:
curl -4 https://ip.hetzner.com
In my example, my subdomain is tutor.example.com
. This is the value that you set at the beginning of Step 4. Additionally, you need the IP address associated with the server you are hosting Open edX on. You will need to add an A record associated with the main subdomain you found from the command above. You will also need to add a CNAME record associated with all subdomains of the main subdomain. In the Namecheap UI, this will look like the following:
Type | Host | Value | TTL |
---|---|---|---|
A record | tutor | <YOUR-IP-ADDRESS> |
Automatic |
CNAME record | *.tutor | tutor.example.com | Automatic |
After setup, these records may take up to 30 minutes to start working, so be patient if your domain does not work immediately.
Conclusion
This is likely the shortest possible LMS setup which results in a production-ready and high-quality service. Open edX, as a platform, is a great LMS and combining it with Docker gives it another level of flexibility. Compared to Moodle, the other dominant free and open-source LMS, Open edX also works on Arm64 servers, which are becoming increasingly appealing due to their generally lower price and higher core count. Even Hetzner's lowest cost Arm server offer can run the minimum configuration of Open edX, while Docker allows very quick transitions to more resource-rich cloud or on-premise servers if needed.