...
How to install canvas lms on ubuntu vps
Learn how to install canvas lms on ubuntu vps!

This article provides a guide demonstrating how to install Canvas LMS on Ubuntu VPS.

Table of Contents

What is Canvas LMS?

Canvas LMS is a powerful open-source Learning Management System developed by Instructure. It provides course management, assignments, grading, discussions, quizzes, user enrollment, integrations, APIs, and many of the features commonly required by schools, universities, training organizations, and corporate learning environments.

Although Instructure offers Canvas as a hosted commercial service, the open-source edition can be installed on your own Ubuntu VPS.

This guide walks through deploying a production-ready Canvas LMS server on Ubuntu 22.04 LTS, including:

  • PostgreSQL
  • Ruby 3.4
  • Node.js 20
  • Yarn
  • Redis
  • Canvas LMS
  • Apache
  • Phusion Passenger
  • Background workers
  • HTTPS using Let’s Encrypt
  • SMTP configuration
  • Basic production hardening

Canvas is considerably more resource-intensive than a typical WordPress or small Rails application. Instructure recommends at least 8 GB of RAM when the web application, database, Redis, and background workers are running on the same machine.

For a small production installation, a sensible starting VPS configuration is:

Resource Recommended
CPU 4 vCPU or more
RAM 16 GB minimum
Storage 256 GB SSD/NVMe
OS Ubuntu 22.04 LTS
Database PostgreSQL 14+
Redis Redis 6+
Ruby Ruby 3.4.1+
Node.js Node.js 20+

For larger deployments, PostgreSQL, Redis, Canvas web nodes, background workers, and object storage should eventually be separated.
Launch 100% ssd ubuntu vps from $3. 19/mo!


Compare Ubuntu VPS Plans

KVM-SSD-1
KVM-SSD-8
KVM-SSD-16
KVM-SSD-32
CPU
1 Core
2 Cores
4 Cores
8 Cores
Memory
1 GB
8 GB
16 GB
32 GB
Storage
16 GB NVMe
128 GB NVMe
256 GB NVMe
512 GB NVMe
Bandwidth
1 TB
4 TB
8 TB
16 TB
Network
1 Gbps
1 Gbps
1 Gbps
1 Gbps
Delivery Time
⏱️ Instant
⏱️ Instant
⏱️ Instant
⏱️ Instant
Location
US/EU/APAC
US/EU/APAC
US/EU/APAC
US/EU/APAC
Price
$7.58*
$39.50*
$79.40*
$151.22*
KVM-SSD-1
$7.58*
CPU 1 Core
Memory 1 GB
Storage 16 GB NVMe
Bandwidth 1 TB
Network 1 Gbps
Delivery Time ⏱️ Instant
Location US/EU/APAC
KVM-SSD-8
$39.50*
CPU 2 Cores
Memory 8 GB
Storage 128 GB NVMe
Bandwidth 4 TB
Network 1 Gbps
Delivery Time ⏱️ Instant
Location US/EU/APAC
KVM-SSD-16
$79.40*
CPU 4 Cores
Memory 16 GB
Storage 256 GB NVMe
Bandwidth 8 TB
Network 1 Gbps
Delivery Time ⏱️ Instant
Location US/EU/APAC
KVM-SSD-32
$151.22*
CPU 8 Cores
Memory 32 GB
Storage 512 GB NVMe
Bandwidth 16 TB
Network 1 Gbps
Delivery Time ⏱️ Instant
Location US/EU/APAC

How to Install Canvas LMS on Ubuntu VPS

To install Canvas LMS on Ubuntu VPS, follow the steps below:

  1. Prepare the DNS Records

    Before installing Canvas, create DNS records pointing to your VPS.

    For example:

    canvas.example.com       A       192.0.2.10
    canvasfiles.example.com  A       192.0.2.10
    

    Replace 192.0.2.10 with the public IP address of your VPS.

    The second hostname is important because Canvas recommends serving user-uploaded content from a hostname separate from the main Canvas application. Instructure specifically notes that files_domain should be a different hostname from the browser’s perspective, even if both hostnames ultimately point to the same web server.

    Throughout this guide, replace:

    canvas.example.com
    

    with your actual Canvas hostname.

  2. Connect to the Ubuntu VPS

    Connect over SSH:

    ssh root@SERVER_IP
    

    Update the server:

    apt update
    apt upgrade -y
    

    Install some basic utilities:

    apt install -y \
        curl \
        wget \
        git \
        nano \
        unzip \
        ca-certificates \
        gnupg \
        software-properties-common \
        build-essential
    

    Set the hostname if necessary:

    hostnamectl set-hostname canvas.example.com
    

    Confirm:

    hostnamectl
    
  3. Create an Administrative User

    Although you can initially configure the server as root, it is better to create a normal sudo-enabled administrator.

    See Also: ✅ Easily Setup Multilingual WooCommerce Store with Rad Web Hosting and WPML (Boost Your Sales!)

    For example:

    adduser canvasadmin
    

    Add the account to the sudo group:

    usermod -aG sudo canvasadmin
    

    Switch to it:

    su - canvasadmin
    

    For the remainder of the guide, commands requiring elevated privileges use sudo.

  4. Configure the Firewall

    If UFW is enabled, allow SSH, HTTP, and HTTPS:

    sudo ufw allow OpenSSH
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    

    Enable UFW:

    sudo ufw enable
    

    Check the rules:

    sudo ufw status
    

    You should see ports 22, 80, and 443 allowed.

    Do not expose PostgreSQL or Redis publicly when they are installed locally.

  5. Install PostgreSQL

    Canvas uses PostgreSQL for its production database and currently requires PostgreSQL 14 or newer.

    Ubuntu 22.04 provides PostgreSQL 14:

    sudo apt install -y postgresql postgresql-contrib libpq-dev
    

    Start and enable PostgreSQL:

    sudo systemctl enable --now postgresql
    

    Verify:

    sudo systemctl status postgresql
    

    Check its version:

    psql --version
    

    You should have PostgreSQL 14 or newer.

  6. Create the Canvas PostgreSQL User and Database

    Create a dedicated PostgreSQL account:

    sudo -u postgres createuser canvas \
        --no-createdb \
        --no-superuser \
        --no-createrole \
        --pwprompt
    

    You will be prompted to create a database password.

    Use a long random password and save it securely.

    For example:

    YOUR_STRONG_DATABASE_PASSWORD
    

    Create the Canvas production database:

    sudo -u postgres createdb canvas_production --owner=canvas
    

    Verify:

    sudo -u postgres psql -c "\l"
    

    You should see:

    canvas_production
    

    owned by:

    canvas
    

    Test the database login:

    psql -h localhost -U canvas -d canvas_production
    

    Enter the database password.

    If successful, quit PostgreSQL with:

    \q
    
  7. Install Redis

    Redis is strongly recommended by Canvas and is required by some Canvas functionality, including OAuth-related functionality. The current production documentation specifies Redis 6.x or later.

    Install Redis:

    sudo apt install -y redis-server
    

    Enable it:

    sudo systemctl enable --now redis-server
    

    Test Redis:

    redis-cli ping
    

    Expected response:

    PONG
    

    Check the version:

    redis-server --version
    

    For a single-server installation, Redis should remain bound to localhost.

    Check:

    sudo ss -lntp | grep 6379
    

    You generally want Redis listening only on:

    127.0.0.1:6379
    

    or another private/internal address.

  8. Install Canvas Ruby Dependencies

    Current Canvas releases require at least Ruby 3.4.1. Ruby 3.5+ is currently described by the Canvas production documentation as untested.

    Instructure maintains an Ubuntu Ruby PPA.

    Add it:

    sudo add-apt-repository -y ppa:instructure/ruby
    sudo apt update
    

    Install Ruby and the required development libraries:

    sudo apt install -y \
        ruby3.4 \
        ruby3.4-dev \
        zlib1g-dev \
        libxml2-dev \
        libsqlite3-dev \
        libpq-dev \
        libxmlsec1-dev \
        libyaml-dev \
        libidn11-dev \
        curl \
        make \
        g++
    

    These dependencies closely follow Instructure’s current production installation recommendations.

    See Also: How to Setup BIND DNS Server on Ubuntu VPS

    Check Ruby:

    ruby --version
    

    You want something similar to:

    ruby 3.4.x
    

    If Ubuntu still points ruby at another version, inspect:

    which ruby
    ruby --version
    
  9. Install Node.js 20

    Canvas currently requires Node.js 20 or newer, and the current source tree specifies Node.js >=20.0.0. The repository’s .nvmrc currently points to Node 20.9.0.

    Install Node.js 20 from NodeSource:

    curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
    

    Install Node:

    sudo apt install -y nodejs
    

    Check it:

    node --version
    npm --version
    

    You should see Node 20.x or newer.

  10. Install Yarn

    Canvas continues to use Yarn 1.x for its JavaScript dependency tree. The current package configuration specifies Yarn ^1.19.1.

    Install Yarn:

    sudo npm install -g yarn
    

    Check:

    yarn --version
    

    A Yarn 1.x release should be returned.

    Do not use Yarn Berry/Yarn 2+ unless the Canvas source branch explicitly changes its package requirements.

  11. Create the Canvas Runtime User

    Create a dedicated system account that will run Canvas:

    sudo adduser \
        --disabled-password \
        --gecos "" \
        canvasuser
    

    Canvas will ultimately run under this account instead of root.

  12. Download Canvas LMS

    Move to a temporary working directory:

    cd ~
    

    Clone the official repository:

    git clone https://github.com/instructure/canvas-lms.git
    

    Enter it:

    cd canvas-lms
    

    For a production installation, use Instructure’s production branch:

    git checkout prod
    

    The official Production Start documentation currently recommends the prod branch for production deployments.

    Confirm:

    git branch --show-current
    

    Expected:

    prod
    
  13. Move Canvas to /var/canvas

    Create the production application directory:

    sudo mkdir -p /var/canvas
    

    Give your administrative user temporary ownership:

    sudo chown -R "$USER":"$USER" /var/canvas
    

    Copy the Canvas application:

    cp -a ~/canvas-lms/. /var/canvas/
    

    Enter the application directory:

    cd /var/canvas
    

    Confirm:

    ls
    

    You should see directories such as:

    app
    config
    db
    doc
    gems
    lib
    public
    script
    ui
    

    along with:

    Gemfile
    Rakefile
    package.json
    
  14. Install Bundler

    Canvas uses Bundler to manage its Ruby dependencies.

    The current Canvas lock file identifies Bundler 2.6.7, so installing that version avoids unnecessary dependency-resolution differences.

    Install Bundler:

    sudo gem install bundler -v 2.6.7
    

    Verify:

    bundle --version
    

    Configure dependencies to install underneath the Canvas tree:

    bundle config set --local path vendor/bundle
    

    Then install the gems:

    bundle install
    

    This can take several minutes and consume substantial CPU and RAM.

    See Also: How to Configure Additional Firewall Rules on Rocky Linux VPS (5 Minute Guide)

    If compilation fails, review the error carefully. Most gem failures indicate a missing development library rather than a Canvas problem.

  15. Install Canvas JavaScript Dependencies

    From /var/canvas:

    yarn install
    

    This downloads a substantial dependency tree.

    Verify it completes without errors.

    If Yarn complains about Node compatibility, check:

    node --version
    

    and:

    cat package.json | grep -A3 '"engines"'
    

    Do not bypass engine checks unless you have a very specific reason to do so.

  16. Create Canvas Configuration Files

    Canvas ships example configuration files that must be copied before initialization.

    Run:

    cd /var/canvas
    

    Then:

    for config in amazon_s3 database vault_contents delayed_jobs domain file_store outgoing_mail security external_migration; do
        cp config/${config}.yml.example config/${config}.yml
    done
    

    Also create the dynamic settings file:

    cp config/dynamic_settings.yml.example config/dynamic_settings.yml
    
  17. Configure the Database

    Edit:

    nano config/database.yml
    

    Find the production section and configure it similar to:

    production:
      adapter: postgresql
      encoding: utf8
      database: canvas_production
      host: localhost
      username: canvas
      password: "YOUR_STRONG_DATABASE_PASSWORD"
      timeout: 5000
    

    Save the file.

    Test the credentials independently if needed:

    PGPASSWORD='YOUR_STRONG_DATABASE_PASSWORD' \
    psql -h localhost -U canvas -d canvas_production -c "SELECT version();"
    

    If PostgreSQL responds, Canvas should be able to connect as well.

  18. Configure the Canvas Domain

    Edit:

    nano config/domain.yml
    

    Configure the production section:

    production:
      domain: "canvas.example.com"
      ssl: true
      files_domain: "canvasfiles.example.com"
    

    The important values are:

    domain
    files_domain
    ssl
    

    Use only hostnames here; do not add:

    https://
    

    before the domain unless the particular setting explicitly calls for a URL.

  19. Configure Canvas Security Secrets

    Copying the example already created:

    config/security.yml
    

    Edit it:

    nano config/security.yml
    

    Canvas requires randomized secret values. The official documentation requires random strings of at least 20 characters.

    Generate strong secrets with:

    openssl rand -hex 64
    

    Run the command separately for each required secret.

    For example:

    openssl rand -hex 64
    openssl rand -hex 64
    openssl rand -hex 64
    

    Place the generated strings into the corresponding production values in security.yml.

    Never reuse the example secrets in production.

    Never publish this file.

  20. Configure Redis

    Create the Redis configuration:

    cp config/redis.yml.example config/redis.yml
    

    Edit it:

    nano config/redis.yml
    

    Configure:

    production:
      url:
        - redis://127.0.0.1:6379/0
    

    Now configure Canvas caching:

    cp config/cache_store.yml.example config/cache_store.yml
    

    Edit:

    nano config/cache_store.yml
    

    Use:

    See Also: Self-Hosting a Bluesky Personal Data Server on Ubuntu VPS

    production:
      cache_store: redis_cache_store
    

    This matches the Redis cache configuration recommended in the current Canvas Production Start documentation.

  21. Configure Outgoing Email

    Canvas relies heavily on email for notifications, invitations, password resets, announcements, and course activity.

    Edit:

    nano config/outgoing_mail.yml
    

    A typical authenticated SMTP configuration resembles:

    production:
      address: "smtp.example.com"
      port: "587"
      user_name: "canvas@example.com"
      password: "YOUR_SMTP_PASSWORD"
      authentication: "plain"
      enable_starttls_auto: true
      domain: "example.com"
      outgoing_address: "canvas@example.com"
      default_name: "Canvas LMS"
    

    Replace these settings with your SMTP provider’s actual information.

    The domain and outgoing_address fields describe Canvas’s outbound identity, while the SMTP address, credentials, and port describe the mail server connection.

    For production email deliverability, also configure:

    • SPF
    • DKIM
    • DMARC
    • valid PTR/rDNS where applicable
  22. Prepare Canvas Runtime Directories

    Create required directories:

    cd /var/canvas
    

    Run:

    mkdir -p \
        log \
        tmp/pids \
        public/assets \
        app/stylesheets/brandable_css_brands
    

    Create required files:

    touch app/stylesheets/_brandable_variables_defaults_autogenerated.scss
    touch log/production.log
    
  23. Initialize the Canvas Database

    Before running initialization, generate the asset revision:

    yarn gulp rev
    

    Now run the initial Canvas database setup:

    RAILS_ENV=production bundle exec rake db:initial_setup
    

    Canvas will prompt for information including:

    Admin email
    Admin password
    Organization/account name
    Usage statistics preference
    

    For example:

    Admin email:
    admin@example.com
    
    Account name:
    Example University
    

    Use a strong administrator password.

    Canvas also supports environment variables for automating these answers:

    CANVAS_LMS_ADMIN_EMAIL
    CANVAS_LMS_ADMIN_PASSWORD
    CANVAS_LMS_ACCOUNT_NAME
    CANVAS_LMS_STATS_COLLECTION
    

    The official installer supports opt_in, opt_out, or anonymized for statistics collection.

    After initialization, your Canvas database should contain the required schema and initial administrator account.

  24. Compile Canvas Production Assets

    Canvas must build its CSS, JavaScript, branding, and other static assets before the interface will work correctly.

    Run:

    cd /var/canvas
    

    Then:

    RAILS_ENV=production \
    SASS_STYLE=compressed \
    bundle exec rake canvas:compile_assets
    

    Asset compilation is one of the most resource-intensive stages of the installation.

    On a smaller VPS, compilation may fail because of memory exhaustion.

    If necessary, temporarily create swap:

    sudo fallocate -l 8G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    

    Verify:

    free -h
    

    You can also reduce Canvas build concurrency:

    export CANVAS_BUILD_CONCURRENCY=1
    

    Then rerun the asset compilation.

    Recent Canvas deployment experience confirms that missing or failed asset compilation can leave the Rails application technically accessible while the UI is incomplete, broken, or unstyled.

  25. Set Canvas File Ownership

    Set the Canvas runtime user as the owner of files it must modify:

    See Also: 🚀 Install and Run Self-hosted Mattermost Instance on Linux VPS

    sudo chown -R canvasuser:canvasuser \
        /var/canvas/log \
        /var/canvas/tmp \
        /var/canvas/public/assets \
        /var/canvas/public/dist \
        /var/canvas/app/stylesheets/brandable_css_brands
    

    Also:

    sudo chown canvasuser:canvasuser \
        /var/canvas/config/environment.rb \
        /var/canvas/config.ru \
        /var/canvas/app/stylesheets/_brandable_variables_defaults_autogenerated.scss
    

    Protect sensitive configuration files:

    sudo chown canvasuser:canvasuser /var/canvas/config/*.yml
    sudo chmod 400 /var/canvas/config/*.yml
    

    Canvas’s production documentation specifically recommends restricting these YAML files because they can contain database passwords, SMTP credentials, encryption keys, and other secrets.

  26. Install Apache

    Canvas’s official production deployment guide uses Apache + Phusion Passenger.

    Install Apache:

    sudo apt install -y apache2
    

    Enable common required modules:

    sudo a2enmod rewrite
    sudo a2enmod ssl
    sudo a2enmod headers
    
  27. Install Phusion Passenger

    Install the repository prerequisites:

    sudo apt install -y \
        dirmngr \
        gnupg \
        apt-transport-https \
        ca-certificates \
        curl
    

    Install Phusion’s current signing key:

    curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key-2025.txt \
        | gpg --dearmor \
        | sudo tee /etc/apt/trusted.gpg.d/phusion.gpg >/dev/null
    

    Add the Ubuntu 22.04/Jammy Passenger repository:

    echo "deb https://oss-binaries.phusionpassenger.com/apt/passenger jammy main" \
        | sudo tee /etc/apt/sources.list.d/passenger.list
    

    Update:

    sudo apt update
    

    Install Passenger’s Apache module:

    sudo apt install -y libapache2-mod-passenger
    

    Enable Passenger:

    sudo a2enmod passenger
    

    Restart Apache:

    sudo systemctl restart apache2
    

    These commands use Phusion’s current repository/key installation method rather than the older deprecated apt-key workflow.

    Validate Passenger:

    sudo passenger-config validate-install
    

    All checks should pass.

  28. Tell Passenger Which Ruby to Use

    Determine Ruby’s location:

    which ruby
    

    For example:

    /usr/bin/ruby
    

    Inspect Passenger configuration:

    sudo nano /etc/apache2/mods-available/passenger.conf
    

    Ensure Passenger is using the correct Ruby.

    For example:

    PassengerRuby /usr/bin/ruby
    PassengerDefaultUser canvasuser
    

    Verify Ruby:

    /usr/bin/ruby --version
    

    Make sure it reports Ruby 3.4.x.

    Restart Apache:

    sudo systemctl restart apache2
    
  29. Create the Canvas Apache VirtualHost

    Disable the default Apache site:

    sudo a2dissite 000-default.conf
    

    Create:

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

    Initially configure HTTP:

        ServerName canvas.example.com
        ServerAlias canvasfiles.example.com
    
        ServerAdmin admin@example.com
    
        DocumentRoot /var/canvas/public
    
        SetEnv RAILS_ENV production
    
        PassengerAppEnv production
        PassengerDefaultUser canvasuser
    
        
            Options FollowSymLinks
            AllowOverride All
            Require all granted
        
    
        ErrorLog ${APACHE_LOG_DIR}/canvas_error.log
        CustomLog ${APACHE_LOG_DIR}/canvas_access.log combined
    
    
    

    Enable it:

    See Also: How to Install and Run Rootkit Hunter on AlmaLinux VPS

    sudo a2ensite canvas.conf
    

    Check the configuration:

    sudo apachectl configtest
    

    Expected:

    Syntax OK
    

    Restart Apache:

    sudo systemctl restart apache2
    
  30. Test Canvas Before Adding SSL

    Check Apache:

    sudo systemctl status apache2
    

    Check Canvas:

    curl -I http://canvas.example.com/
    

    Also check:

    curl -I http://canvas.example.com/health_check
    

    If Canvas starts correctly, you should receive an HTTP response rather than a Passenger application error.

    You can also watch Canvas’s production log:

    sudo tail -f /var/canvas/log/production.log
    

    And Apache:

    sudo tail -f /var/log/apache2/canvas_error.log
    

    These two logs are extremely useful during initial deployment.

  31. Install Let’s Encrypt SSL

    Install Certbot:

    sudo apt install -y certbot python3-certbot-apache
    

    Request certificates for both Canvas hostnames:

    sudo certbot --apache \
        -d canvas.example.com \
        -d canvasfiles.example.com
    

    Certbot will:

    1. Validate the DNS records.
    2. Request the certificates.
    3. Modify the Apache VirtualHost.
    4. Configure HTTPS.
    5. Optionally redirect HTTP to HTTPS.

    Verify renewal:

    sudo certbot renew --dry-run
    

    Check the timer:

    systemctl status certbot.timer
    
  32. Verify HTTPS

    Test:

    curl -I https://canvas.example.com/
    

    Then:

    curl -I https://canvas.example.com/health_check
    

    Open:

    https://canvas.example.com
    

    in your browser.

    You should reach the Canvas login interface.

    Log in using the administrator credentials created during:

    RAILS_ENV=production bundle exec rake db:initial_setup
    
  33. Configure Canvas Background Jobs

    Canvas relies heavily on background jobs for:

    • email notifications
    • reports
    • statistics
    • course operations
    • file processing
    • scheduled tasks
    • imports and exports
    • other asynchronous actions

    Canvas will not function correctly without the background job worker.

    The Canvas source includes:

    /var/canvas/script/canvas_init
    

    Create the service link:

    sudo ln -s /var/canvas/script/canvas_init /etc/init.d/canvas_init
    

    Register it:

    sudo update-rc.d canvas_init defaults
    

    Start it:

    sudo /etc/init.d/canvas_init start
    

    Check processes:

    ps aux | grep delayed_job
    

    You should see Canvas delayed job workers.

    The current Canvas source still contains the canvas_init script, and its purpose is specifically to start and stop Canvas background jobs under RAILS_ENV=production.

    For a larger installation, you can dedicate one or more separate Canvas application nodes exclusively to processing these background jobs.

  34. Verify Canvas Services

    Check PostgreSQL:

    sudo systemctl status postgresql
    

    Check Redis:

    sudo systemctl status redis-server
    

    Check Apache:

    sudo systemctl status apache2
    

    Check Passenger:

    sudo passenger-memory-stats
    

    Check workers:

    ps aux | grep delayed_job
    

    Check HTTP:

    curl -I https://canvas.example.com/
    

    Check health endpoint:

    curl -I https://canvas.example.com/health_check
    
  35. Test Redis from Canvas

    You can verify that Rails boots in production mode:

    See Also: How to Host a Telegram Bot on Ubuntu VPS

    cd /var/canvas
    

    Run:

    sudo -u canvasuser \
    RAILS_ENV=production \
    bundle exec rails runner 'puts Rails.env'
    

    Expected:

    production
    

    You can also check Redis directly:

    redis-cli ping
    

    Expected:

    PONG
    
  36. Test Outgoing Email

    After logging into Canvas, configure an account with a valid email address and trigger a notification or password reset.

    Watch:

    sudo tail -f /var/canvas/log/production.log
    

    If delivery fails, common causes include:

    • incorrect SMTP password
    • blocked SMTP port
    • wrong TLS mode
    • invalid sender address
    • provider requiring SMTP AUTH
    • SPF/DKIM misconfiguration
    • VPS provider blocking outbound port 25

    Where possible, use authenticated SMTP submission over:

    587
    

    rather than sending directly over port 25.

  37. Optional: Enable X-Sendfile

    If Canvas stores uploaded files locally, Apache’s X-Sendfile support can improve file download performance by allowing Apache to serve file content directly instead of passing it through Rails.

    Install:

    sudo apt install -y libapache2-mod-xsendfile
    

    Verify:

    sudo apachectl -M | grep xsendfile
    

    You should see:

    xsendfile_module
    

    Add to the Canvas VirtualHost:

    XSendFile On
    XSendFilePath /var/canvas
    

    Canvas’s production documentation recommends this optimization for installations using local file storage.

    Restart Apache:

    sudo systemctl restart apache2
    
  38. Understand the Canvas Files Domain

    Canvas should ideally use:

    canvas.example.com
    

    for the application and:

    canvasfiles.example.com
    

    for uploaded content.

    This provides a security boundary between the Canvas application and user-controlled files.

    Both DNS records can point to the same VPS:

    canvas.example.com       -> VPS IP
    canvasfiles.example.com  -> VPS IP
    

    and both can be handled by the same Apache configuration.

    What matters is that browsers see them as separate origins.

  39. Consider Object Storage for Production

    Local disk storage works for a small Canvas installation, but it becomes a limitation as course uploads grow.

    For a more scalable deployment, consider S3-compatible object storage.

    That allows Canvas web servers to remain relatively disposable while uploaded content lives independently.

    A more scalable architecture might look like:

                             +-------------------+
                             |  Load Balancer    |
                             +---------+---------+
                                       |
                             +---------+---------+
                             |                   |
                      +------v------+     +------v------+
                      | Canvas Web 1 |     | Canvas Web 2 |
                      +------+------+     +------+-------+
                             |                   |
                             +---------+---------+
                                       |
                  +--------------------+--------------------+
                  |                    |                    |
           +------v------+      +------v------+      +------v------+
           | PostgreSQL  |      |    Redis    |      | Object/S3   |
           +-------------+      +-------------+      +-------------+
                                       |
                                +------v------+
                                | Canvas Jobs |
                                +-------------+
    

    For a small VPS, however, running everything on one host is a reasonable starting point.

  40. Configure Automatic Security Updates

    Install:

    sudo apt install -y unattended-upgrades
    

    Enable:

    sudo dpkg-reconfigure --priority=low unattended-upgrades
    

    Remember that Canvas itself is not updated through Ubuntu’s package manager because it was installed from Git.

  41. Back Up Canvas

    At minimum, back up:

    PostgreSQL

    sudo -u postgres pg_dump \
        -Fc \
        canvas_production \
        > /root/canvas_production.dump
    

    Canvas configuration

    sudo tar czf /root/canvas-config.tar.gz \
        /var/canvas/config
    

    Uploaded files

    If using local file storage, back up the Canvas file store as well.

    See Also: How to Install Concourse CI on Ubuntu VPS

    SSL certificates

    Certbot certificates live under:

    /etc/letsencrypt
    

    A proper backup strategy should therefore protect:

    PostgreSQL database
    Canvas uploaded files
    /var/canvas/config
    /etc/letsencrypt
    custom branding/themes
    external integration credentials
    

    Do not rely only on a VPS snapshot as your sole backup.

  42. Updating Canvas LMS

    Before every update:

    1. Back up PostgreSQL.
    2. Back up configuration.
    3. Take a VPS snapshot if available.
    4. Review Canvas changes before deploying.
    5. Schedule maintenance if necessary.

    Enter Canvas:

    cd /var/canvas
    

    Confirm the branch:

    git status
    git branch --show-current
    

    Retrieve updates:

    git fetch origin
    

    Update the production branch:

    git checkout prod
    git pull
    

    Install Ruby dependencies:

    bundle install
    

    Install JavaScript dependencies:

    yarn install
    

    Run database migrations:

    RAILS_ENV=production bundle exec rake db:migrate
    

    Recompile assets:

    RAILS_ENV=production \
    SASS_STYLE=compressed \
    bundle exec rake canvas:compile_assets
    

    Canvas’s production documentation also recommends regenerating existing themes after subsequent updates:

    RAILS_ENV=production \
    bundle exec rake brand_configs:generate_and_upload_all
    

    Restore ownership:

    sudo chown -R canvasuser:canvasuser \
        /var/canvas/log \
        /var/canvas/tmp \
        /var/canvas/public/assets \
        /var/canvas/public/dist
    

    Restart workers:

    sudo /etc/init.d/canvas_init restart
    

    Restart Apache:

    sudo systemctl restart apache2
    

    Then test:

    curl -I https://canvas.example.com/health_check
    
  43. Useful Troubleshooting Commands

    Check Canvas

    sudo tail -100 /var/canvas/log/production.log
    

    Or follow live:

    sudo tail -f /var/canvas/log/production.log
    

    Check Apache

    sudo tail -100 /var/log/apache2/canvas_error.log
    

    Check Apache syntax

    sudo apachectl configtest
    

    Expected:

    Syntax OK
    

    Check Passenger

    sudo passenger-config validate-install
    

    And:

    sudo passenger-memory-stats
    

    Check PostgreSQL

    sudo systemctl status postgresql
    

    Test the database:

    psql -h localhost \
        -U canvas \
        -d canvas_production
    

    Check Redis

    redis-cli ping
    

    Expected:

    PONG
    

    Check Canvas workers

    ps aux | grep delayed_job
    

    Verify the installed versions

    ruby --version
    node --version
    yarn --version
    psql --version
    redis-server --version
    apache2 -v
    
  44. Canvas Returns HTTP 500

    Start with:

    sudo tail -100 /var/canvas/log/production.log
    

    Then:

    sudo tail -100 /var/log/apache2/canvas_error.log
    

    Common causes are:

    • database credentials are incorrect
    • security.yml is incomplete
    • Canvas cannot read configuration files
    • Passenger is using the wrong Ruby
    • database initialization was not completed
    • pending database migrations
    • Redis configuration is invalid
    • Canvas runtime directories are not writable

    Check database state:

    See Also: Top 10 Best Grafana Dashboards for Service Monitoring

    cd /var/canvas
    RAILS_ENV=production bundle exec rake db:migrate:status
    
  45. Canvas Loads but Has No CSS

    This almost always indicates a problem with compiled assets or static asset delivery.

    Recompile:

    cd /var/canvas
    

    Then:

    RAILS_ENV=production \
    SASS_STYLE=compressed \
    bundle exec rake canvas:compile_assets
    

    Check:

    ls -lah public/dist
    

    And:

    ls -lah public/assets
    

    Repair ownership:

    sudo chown -R canvasuser:canvasuser \
        public/dist \
        public/assets
    

    Then restart Apache:

    sudo systemctl restart apache2
    

    Asset compilation is mandatory; Canvas may otherwise answer requests while presenting a broken interface.

  46. Passenger Reports a Ruby Error

    Check what Canvas itself sees:

    cd /var/canvas
    ruby --version
    bundle exec ruby --version
    

    Then inspect Passenger:

    sudo passenger-config about ruby-command
    

    If Passenger is using the wrong Ruby, explicitly configure:

    PassengerRuby /usr/bin/ruby
    

    then:

    sudo systemctl restart apache2
    
  47. Background Tasks Are Not Running

    Check:

    ps aux | grep delayed_job
    

    Restart:

    sudo /etc/init.d/canvas_init restart
    

    Then examine:

    sudo tail -f /var/canvas/log/delayed_job.log
    

    and:

    sudo tail -f /var/canvas/log/production.log
    

    Pay particular attention to file permissions on:

    /var/canvas/config
    /var/canvas/log
    /var/canvas/tmp
    

    Canvas workers need to read the protected configuration files and write to their runtime directories.

  48. Production Security Checklist

    Before opening the LMS to users, verify all of the following:

    • HTTPS is enabled.
    • HTTP redirects to HTTPS.
    • PostgreSQL is not exposed publicly.
    • Redis is not exposed publicly.
    • Canvas runs as canvasuser, not root.
    • Configuration files are protected.
    • SSH root authentication is restricted where practical.
    • Password authentication is disabled if SSH keys are used.
    • UFW or another firewall is configured.
    • Automatic operating-system security updates are enabled.
    • SMTP credentials are protected.
    • PostgreSQL backups are automated.
    • User-uploaded files are backed up.
    • Off-server backups exist.
    • DNS has been configured correctly.
    • SPF/DKIM/DMARC are configured for outgoing mail.
    • Canvas background workers are running.
    • /health_check responds normally.
    • PostgreSQL, Redis, Apache, and Canvas logs are monitored.
  49. Recommended Production Architecture

    For a small organization:

    Ubuntu VPS
    |
    +-- Apache + Passenger
    |
    +-- Canvas LMS
    |
    +-- Canvas delayed jobs
    |
    +-- PostgreSQL
    |
    +-- Redis
    |
    +-- Local or S3-compatible file storage
    

    For modest production usage, start with roughly:

    4-8 vCPU
    8-16 GB RAM
    100+ GB NVMe
    

    For heavier usage, separate components:

    2+ Canvas web servers
    1+ Canvas jobs server
    Dedicated PostgreSQL
    Dedicated Redis
    S3-compatible object storage
    Load balancer
    Central backups
    Monitoring
    

    Canvas’s own production documentation explicitly notes that the web application, database, and job processing can be separated and that busy environments benefit from moving job processing onto dedicated nodes.

  50. Final Verification

    Run:

    See Also: Backup WordPress Site to Microsoft OneDrive

    curl -I https://canvas.example.com/
    

    Then:

    curl -I https://canvas.example.com/health_check
    

    Check all major services:

    sudo systemctl status apache2
    sudo systemctl status postgresql
    sudo systemctl status redis-server
    

    Check Passenger:

    sudo passenger-memory-stats
    

    Check jobs:

    ps aux | grep delayed_job
    

    Finally visit:

    https://canvas.example.com
    

    and log in with the administrator account created during db:initial_setup.

    You now have a self-hosted Canvas LMS installation running on an Ubuntu VPS with PostgreSQL, Redis, Apache, Passenger, HTTPS, and Canvas background processing.

Important Version Note

Canvas LMS is under active development, so dependency requirements can change relatively quickly. As of the current Canvas source and production documentation:

Ubuntu reference platform: 22.04 LTS
Ruby:                     3.4.1+
Node.js:                  20+
PostgreSQL:               14+
Redis:                    6+
Yarn:                     1.x / ^1.19.1
Web server:               Apache + Passenger
Production branch:        prod

Instructure’s Production Start documentation was most recently updated in May 2026, and the source tree currently pins Ruby 3.4.1 in Gemfile.lock while requiring Node.js 20 or later in package.json.

Before installing a future Canvas release or performing a major upgrade, always compare these values with the current prod branch instead of assuming an older Canvas installation guide remains accurate.
Launch 100% ssd ubuntu vps from $3. 19/mo!

Conclusion

You now know how to install Canvas LMS on Ubuntu VPS.

Avatar of editorial staff

Editorial Staff

Rad Web Hosting is a leading provider of web hosting, Cloud VPS, and Dedicated Servers in Dallas, TX.

Leave a Reply

lg