Self Host and Install Canvas LMS
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.
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 SetupStep 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;
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}"
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;
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 ServiceStep 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
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
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!
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.







