In today’s digital landscape, managing student classes, assignments, and research tools effectively requires a robust and flexible Learning Management System (LMS). Canvas LMS has emerged as a leading open-source platform, offering comprehensive features that cater to the needs of both educators and learners. Its modular design, extensive integration options, and support for modern standards like Learning Tools Interoperability (LTI) make it a powerful choice.
Canvas LMS is versatile and can be deployed for various purposes, including small group or organizational use, research data collection, and development projects like Caliper analytics. It also supports interoperability with different LTI versions. This guide is particularly focused on individuals setting up their own Canvas instance, who need access to the Canvas admin panel or dashboard for development and building LTI 1.3 support for learning tools.
However, there is a notable challenge in the adoption of LTI 1.3 by institutions and individuals. Public Canvas instances, such as those hosted by Instructure, do not support LTI 1.3, which is the latest version enabling advanced integrations and tools. For educators, researchers, or developers seeking to leverage the full capabilities of LTI services, self-hosting Canvas LMS becomes essential.
In this article, I’ll walk you through deploying Canvas LMS on a Kubernetes cluster. Whether you’re managing a small educational organization or working on research and development, this guide will help you navigate the challenges of deploying a large-scale application like Canvas. You’ll gain the knowledge needed to set up Canvas, troubleshoot common issues, and leverage its powerful features, including Single Sign-On security with LTI 1.3. LTI 1.3 has become the industry standard for OAuth 2.0 security and Single Sign-On, used by platforms like LinkedIn Learning, which essentially serves as LinkedIn’s own Learning Management System.
Before diving into the deployment process, it’s essential to set up the foundational components. Start by cloning the Canvas LMS repository and configuring the required Docker and Docker Compose files to suit your needs.
To begin, clone the Canvas LMS GitHub repository and switch to the prod branch. The production branch is optimized for deployment and contains the necessary files for setting up Canvas in a production environment. Run the following commands:
git clone https://github.com/instructure/canvas-lms.git
cd canvas-lms
git checkout prod
Canvas LMS supports Docker-based deployment, making it easier to containerize and orchestrate the application and its dependencies. Inside the repository, you’ll find:
Kubernetes is an Orchestrating platform for containerized applications, basically applications packaged in a container, in which the ned user needs not to worry about environments, packages, versions etc, as name says the application can easily run on a container on any enviorment. Kuberntes provides a distributed cluster to easily orchestrate the containers and application mostly have some kind of distributed architecture or microservice architecture. so Kubernetes facilitates both configuration and automation of tht application’s ecosystem e.g an application might come with an API gateway as a standalone application, redis application for queue management, Database container, a file system and a user interface so this kind of distributed architecture there 5 different standalone application that interact with each other.
Here is a diagram that gives an overview of a Kubernetes environment.
Here also links to the overview of Kubernetes:
· Kubernetes overview & essential Reading
To deploy Canvas LMS on Kubernetes, we leverage Kompose (conversion tool for docker compose to container orchastrators like Kubernetes) **to translate the existing docker-compose.yml into Kubernetes manifests. Kompose simplifies the process of converting Docker-based configurations into Kubernetes-native resources, such as:
· Deployments (Canvas Web, Redis, Postgres)
. Services (ClusterIP for internal services, LoadBalancer for public access)
. Persistent Volume Claims (PVCs)
After conversion, we can enhance these configurations to suit your production requirements. Carefully review the auto generated Kubernetes manifest by Kompose.
The Canvas LMS application requires several Kubernetes components to function correctly: Deployments, Services, and Persistent Volumes. Translating Docker Compose with Kompose, run the following command to convert the docker-compose.yml file into Kubernetes YAML files:
kompose convert -f docker-compose.yml
This command generates several YAML files, including deployments, services, and persistent volume claims for all services defined in docker-compose.yml.
Here’s an example of the deployment file for the Canvas web application:
apiVersion: apps/v1
kind: Deployment
metadata:
name: canvas-web
labels:
app: canvas-web
spec:
replicas: 2
selector:
matchLabels:
app: canvas-web
template:
metadata:
labels:
app: canvas-web
spec:
containers:
- name: canvas-web
image: instructure/canvas-lms:latest
ports:
- containerPort: 3000
env:
- name: RAILS_ENV
value: "production"
- name: POSTGRES_PASSWORD
value: "securepassword"
- name: REDIS_URL
value: "redis://redis:6379"
volumeMounts:
- name: canvas-storage
mountPath: /usr/src/app/storage
volumes:
- name: canvas-storage
persistentVolumeClaim:
claimName: canvas-pvc
Also some Canvas requires persistent storage for its assets and configurations, Below is an example of a Persistent Volume Claim (PVC) configuration:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: canvas-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
The web application is exposed via a Kubernetes service, which routes traffic to the Canvas deployment. Depending on your cluster’s configuration, you can use a ClusterIP, NodePort, or LoadBalancer type.
Here’s an example of the Service definition:
apiVersion: v1
kind: Service
metadata:
name: canvas-web
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 3000
selector:
app: canvas-web
This configuration ensures that the Canvas web application is accessible over port 80 via an external load balancer.
For production setups, we recommend using an NGINX Ingress Controller to route domain-based traffic to Canvas LMS. Here’s an example Ingress configuration:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: canvas-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: canvas.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: canvas-web
port:
number: 80
I’ll pause here to keep this article concise, but I’ll continue with common issues you might encounter when deploying a Canvas instance.
Cloning the Canvas Repository
Clone the official Canvas LMS repository from GitHub. The prod branch is the most stable production-ready version of Canvas LMS. git clone https://github.com/instructure/canvas-lms.git cd canvas-lms
git checkout prod
Preparing the Configuration Files
Canvas relies on various configuration files to define its database, Redis, and email settings. Copy the example configurations and modify them as needed
cp config/database.yml.example config/database.yml cp config/outgoing_mail.yml.example config/outgoing_mail.yml
502 Bad Gateway (NGINX) Cause: The web service is not listening on the expected port.
Solution: Ensure that the service target port matches the container’s exposed port (3000 in our case).
kubectl logs <web-pod-name> kubectl logs canvas-web
503 Service Unavailable Cause: The service does not have available endpoints.
Solution: Ensure the pods are running and correctly labeled.
kubectl get pods kubectl describe service canvas-web-service
Database Connection Errors Cause: Incorrect credentials or network issues.
Solution: Check the DATABASE_URL environment variable in the deployment.
Missing Assets or Broken UI Cause: Asset compilation was not performed.
Solution: Run asset precompilation in the container:
kubectl exec -it <web-pod> -- bash cd /usr/src/app RAILS_ENV=production bundle exec rake assets:precompile
Permission Errors (Protected Directories in the Container)
Cause: Some files in /usr/src/app were owned by root, preventing docker user access.
Fix: Modify Dockerfile and Dockerfile.production to update ownership:
USER root RUN chown -R docker:docker /usr/src/app USER docker
Job Pods Keep Failing
Cause: Insufficient memory or missing dependencies.
Fix: Allocate more resources and check logs.
kubectl logs jobs-pod
Deploying Canvas LMS on Kubernetes empowers organizations, researchers, and educators with full control over their learning management systems. Whether you’re a small organization looking to self-host an LMS for assessments, assignments, and structured coursework, this setup could be an ideal solution for your users.
This guide provides valuable insights, covering:
With this setup, educators, researchers, and developers can self-host Canvas LMS, enabling LTI 1.3 features and efficiently managing learning environments. I’ve also included Kubernetes manifests in the Canvas LMS K8s repository here. Feel free to reach out if you encounter any issues!