Self Host and Install Canvas LMS

Post Author:

Adeel

Categories:

Date Posted:

August 7, 2023

Share This:

Self Host and Install Canvas LMS On Your Server

Canvas is a powerful open-source LMS that can be self-hosted on your own server. This is a detailed guide to help you Install Canvas LMS on Ubuntu using the Apache web server and enabling SSL for secure communication.

Want to See Canvas LMS in Action First?

Before you dive into the installation steps below, explore a live, fully working demo of Canvas LMS — see the dashboard, courses, and interface exactly as you'll get it after installation.

Try Live Demo →

Caution: The steps below are fairly technical and should be performed by a server admin. The installation requires full access to the server this can be verified with the "sudo su" command. The requirements for the Canvas LMS when running all components on the same server are:

RAM (Memory): 8 GB RAM
Processor: 4 CPU cores with 2.0 GHz or more
Disk Space: 40-50GB for storage
OS: Ubuntu 22.04 LTS - This is a MUST

Prerequisite Step:

Create a new user on your Linux system as "canvas". This user will have permission to run the Canvas LMS setup. It is recommended that you have a separate Linux user manage your canvas installation. After executing the below command it will ask you to set the password for this new user, make sure you keep the password handy as it will be used to login and confirm certain actions during the installation

sudo adduser canvas su - canvas

We Handle Your Canvas Installation

Get Canvas Setup

Step 1: Create a PostgreSQL user and databases for Canvas

Once you execute this command, it will ask for your server password and then, your canvas PostgreSQL password. Please note the later one as it will be used when we will edit the canvas database config file.

sudo apt-get install wget ca-certificates -y && wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo tee /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc && echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list && sudo apt-get update; sudo apt-get install postgresql-16; sudo -u postgres createuser canvas --no-createdb --no-superuser --no-createrole --pwprompt; sudo -u postgres createdb canvas_production --owner=canvas; CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE EXTENSION IF NOT EXISTS postgis;

Step 2: Installing Git, Ruby, Node.js, and Yarn

sudo apt-get install git-core; sudo apt-get install software-properties-common; sudo add-apt-repository ppa:instructure/ruby; sudo apt-get update; sudo apt-get install ruby3.3 ruby3.3-dev zlib1g-dev libxml2-dev libsqlite3-dev postgresql libpq-dev libxmlsec1-dev libidn11-dev curl make g++; curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash; source ~/.bashrc; nvm install 18.20; curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.19.1; export PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH"

Step 3: Cloning and Install Canvas LMS

current_user=$(whoami); new_directory="/var"; cd "$new_directory"; sudo git clone https://github.com/instructure/canvas-lms.git canvas; sudo chown -R "$current_user":"$current_user" "$new_directory"/canvas; cd canvas; git checkout prod; for config in amazon_s3 database delayed_jobs vault_contents domain file_store outgoing_mail security external_migration; do cp config/$config.yml.example config/$config.yml; done

Step 4: Configuring Database, Outgoing Mail and Domain Settings

Set your Database credentials in this step, keep everything as it is, and just set the password to the value you entered in Step 1;

Note: When you open a file with  nano command then press ctrl + x then Y to save the changes to the file.

In the next steps, we will use this placeholder .  Make sure you replace this with your actual domain name used for Canvas before executing the commands.

 

cp config/database.yml.example config/database.yml; nano config/database.yml;

Open database.yml and keep only the production block with these settings:

production:
adapter: postgresql
encoding: utf8
database: canvas_production
username: canvas
password: {your_password_from_step_1}
host: localhost

Set the dynamic settings correctly for LTI external tool integrations to work properly.

cp config/dynamic_settings.yml.example config/dynamic_settings.yml; nano config/dynamic_settings.yml;

Make sure you replace development with production at the top in the dynamic_settings.yml file

production:
 config:
  canvas:
    canvas:
     encryption-secret: {random_32_char_string}
     signing-secret: {random_32_char_string}
 rich-content-service:
  app-host: https://your-domain.com

Set your SMTP mail server details for emails to work on your Canvas LMS. See this guide to learn how to get your SMTP details for Gmail.​

cp config/outgoing_mail.yml.example config/outgoing_mail.yml; nano config/outgoing_mail.yml;
These settings in the outgoing_mail.yml are tested to work. Note these 2 important parameters,
enable_starttls_auto: false
ssl: true
production:
address: smtp.gmail.com # Your SMTP server address
port: "465" # Port 465 for SSL
enable_starttls_auto: false # Disable TLS
ssl: true # Enable SSL
user_name: "{Your_SMTP_OR_GMAIL_USERNAME}"
password: "{Your_SMTP_OR_GMAIL_PASSWORD}"
authentication: plain # secure authentication
domain: smtp.gmail.com # Your SMTP server address
outgoing_address: "{YOUR_EMAIL}"
default_name: "{YOUR_FROM_NAME_ON_EMAILS}"
If using port 587 (TLS), use:
production:
address: smtp.gmail.com # Your SMTP server address
port: "587" # Port 587 for TLS
enable_starttls_auto: true
ssl: false
user_name: "{Your_SMTP_OR_GMAIL_USERNAME}"
password: "{Your_SMTP_OR_GMAIL_PASSWORD}"
authentication: plain # secure authentication

Set your domain name under Production -> domain. This should be the domain that is pointed to your server IP address. If you are not sure how to do this see this guide as an example.

cp config/domain.yml.example config/domain.yml; nano config/domain.yml;

Add these three settings under production:

production:
  domain: your-domain.com
  files_domain: your-domain.com
  ssl: true

Insert a randomized string of at least 20 characters in production -> encryption_key & set your own domain name in production -> lti_iss: ''. Make sure the domain name is properly set as this is required for LTI external tools to work properly on your Canvas.

cp config/security.yml.example config/security.yml; nano config/security.yml;

Your security.yml should look something like this,

production: &default
# replace this with a random string of at least 20 characters
encryption_key: '{random_string_of_at_least_20_characters}'
jwt_encryption_keys:
  - '{random_jwt_key}'
lti_iss: '{your_domain}'

Set file store configuration:

cp config/file_store.yml.example config/file_store.yml; nano config/file_store.yml;

Add:

production:
  storage: local
  path_prefix: tmp/files

Set session store configuration:

cp config/session_store.yml.example config/session_store.yml; nano config/session_store.yml;

Add:

production:
  session_store: cache_store

Set Redis connection configuration:

cp config/redis.yml.example config/redis.yml; nano config/redis.yml;

Add:

production:
  url: redis://localhost

Step 5: Installing Dependencies and Compiling Assets

sudo apt-get install libyaml-dev; sudo gem install bundler --version 2.5.10; bundle config set --local path vendor/bundle; bundle install; yarn install; yarn gulp rev; export [email protected]; export CANVAS_LMS_ADMIN_PASSWORD=your_secure_password; export CANVAS_LMS_ACCOUNT_NAME=Your_Account_Name; export CANVAS_LMS_STATS_COLLECTION=opt_out; RAILS_ENV=production bundle exec rake db:initial_setup; RAILS_ENV=production bundle exec rake db:migrate; mkdir -p log tmp/pids public/assets app/stylesheets/brandable_css_brands; touch app/stylesheets/_brandable_variables_defaults_autogenerated.scss Gemfile.lock log/production.log; NODE_OPTIONS='--max-old-space-size=4096' RAILS_ENV=production bundle exec rake canvas:compile_assets_dev || NODE_OPTIONS='--max-old-space-size=4096' RAILS_ENV=production bundle exec rake canvas:compile_assets; RAILS_ENV=production bundle exec rake brand_configs:generate_and_upload_all; echo "SELECT id, email FROM users WHERE admin=TRUE LIMIT 1;" | psql -U canvas -d canvas_production;

Step 6: Installing and Configuring Apache

sudo apt-get install apache2 apache2-dev libcurl4-openssl-dev libssl-dev zlib1g-dev g++ make; sudo gem install passenger; sudo passenger-install-apache2-module --auto --languages ruby; sudo passenger-install-apache2-module --snippet | grep LoadModule | sudo tee /etc/apache2/mods-available/passenger.load; sudo sh -c 'echo "PassengerRoot $(sudo passenger-config --root)" > /etc/apache2/mods-available/passenger.conf'; sudo sh -c 'echo "PassengerDefaultRuby /usr/bin/ruby3.4" >> /etc/apache2/mods-available/passenger.conf'; sudo sh -c 'echo "PassengerDefaultUser canvas" >> /etc/apache2/mods-available/passenger.conf'; sudo sh -c 'echo "PassengerStartTimeout 180" >> /etc/apache2/mods-available/passenger.conf'; sudo sh -c 'echo "PassengerPreloadBundler On" >> /etc/apache2/mods-available/passenger.conf'; sudo sh -c 'echo "PassengerFriendlyErrorPages Off" >> /etc/apache2/mods-available/passenger.conf'; sudo sh -c 'echo "PassengerInstanceRegistryDir /var/run/passenger-instreg" >> /etc/apache2/mods-available/passenger.conf'; sudo mkdir -p /var/run/passenger-instreg; sudo a2enmod rewrite; sudo a2enmod passenger; sudo a2enmod ssl; sudo a2enmod headers; sudo a2enmod proxy; sudo a2enmod proxy_http; sudo a2enmod xsendfile; sudo service apache2 restart;

Step 7: Obtain SSL Certificate For Your Domain

Canvas requires a valid & verified SSL certificate to be installed for your domain, please note that self signed cert will not work. We will use Lets Encrypt to get a free certificate and make it auto-renew so it does not expire after the 3-month period.

A) Install Certbot:

sudo apt update; sudo apt install certbot;

B) Install certbot plugin for Apache:

# Install Certbot for Apache
sudo apt install python3-certbot-apache
# Install Certbot for Nginx
#sudo apt install certbot python3-certbot-nginx

C) Obtain the SSL Certificate: Once you execute the below command and follow the steps a SSL cert and private key will be generated on your server. Note the following 2 paths to enter in the next Step 8: Cert: /etc/letsencrypt/live/fullchain.pem Key: /etc/letsencrypt/live/privkey.pem

# For Apache
sudo certbot --apache -d {your_domain}
# For Nginx
sudo certbot --nginx

D) Automatic Renewal: Let's Encrypt SSL certificates are typically valid for 90 days. Ubuntu's certbot package automatically installs a systemd timer for renewal, so no manual cron setup is required. To verify renewal is working, you can run:

sudo certbot renew --dry-run

Step 8: Configuring Virtual Hosts for Canvas

First, disable any Apache VirtualHosts you don't want running

sudo unlink /etc/apache2/sites-available/000-default.conf; sudo unlink /etc/apache2/sites-available/default-ssl.conf; sudo unlink /etc/apache2/sites-available/000-default-le-ssl.conf;

Now we will create a Virtual host for our Canvas LMS Installation.

sudo nano /etc/apache2/sites-available/canvas.conf

Add the following configuration to canvas.conf:

<VirtualHost *:80>
ServerName {your_domain}
DocumentRoot /var/canvas/public
PassengerRuby /usr/bin/ruby
PassengerAppEnv production
RailsEnv production
PassengerEnabled on
<Directory /var/canvas/public>
AllowOverride all
Options -MultiViews
Require all granted
</Directory>
</VirtualHost>
sudo nano /etc/apache2/sites-available/canvas-ssl.conf

Add the following configuration to canvas-ssl.conf: Set the paths for these 2 variables according to the value recived in Step 7: for cert and key

SSLCertificateFile and  SSLCertificateKeyFile

<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName {your_domain}
DocumentRoot /var/canvas/public
PassengerRuby /usr/bin/ruby
PassengerAppEnv production
RailsEnv production
PassengerEnabled on
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/{your_domain}/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/{your_domain}/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
<Directory /var/canvas/public>
AllowOverride all
Options -MultiViews
Require all granted
</Directory>
XSendFile On
XSendFilePath /var/canvas
</VirtualHost>
</IfModule>
sudo a2ensite canvas.conf; sudo a2ensite canvas-ssl.conf;

Step 9: Setup Automated jobs & Firewall Rules

sudo ln -s /var/canvas/script/canvas_init /etc/init.d/canvas_init; sudo update-rc.d canvas_init defaults; sudo /etc/init.d/canvas_init start; sudo ufw allow 80; sudo ufw allow 80/tcp; sudo ufw allow 443; sudo ufw allow 443/tcp; sudo ufw allow 5432; sudo ufw allow 5432/tcp; sudo ufw allow 3001; sudo ufw allow 3001/tcp; sudo ufw allow 3000; sudo ufw allow 3000/tcp; sudo ufw allow 6379; sudo ufw allow 6379/tcp; sudo ufw allow 8000; sudo ufw allow 8000/tcp; sudo ufw allow ssh; sudo ufw enable; sudo ufw reload;

Step 10: Setup Redis in Cache Configuration

Some of the features of Canvas require Redis, such as OAuth2 which is needed for LTI external tools, so it's required that you setup Redis for caching.

Required version: redis 2.6.x or above.

sudo add-apt-repository ppa:chris-lea/redis-server; sudo apt-get update; sudo apt-get install redis-server; sudo systemctl start redis-server; sudo systemctl enable redis-server; sudo cp config/cache_store.yml.example config/cache_store.yml; sudo nano config/cache_store.yml;

Make sure the cache_store.yml file contains:

test:
cache_store: redis_cache_store
development:
cache_store: redis_cache_store
production:
cache_store: redis_cache_store
sudo cp config/redis.yml.example config/redis.yml; sudo nano config/redis.yml;

Make sure the redis.yml file contains:

production:
url:
- redis://localhost
sudo systemctl restart redis-server;

Step 11: Enable Canvas Rich Content Editor

Canvas requires the Canvas RCE API library to be running and configured for full rich content editing functionality. Run the following command to clone the RCE API, install dependencies, and automatically generate all required secret keys:

git clone https://github.com/instructure/canvas-rce-api.git; cd canvas-rce-api; npm install --omit=dev; npm audit fix; cp .env.example .env; ECOSYSTEM_SECRET=$(head -c 32 /dev/urandom | base64 | tr -d '+/=' | tr -dc 'a-zA-Z0-9' | head -c 32); ECOSYSTEM_KEY=$(head -c 32 /dev/urandom | base64 | tr -d '+/=' | tr -dc 'a-zA-Z0-9' | head -c 32); CIPHER_PASSWORD=$(openssl rand -hex 16); echo "ECOSYSTEM_SECRET: $ECOSYSTEM_SECRET"; echo "ECOSYSTEM_KEY: $ECOSYSTEM_KEY"; sed -i "s/^\(NODE_ENV=\).*/\1production/; s/^\(ECOSYSTEM_SECRET=\).*/\1$ECOSYSTEM_SECRET/; s/^\(ECOSYSTEM_KEY=\).*/\1$ECOSYSTEM_KEY/; s/^\(CIPHER_PASSWORD=\).*/\1$CIPHER_PASSWORD/" .env; nano .env

Note down the ECOSYSTEM_KEY and ECOSYSTEM_SECRET values printed on screen, you will need them in the next step.

Now configure the vault_contents.yml file:

cd ..; cp config/vault_contents.yml.example config/vault_contents.yml; nano config/vault_contents.yml

Replace develpoment with production in vault_contents.yml.The contents should look like this,

production:
'app-canvas/data/secrets':
data:
canvas_security:
encryption_secret: "YOUR_ECOSYSTEM_KEY"
signing_secret: "YOUR_ECOSYSTEM_SECRET"

Replace YOUR_ECOSYSTEM_KEY and YOUR_ECOSYSTEM_SECRET with the values printed earlier. Open the dynamic_settings.yml config file as below.

nano config/dynamic_settings.yml;

Locate the rich-content-service key and set your domain as the app-host value. Make sure to include https://:

rich-content-service:
app-host: "https://{your_domain}"

IMPORTANT: Editing the YML files is a risky business, do not use tabs to indent while editing these files as this may result in parsing errors. Moreover, if the columns are not properly aligned for values then it will throw a parsing error as well. The error could be something like this. Error starting web application Web application Error column unalign error (): did not find expected key while parsing a block mapping at line 13 column 7 (Psych::SyntaxError) tab error (): found character that cannot start any token while scanning for the next token at line 14 column 5 (Psych::SyntaxError)

SOLUTION: To avoid this, make sure not to use tabs while editing and be sure that you follow the formatting exactly as shown in the code samples any extra space can make the YML file syntax invalid and the application will not start. If you encounter any such issue make sure you run your YML file through a formatter like this one that will point out any syntax issues in the file.

Now, we will set up Apache as a reverse proxy for the Canvas RCE API. so credentials are encrypted over HTTPS:

sudo nano /etc/apache2/sites-available/canvas-ssl.conf;
Add the below 2 lines before the end of </VirtualHost> block,
ProxyPass /api/session http://localhost:3001/api/session
ProxyPassReverse /api/session http://localhost:3001/api/session
</VirtualHost>
sudo a2enmod proxy_http; sudo service apache2 restart;

Finally, start the RCE API as a persistent service using PM2 so it keeps running permanently and auto-restarts on server reboot.

cd canvas-rce-api; npm install -g pm2; pm2 start npm --name 'canvas-rce-api' -- start; pm2 status

CRITICAL, Make PM2 survive server reboots. Both steps below must be completed or RCE will stop working after every reboot:

pm2 startup

This outputs a command, COPY and RUN that command immediately

pm2 save

Alternatively, if you prefer a native Linux service without extra dependencies, set up RCE as a systemctl service instead:

sudo nano /etc/systemd/system/canvas_rce.service

Paste the following, replacing the node path with your actual path from which node:

[Unit]\nDescription=Canvas RCE Node.js Server\nAfter=network.target\n\n[Service]\nExecStart=/home/canvas/.nvm/versions/node/v20.20.2/bin/node /home/canvas/canvas-rce-api/app.js\nWorkingDirectory=/home/canvas/canvas-rce-api\nRestart=always\nUser=canvas\nGroup=canvas\nEnvironment=NODE_ENV=production\n\n[Install]\nWantedBy=multi-user.target
sudo systemctl daemon-reload; sudo systemctl start canvas_rce.service; sudo systemctl enable canvas_rce.service; sudo systemctl restart canvas_rce.service; sudo systemctl status canvas_rce.service; sudo service apache2 restart

The RCE is now fully configured and will start automatically on every server reboot.

If you are facing any issues with the RCE editor even with these settings then please refer to this Github post by one of the users. Following the steps mentioned here for the RCE configuration should resolve any problems that you might face.

https://github.com/instructure/canvas-rce-api/issues/6#issuecomment-631818899

We know it’s complex—let us help!

Canvas Installation Service

Step 12: Set Correct Permissions & ensure users can't read private Canvas files

cd /var/canvas; current_user=$(whoami); sudo chown -R "$current_user":"$current_user" .; sudo find config/ -type f -exec chmod 400 {} +;

Step 13: Optimizing File Downloads (Optional)

you can optimize the downloading of files using the X-Sendfile header (X-Accel-Redirect in nginx). First make sure that apache has mod_xsendfile installed and enabled. For UBUNTU this can be done by following command:

sudo apt-get install libapache2-mod-xsendfile; sudo systemctl reload apache2; nano config/environments/production-local.rb;

Add the following lines to production-local.rb:

# If you have mod_xsendfile enabled in Apache:
config.action_dispatch.x_sendfile_header = 'X-Sendfile'
# For nginx:
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'

Conclusion: Canvas LMS Installed

By following this step-by-step guide, you can Install Canvas LMS on your own Ubuntu Server. Please be advised that these configurations need to be handled by a server administrator.

We know it's quite complex to perform the installation so we are here to help with that as well.

Canvas LMS Installation Price

We have a one-time setup fee for setting up Canvas LMS on your own server. There are some prerequisites to allow us to begin the installation process for you. Make sure you share with us the below items before you purchase the install package.

One Time Installation Service

Basic Canvas LMS Setup

$350*
Pre-Requisites for Installation
  • A fresh server running Ubuntu version -> 22.04
  • Port 3000 must be accessible on the server for the RCE setup
  • A minimum of 8 GB of RAM is recommended for Canvas LMS.
  • Root access to the server is needed.
  •  A domain URL pointing to your Linux server.
  •  SMTP server credentials (your email and app password) to enable emails from Canvas. Follow this guide till Step #3 to generate the app password after enabling 2-step verification for your Google account.
what you’ll get
  • Core Canvas LMS installation
  • Email Setup

  • System Firewall Setup

  • SSL Certificate/HTTPS Setup

  • Rich Content Editor Functionality

  • Redis Cache Configuration

  • This package includes everything you need to set up the basic open-source version of Canvas LMS software on your own server

Package does not include: If there are any other setup or installation tasks apart from the core Canvas LMS setup then it would be charged separately based on the hourly rates mentioned here.

Install Completion Time: Approx 2 working days

*Package is subject to our development service terms and conditions

Having trouble deciding how to proceed? reach out to us below and we’ll take you through!

Let’s discuss your project!

    Our Recommendation

    Affiliate Disclosure: We use affiliate links in our content. It wouldn’t cost you anything. However, it helps us offset the cost of producing the content and the offerings. Thanks for your support.

    About the Author: Adeel

    A decade in web development turned into a focus on progressive education models and eLearning tools. I express that through code: Adaptive Learning for LearnDash, Virtual Classroom for WordPress, and WPZoomy, to name a few.

    recent posts