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. 1. Preparing for Deployment 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. 1.1 Clone the Canvas LMS Repository 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 1.2 Focus on Docker Files and Configuration Canvas LMS supports Docker-based deployment, making it easier to containerize and orchestrate the application and its dependencies. Inside the repository, you’ll find: 1.2.1 Dockerfile This file defines the build instructions for the Canvas web application container. Review the FROM instructure/ruby-passenger base image and configurations for NGINX, Passenger, and Ruby. 1.2.2 docker-compose.yml This file defines the multi-container setup for local testing or lightweight deployments. Key services include: web → The Canvas web application. redis → Caching service. postgres → Database. 1.2.3 Local Build You can try a local build on your computer. Check out this quick start guide for more details. After launching the containers, ensure the database is migrated and seeded with default data using the rakecommands. Now you should access Canvas locally, now let’s move to deploying on Kubernetes. 2. Kubernetes 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: · Overview of Kubernetes · What is Kubernetes · Kubernetes overview & essential Reading · Tutorial — Kubernetes · Top posts about Kubernetes 3. Deploying the Kubernetes Cluster 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. 3.1 Creating the Canvas Deployment 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. Sample Deployment for Canvas Web Application 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 Exposing the Canvas Service 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. Ingress Configuration 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. Challenges Encountered and How I resolved Them 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-lmsgit 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 neededcp 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 Conclusion 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: Setting up Canvas from the GitHub repository Using Kompose to convert Docker Compose to Kubernetes Deploying services, configuring ingress, and setting up persistent storage Troubleshooting common Kubernetes and Canvas issues (Debugging 502, 503 errors, and permission issues) 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! 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 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. Canvas LMS 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. 1. Preparing for Deployment 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. Canvas LMS repository 1.1 Clone the Canvas LMS Repository 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 git clone https://github.com/instructure/canvas-lms.git cd canvas-lms git checkout prod 1.2 Focus on Docker Files and Configuration Canvas LMS supports Docker-based deployment , making it easier to containerize and orchestrate the application and its dependencies. Inside the repository, you’ll find: Docker-based deployment 1.2.1 Dockerfile This file defines the build instructions for the Canvas web application container. Review the FROM instructure/ruby-passenger base image and configurations for NGINX, Passenger, and Ruby. This file defines the build instructions for the Canvas web application container. build instructions Review the FROM instructure/ruby-passenger base image and configurations for NGINX, Passenger, and Ruby . NGINX, Passenger, and Ruby 1.2.2 docker-compose.yml This file defines the multi-container setup for local testing or lightweight deployments. Key services include: web → The Canvas web application. redis → Caching service. postgres → Database. This file defines the multi-container setup for local testing or lightweight deployments. multi-container setup Key services include: Key services include: web → The Canvas web application. web redis → Caching service. redis postgres → Database. postgres 1.2.3 Local Build You can try a local build on your computer. Check out this quick start guide for more details. After launching the containers, ensure the database is migrated and seeded with default data using the rakecommands. Now you should access Canvas locally, now let’s move to deploying on Kubernetes. You can try a local build on your computer. Check out this quick start guide for more details. local build this quick start guide After launching the containers, ensure the database is migrated and seeded with default data using the rakecommands. database is migrated seeded with default data Now you should access Canvas locally, now let’s move to deploying on Kubernetes. 2. Kubernetes 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 is a diagram that gives an overview of a Kubernetes environment. Here also links to the overview of Kubernetes: · Overview of Kubernetes Overview of Kubernetes · What is Kubernetes What is Kubernetes · Kubernetes overview & essential Readin g Kubernetes overview & essential Readin · Tutorial — Kubernetes Tutorial — Kubernetes · Top posts about Kubernetes Top posts about Kubernetes 3. Deploying the Kubernetes Cluster 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) Deployments . Services (ClusterIP for internal services, LoadBalancer for public access) Services . Persistent Volume Claims (PVCs) 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. 3.1 Creating the Canvas Deployment 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: Deployments Services Persistent Volumes kompose convert -f docker-compose.yml 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. Sample Deployment for Canvas Web Application 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 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 apiVersion: v1 kind: PersistentVolumeClaim metadata: name: canvas-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi Exposing the Canvas Service 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. ClusterIP NodePort LoadBalancer 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 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. Ingress Configuration For production setups, we recommend using an NGINX Ingress Controller to route domain-based traffic to Canvas LMS. Here’s an example Ingress configuration: NGINX Ingress Controller 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 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. Challenges Encountered and How I resolved Them 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-lmsgit 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 neededcp 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 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 Cloning the Canvas Repository 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 Canvas LMS prod branch https://github.com/instructure/canvas-lms.git git checkout prod 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 Preparing the Configuration Files 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 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 502 Bad Gateway (NGINX) Cause : The web service is not listening on the expected port. 502 Bad Gateway (NGINX) Cause Solution : Ensure that the service target port matches the container’s exposed port (3000 in our case). Solution kubectl logs <web-pod-name> kubectl logs canvas-web 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 503 Service Unavailable Cause : The service does not have available endpoints. 503 Service Unavailable Cause Solution : Ensure the pods are running and correctly labeled. Solution kubectl get pods kubectl describe service canvas-web-service 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. Database Connection Errors Cause : Incorrect credentials or network issues. Database Connection Errors Cause Solution : Check the DATABASE_URL environment variable in the deployment. Solution 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 Missing Assets or Broken UI Cause : Asset compilation was not performed. Missing Assets or Broken UI Cause Solution : Run asset precompilation in the container: Solution kubectl exec -it <web-pod> -- bash cd /usr/src/app RAILS_ENV=production bundle exec rake assets:precompile 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 Permission Errors (Protected Directories in the Container) Permission Errors (Protected Directories in the Container) Cause: Some files in /usr/src/app were owned by root, preventing docker user access. Cause: Fix: Modify Dockerfile and Dockerfile.production to update ownership: Fix: USER root RUN chown -R docker:docker /usr/src/app USER docker 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 Job Pods Keep Failing Cause: Insufficient memory or missing dependencies. Cause: Fix: Allocate more resources and check logs. Fix: kubectl logs jobs-pod kubectl logs jobs-pod Conclusion 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: Setting up Canvas from the GitHub repository Using Kompose to convert Docker Compose to Kubernetes Deploying services, configuring ingress, and setting up persistent storage Troubleshooting common Kubernetes and Canvas issues (Debugging 502, 503 errors, and permission issues) Setting up Canvas from the GitHub repository Using Kompose to convert Docker Compose to Kubernetes Deploying services, configuring ingress, and setting up persistent storage Troubleshooting common Kubernetes and Canvas issues (Debugging 502, 503 errors, and permission issues) 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! here