Self Host and Install Canvas LMS in 2023

Post Author:



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.

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: 30GB for storage
OS: Ubuntu 20.04 LTS - This is a MUST

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 postgresql-12; sudo -u postgres createuser canvas --no-createdb --no-superuser --no-createrole --pwprompt; sudo -u postgres createdb canvas_production --owner=canvas; sudo -u postgres createdb canvas_development --owner=canvas; sudo -u postgres createuser $USER; sudo -u postgres psql -c "alter user $USER with superuser" postgres;

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.1 ruby3.1-dev zlib1g-dev libxml2-dev libsqlite3-dev postgresql libpq-dev libxmlsec1-dev libidn11-dev curl make g++; curl | bash; source ~/.bashrc; nvm install 18.1.0; curl -o- -L | bash -s -- --version 1.19.1;

Step 3: Cloning and Install Canvas LMS

current_user=$(whoami); new_directory="/var"; cd "$new_directory"; sudo git clone canvas; sudo chown -R "$current_user":"$current_user" "$new_directory"/canvas; cd canvas; git checkout prod; for config in amazon_s3 database delayed_jobs 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 {your_domain}.  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;

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

# tree

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
address: # 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: cram_md5 # secure authentication
domain: # Your SMTP server address
outgoing_address: "{YOUR_EMAIL}"
default_name: "{YOUR_FROM_NAME_ON_EMAILS}"

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;

Insert a randomized string of at least 20 characters in production -> encryption_key & set your own domain name in production -> lti_iss: '{your_domain}'. 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: daedd3a131ddd8988b14f6e4e01039c93cfa0160
lti_iss: '{your_domain}'

Step 5: Installing Dependencies and Compiling Assets

sudo apt-get install libyaml-dev; sudo gem install bundler --version 2.3.26; bundle config set --local path vendor/bundle; bundle install; sudo gem update strscan; sudo gem uninstall stringio; sudo gem install stringio -v 3.0.8; yarn install; mv db/migrate/20210823222355_change_immersive_reader_allowed_on_to_on.rb .; mv db/migrate/20210812210129_add_singleton_column.rb db/migrate/20111111214311_add_singleton_column.rb; yarn gulp rev; RAILS_ENV=production bundle exec rake db:initial_setup; mv 20210823222355_change_immersive_reader_allowed_on_to_on.rb db/migrate/.; 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; RAILS_ENV=production bundle exec rake canvas:compile_assets;

Step 6: Installing and Configuring Apache

sudo apt-get install apache2; sudo apt-get install -y dirmngr gnupg apt-transport-https ca-certificates; sudo apt-key adv --keyserver hkp:// --recv-keys 561F9B9CAC40B2F7; sudo sh -c 'echo deb focal main > /etc/apt/sources.list.d/passenger.list'; sudo apt-get update; sudo apt-get install -y libapache2-mod-passenger; sudo a2enmod rewrite; sudo a2enmod passenger; sudo a2enmod ssl; sudo nano /etc/apache2/mods-available/passenger.conf;

Now, you have to add your server user in the config file. If you are not sure what it is then run whoami command to find out and add the user in passenger.conf file

PassengerDefaultUser {your_user_here} PassengerStartTimeout 180 PassengerPreloadBundler On

If you want to enable error reporting until the installation is complete so you can view any errors during the process then you can also add the following line in the same file. Please make sure you comment out this line if everything goes well and you are in production mode.

PassengerFriendlyErrorPages On

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/{your_domain}/fullchain.pem Key: /etc/letsencrypt/live/{your_domain}/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. To automatically renew them, you can set up a cron job in the crontab as follows:

crontab -e

Add the below line once you've opened the crontab with the above command, save and exit.

0 0 * * * /usr/bin/certbot renew --quiet

Step 8: Configuring Virtual Hosts for Canvas

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

sudo unlink /etc/apache2/sites-enabled/000-default.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/ruby3.1
PassengerAppEnv production
RailsEnv production
<Directory /var/canvas/public>
AllowOverride all
Options -MultiViews
Require all granted
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/ruby3.1
PassengerAppEnv production
RailsEnv production
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
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 3001; sudo ufw allow 3001/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:

cache_store: redis_cache_store
cache_store: redis_cache_store
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:

- redis://localhost

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. To configure RCE API you will need to get a Flickr & YouTube API Key. Below are the steps to get your keys.

Getting a Flickr API Key:

  1. Create a Flickr Account: If you don't already have one, create a Flickr account at
  2. Flickr API Key:

Getting a YouTube API Key:

  1. Create a Google Account: If you don't have one, create a Google account at
  2. Google Cloud Console:
  3. Create a Project:
    • Click on the project drop-down menu at the top of the page.
    • Click "New Project."
    • Enter a project name and select an organization (if applicable).
  4. Enable the YouTube Data API:
    • In the left navigation pane, click on "APIs & Services" > "Library."
    • Search for "YouTube Data API" and select it.
    • Click the "Enable" button.
  5. Create Credentials:
    • In the left navigation pane, click on "APIs & Services" > "Credentials."
    • Click the "Create Credentials" button and select "API Key."
  6. Get Your API Key:
    • A pop-up will appear with your API key.
    • You can restrict the API key to prevent unauthorized use if needed. Install Canvas LMS youtube-api-key
git clone; cd canvas-rce-api; npm install --production; npm audit fix; cp .env.example .env; ECOSYSTEM_SECRET=$(unique_string=$(head -c 32 /dev/urandom | base64 | tr -d '+/=' | tr -dc 'a-zA-Z0-9' | head -c 32); echo $unique_string); echo $ECOSYSTEM_SECRET; ECOSYSTEM_KEY=$(unique_string=$(head -c 32 /dev/urandom | base64 | tr -d '+/=' | tr -dc 'a-zA-Z0-9' | head -c 32); echo $unique_string); echo $ECOSYSTEM_KEY; CIPHER_PASSWORD=$(openssl rand -hex 16); 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

Add the Flicker and YouTube API keys created previously in the .env file. Copy ECOSYSTEM_KEY & ECOSYSTEM_SECRET from the same file. These 2 values will be used next.

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

Add the values of ECOSYSTEM_KEY & ECOSYSTEM_SECRET copied from the .env file. Replace develpoment with production in vault_contents.yml.The contents should look like this,

access_key: 'fake-access-key'
secret_key: 'fake-secret-key'
security_token: 'fake-security-token'
access_key: 'fake-access-key'
secret_key: 'fake-secret-key'
security_token: 'fake-security-token'
encryption_secret: "YOUR_ECOSYSTEM_KEY"
signing_secret: "YOUR_ECOSYSTEM_SECRET"

Open the dynamic_settings.yml config file as below.

nano config/dynamic_settings.yml;

Locate this key rich-content-service -> app-host add your domain name in the first value of app-host and comment out the second value as show,

# if you're running canvas-rce-api on its own
app-host: "{your_domain}"
# if you're running canvas-rce-api with docker-compose/rce-api.override.yml in .env
# app-host: "http://rce.canvas.docker:3000"

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 Node App. To ensure that credentials and payloads are encrypted over the wire https as the node app does not directly supports a secure HTTPS connection.

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
sudo a2enmod proxy_http; sudo service apache2 restart;

Finally, start the node app as a screen so that even if you close the terminal window the app is running in the background.

cd canvas-rce-api; sudo apt install screen; screen -S canvas-rce-api;
npm run start;

Now, press Ctrl + a and to detach from the screen.

The RCE should be up and running after this final step.

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; 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.

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

Having a decade-long experience with web development, there came a major turning point in my life that shifted all my attention towards progressive education models. I took a special interest in creating eLearning tools. Now, I express my ideas through the “language of code”: LearnDash Student Voice, Adaptive Learning with LearnDash, Virtual Classroom for WordPress and Zoom WordPress Plugin are some of my plugins. I help educators, coaches, teachers, and field experts combine technology with education to make it scalable, flexible, accessible to the masses & at par with 21st-century learning methodology.

recent posts