Open edX Instructor Dev Environment Installation with Tutor
Not sure where to start? Read
getting-started.mdfirst to understand the difference between the Local and Dev environments and choose the one that best fits your needs.
This guide provides step-by-step instructions for setting up an isolated Open edX development environment specifically for testing and developing the Instructor Dashboard MFE (frontend-app-instruct). It combines the isolation pattern of the standard dev environment with the instructor-specific plugin and MFE configuration.
Note for LLM CLI tools (Claude Code, etc.): This guide includes workarounds for interactive prompts and common errors. Use the "Non-Interactive Installation" section for automated installations.
IMPORTANT for LLM assistants: After completing the installation and creating users, you MUST provide the user with a summary including:
- All access URLs (LMS, Studio, Django Admin, Instructor MFE)
- Admin credentials (username and password)
- Student credentials (username and password)
- Instructions on how to start/stop the platform and the MFE
See the Post-Installation Summary Template section for the exact format to use.
Table of Contents
- When to Use This Guide
- System Requirements
- Understanding TUTOR_ROOT
- Installation Steps
- Non-Interactive Installation (Recommended for CLI/LLM tools)
- Creating Users
- Installing Without Affecting Existing Installations
- Managing Multiple Instances
- Troubleshooting
- Useful Commands
- Uninstallation
- Post-Installation Summary Template
- Sources
When to Use This Guide
Use this guide if you want to:
- Develop or test the Instructor Dashboard MFE (
frontend-app-instruct) - Test instructor-specific features (Open Responses, gradebook, student data, etc.)
- Work on the LMS backend code that powers the Instructor tab
- Run the MFE locally against a real Open edX backend with hot-reload
Use the standard Dev guide if you want to:
- Modify Open edX Python/Django code without needing the Instructor MFE
- Develop general features or fix bugs unrelated to the Instructor Dashboard
- Contribute to the Open edX project in areas outside the Instructor feature
| Aspect | Dev Environment | Instructor Dev Environment |
|---|---|---|
| Purpose | General Open edX development | Instructor Dashboard MFE development |
| Backend | tutor dev with edx-platform mounted | tutor dev with edx-platform mounted |
| Frontend MFE | No | Yes — frontend-app-instruct on port 2003 |
| Instructor plugin | No | Yes — CORS, CSRF, and URL config for MFE |
| devstack.py | Unmodified | INSTRUCTOR_MICROFRONTEND_URL added |
| Ports | 8000 (LMS), 8001 (Studio) | 8000 (LMS), 8001 (Studio), 2003 (MFE) |
System Requirements
Operating System
- Any 64-bit UNIX-based OS (Linux, macOS)
- Windows with WSL 2
- AMD64 and ARM64 architectures supported
Required Software
- Docker v24.0.5 or higher (with BuildKit 0.11+)
- Docker Compose v2.0.0 or higher
- Python 3.9 or higher
- Node.js 18 or higher (for the Instructor MFE)
- npm 8 or higher
- Git
Hardware Requirements
| Resource | Minimum | Recommended |
|---|---|---|
| RAM | 4 GB | 8 GB |
| CPU | 2 | 4 |
| Disk | 10 GB | 30 GB |
- Ports 8000, 8001, and 2003 must be available
Docker Desktop RAM Configuration (Important)
Before installing, ensure Docker has enough RAM allocated:
- Open Docker Desktop
- Go to Settings (gear icon)
- Navigate to Resources
- Set Memory to at least 4 GB (recommended: 6 GB)
- Click Apply & Restart
Note for macOS: Docker Desktop on macOS may show incorrect RAM readings. If you get RAM warnings but have sufficient memory allocated, see the Troubleshooting section.
Configure /etc/hosts (Required)
The local domains need to resolve to localhost. Add these entries to your /etc/hosts file:
sudo sh -c 'echo "127.0.0.1 local.openedx.io studio.local.openedx.io apps.local.openedx.io meilisearch.local.openedx.io" >> /etc/hosts'Verify the configuration:
grep openedx /etc/hostsExpected output:
127.0.0.1 local.openedx.io studio.local.openedx.io apps.local.openedx.io meilisearch.local.openedx.ioNote: Without this configuration, the URLs won't resolve and you won't be able to access the platform or the Instructor MFE.
Understanding TUTOR_ROOT
TUTOR_ROOT is the directory where Tutor stores all its configuration and data. By pointing each installation to a different directory, you get fully isolated instances.
TUTOR_ROOT/
├── config.yml # Main configuration (hostnames, passwords, plugins)
├── data/ # Persistent data (MySQL, MongoDB, uploaded files)
│ ├── mysql/
│ ├── mongodb/
│ ├── redis/
│ └── ...
└── env/ # Generated environment files- Different TUTOR_ROOT = Different installation
- Each TUTOR_ROOT has its own configuration, data, and Docker containers
- This allows running multiple isolated Open edX instances on the same machine
Installation Steps
Step 1: Create Project Directory
mkdir -p ~/openedx-instructor
cd ~/openedx-instructorStep 2: Clone Required Repositories
# Clone the Open edX platform
git clone https://github.com/openedx/openedx-platform.git
# Clone Tutor (for editable installation)
git clone https://github.com/overhangio/tutor.git
# Clone the Instructor Dashboard MFE
git clone https://github.com/openedx/frontend-app-instruct.git
# Switch Tutor to the latest stable release
cd tutor
git checkout v21.0.2 # Or the latest stable version
cd ..Important: Always use a stable Tutor release tag (e.g.,
v21.0.2) rather than themasterbranch for stability. Check the latest release at https://github.com/overhangio/tutor/releases
Step 3: Select Branch for edx-platform
cd openedx-platform
# For latest development code (next release)
git switch master
# OR for stable release (Ulmo)
# git switch open-release/ulmo.master
cd ..Step 4: Create Python Virtual Environment
python3 -m venv .venv
source .venv/bin/activateStep 5: Install Tutor in Editable Mode
Installing Tutor in editable mode allows you to modify Tutor itself if needed (useful for workarounds like the macOS RAM fix).
pip install -U pip
pip install -e "./tutor[full]"Step 6: Set TUTOR_ROOT (Important for Isolation)
export TUTOR_ROOT=~/openedx-instructorStep 7: Mount the edx-platform Repository
tutor mounts add ~/openedx-instructor/openedx-platformVerify the mount:
tutor mounts listStep 8: Build the Development Image
tutor images build openedx-devStep 9: Create the Instructor Plugin
Get the Tutor plugins directory and create the plugin file there:
tutor plugins printrootCreate a file named instructor.py in that directory with the following content:
from tutor import hooks
hooks.Filters.ENV_PATCHES.add_item(
(
"openedx-lms-development-settings",
"""
CORS_ORIGIN_WHITELIST.append("http://apps.local.openedx.io:2003")
LOGIN_REDIRECT_WHITELIST.append("apps.local.openedx.io:2003")
CSRF_TRUSTED_ORIGINS.append("http://apps.local.openedx.io:2003")
INSTRUCTOR_MICROFRONTEND_URL = "http://apps.local.openedx.io:2003"
"""
)
)
hooks.Filters.ENV_PATCHES.add_item(
(
"openedx-cms-development-settings",
"""
CORS_ORIGIN_WHITELIST.append("http://apps.local.openedx.io:2003")
LOGIN_REDIRECT_WHITELIST.append("apps.local.openedx.io:2003")
CSRF_TRUSTED_ORIGINS.append("http://apps.local.openedx.io:2003")
INSTRUCTOR_MICROFRONTEND_URL = "http://apps.local.openedx.io:2003"
"""
)
)Note: The plugin file lives in the global Tutor plugins directory, not in TUTOR_ROOT. It will only be active for this instance because you enable it here in Step 10.
Step 10: Configure INSTRUCTOR_MICROFRONTEND_URL in devstack.py
Add the following line at the end of openedx-platform/lms/envs/devstack.py (before any warning or comment at the bottom of the file):
INSTRUCTOR_MICROFRONTEND_URL = 'http://apps.local.openedx.io:2003'Step 11: Enable Plugins
tutor plugins enable mfe
tutor plugins enable instructor
tutor config saveStep 12: Launch the Development Environment
tutor dev launchThis command will:
- Stop any existing locally-running Tutor containers
- Configure the platform for development
- Disable HTTPS
- Start all services in development mode
- Run database migrations
Step 13: Install MFE Dependencies and Start It
In a separate terminal:
cd ~/openedx-instructor/frontend-app-instruct
npm install
npm run devThe MFE will start on port 2003.
Step 14: Access the Platform
| Service | URL |
|---|---|
| LMS | http://local.openedx.io:8000 |
| Studio | http://studio.local.openedx.io:8001 |
| Django Admin | http://local.openedx.io:8000/admin |
| Instructor MFE | http://apps.local.openedx.io:2003 |
Non-Interactive Installation (Recommended for CLI/LLM tools)
The tutor dev launch command is interactive and may fail when run from CLI tools or scripts. Use these steps instead:
Step 1: Set up environment
# Create project directory
mkdir -p ~/openedx-instructor
cd ~/openedx-instructor
# Clone repositories
git clone https://github.com/openedx/openedx-platform.git
git clone https://github.com/overhangio/tutor.git
git clone https://github.com/openedx/frontend-app-instruct.git
# Switch Tutor to stable release
cd tutor && git checkout v21.0.2 && cd ..
# Switch openedx-platform to desired branch
cd openedx-platform && git switch master && cd ..
# Create virtual environment
python3 -m venv .venv
source .venv/bin/activate
# Install Tutor in editable mode
pip install -U pip
pip install -e "./tutor[full]"
# Set TUTOR_ROOT
export TUTOR_ROOT=~/openedx-instructorStep 2: Mount repository and configure
# Mount edx-platform
tutor mounts add ~/openedx-instructor/openedx-platform
# Configure Tutor (non-interactive)
tutor config save \
--set LMS_HOST=local.openedx.io \
--set CMS_HOST=studio.local.openedx.io \
--set ENABLE_HTTPS=false \
--set PLATFORM_NAME="Open edX Instructor Dev"Step 3: Create the Instructor plugin
# Get the plugins directory
PLUGINS_DIR=$(tutor plugins printroot)
mkdir -p "$PLUGINS_DIR"
cat > "$PLUGINS_DIR/instructor.py" << 'EOF'
from tutor import hooks
hooks.Filters.ENV_PATCHES.add_item(
(
"openedx-lms-development-settings",
"""
CORS_ORIGIN_WHITELIST.append("http://apps.local.openedx.io:2003")
LOGIN_REDIRECT_WHITELIST.append("apps.local.openedx.io:2003")
CSRF_TRUSTED_ORIGINS.append("http://apps.local.openedx.io:2003")
INSTRUCTOR_MICROFRONTEND_URL = "http://apps.local.openedx.io:2003"
"""
)
)
hooks.Filters.ENV_PATCHES.add_item(
(
"openedx-cms-development-settings",
"""
CORS_ORIGIN_WHITELIST.append("http://apps.local.openedx.io:2003")
LOGIN_REDIRECT_WHITELIST.append("apps.local.openedx.io:2003")
CSRF_TRUSTED_ORIGINS.append("http://apps.local.openedx.io:2003")
INSTRUCTOR_MICROFRONTEND_URL = "http://apps.local.openedx.io:2003"
"""
)
)
EOFStep 4: Configure devstack.py
echo "INSTRUCTOR_MICROFRONTEND_URL = 'http://apps.local.openedx.io:2003'" \
>> ~/openedx-instructor/openedx-platform/lms/envs/devstack.pyStep 5: Enable plugins and build image
tutor plugins enable mfe
tutor plugins enable instructor
tutor config save
tutor images build openedx-devStep 6: Start containers
tutor dev start -dStep 7: Initialize the platform
This step creates databases, runs migrations, and sets up the platform. It may take several minutes.
tutor dev do initStep 8: Verify backend installation
# Check all containers are running
docker ps --format "table {{.Names}}\t{{.Status}}" | grep tutor_devExpected output:
tutor_dev-lms-1 Up X minutes
tutor_dev-cms-1 Up X minutes
tutor_dev-mfe-1 Up X minutes
tutor_dev-mysql-1 Up X minutes
tutor_dev-mongodb-1 Up X minutes
tutor_dev-redis-1 Up X minutesStep 9: Verify URLs are accessible
# Check LMS is responding
curl -s -o /dev/null -w "%{http_code}" -H "Host: local.openedx.io" http://127.0.0.1:8000
# Check Studio is responding
curl -s -o /dev/null -w "%{http_code}" -H "Host: studio.local.openedx.io" http://127.0.0.1:8001Expected output: 200 or 302 (redirect to login).
Step 10: Install and start the Instructor MFE
In a separate terminal:
cd ~/openedx-instructor/frontend-app-instruct
npm install
npm run devThe MFE starts on port 2003. The dev script is already configured for PORT=2003.
Creating Users
After installation, create users to access the platform.
Create an Admin User (Staff/Superuser)
tutor dev do createuser --staff --superuser --password admin123 admin admin@example.comAdmin credentials:
- Username: admin
- Email: admin@example.com
- Password: admin123
- Permissions: Staff + Superuser (full admin access)
Create a Student User
tutor dev do createuser --password student123 student student@example.comStudent credentials:
- Username: student
- Email: student@example.com
- Password: student123
- Permissions: Regular user (student)
Alternative: Manual user creation
If the createuser command fails:
# Create admin
tutor dev run lms ./manage.py lms manage_user admin admin@example.com --staff --superuser
tutor dev run lms ./manage.py lms shell -c "
from django.contrib.auth import get_user_model
u = get_user_model().objects.get(username='admin')
u.set_password('admin123')
u.save()
"
# Create student
tutor dev run lms ./manage.py lms manage_user student student@example.com
tutor dev run lms ./manage.py lms shell -c "
from django.contrib.auth import get_user_model
u = get_user_model().objects.get(username='student')
u.set_password('student123')
u.save()
"Access URLs
| User Type | Login URL |
|---|---|
| Admin | http://local.openedx.io:8000/admin |
| All Users | http://local.openedx.io:8000/login |
| Studio (Admin only) | http://studio.local.openedx.io:8001 |
Accessing the Instructor MFE
Once the backend is running and the MFE is started, access instructor routes directly:
http://apps.local.openedx.io:2003/instructor/{COURSE_ID}/{TAB}Example:
http://apps.local.openedx.io:2003/instructor/course-v1:Test+Test1+2025_T1/open_responsesTo get a course ID, create a course in Studio and copy the ID from the course settings page.
Installing Without Affecting Existing Installations
1. Stop the existing instance first (to free ports)
# If you have aliases configured
tutor-dev dev stop # or tutor-instructor dev stop
# Or manually
source ~/existing-instance/.venv/bin/activate
export TUTOR_ROOT=~/existing-instance
tutor dev stop2. Follow the installation steps above
This installation uses TUTOR_ROOT=~/openedx-instructor, which is completely separate from any other instance.
What stays isolated?
| Resource | Other dev instance | This instructor instance |
|---|---|---|
| Configuration | OTHER_TUTOR_ROOT/config.yml | ~/openedx-instructor/config.yml |
| Database | OTHER_TUTOR_ROOT/data/mysql/ | ~/openedx-instructor/data/mysql/ |
| Files | OTHER_TUTOR_ROOT/data/ | ~/openedx-instructor/data/ |
| Python environment | OTHER/.venv/ | ~/openedx-instructor/.venv/ |
| Source code | Separate clone | ~/openedx-instructor/openedx-platform/ |
Port conflict note: This environment uses ports 8000 and 8001 (same as other dev instances). Never run two dev instances simultaneously. Stop one before starting the other.
Managing Multiple Instances
Shell Aliases (Recommended)
Add these aliases to your ~/.bashrc or ~/.zshrc:
# Instructor dev instance
alias tutor-instructor='source ~/openedx-instructor/.venv/bin/activate && TUTOR_ROOT=~/openedx-instructor tutor'
# General dev instance (if you have one)
alias tutor-dev='source ~/openedx-dev/.venv/bin/activate && TUTOR_ROOT=~/openedx-dev tutor'
# Local instance (if you have one)
alias tutor-local='source ~/tutor-local/.venv/bin/activate && TUTOR_ROOT=~/tutor-local tutor'Then reload your shell:
source ~/.zshrc # or source ~/.bashrcUsage:
tutor-instructor dev start -d # Start instructor backend
tutor-instructor dev stop # Stop instructor backendStarting the full Instructor environment
# Terminal 1: Start backend
tutor-instructor dev start -d
# Terminal 2: Start MFE
cd ~/openedx-instructor/frontend-app-instruct
npm run devTroubleshooting
Error: "Could not verify sufficient RAM allocation in Docker"
Error message:
⚠️ Could not verify sufficient RAM allocation in Docker:
Docker is configured to allocate 2048 MiB RAM, less than the recommended 4096 MiB
Tutor may not work if Docker is configured with < 4 GB RAM.
Aborted!Option A: Increase Docker RAM (Recommended)
- Open Docker Desktop → Settings → Resources
- Set Memory to 4 GB or more
- Click Apply & Restart
Option B: Use non-interactive commands (Workaround)
Run the steps separately to bypass the RAM check:
tutor config save
tutor plugins enable mfe
tutor plugins enable instructor
tutor config save
tutor images build openedx-dev
tutor dev start -d
tutor dev do initOption C: Modify Tutor source (Advanced)
Since Tutor is installed in editable mode, you can disable the check:
- Edit
~/openedx-instructor/tutor/tutor/utils.py - Find the function
warn_macos_docker_memory() - Comment out the validation:python
def warn_macos_docker_memory() -> None: try: # check_macos_docker_memory() # <-- Comment this line pass except exceptions.TutorError as e: # ... rest of the function
Error: "AmbiguousPluginError" after git pull
Error message:
xblock.plugin.AmbiguousPluginErrorCause: The Open edX package was renamed from Open_edX to openedx-platform.
Solution:
docker exec tutor_dev-lms-1 pip uninstall --yes Open_edX
docker exec tutor_dev-lms-1 rm -rf /openedx/edx-platform/Open_edX.egg-info
docker exec tutor_dev-lms-1 pip install -e /openedx/edx-platform
tutor dev restart lms cmsMySQL authentication error after init
Error message:
django.db.utils.OperationalError: (1045, "Access denied for user 'openedx'@'...' (using password: YES)")Solution: Stop and restart all services:
tutor dev stop
tutor dev start -dWait a few seconds for MySQL to fully initialize.
Instructor MFE shows blank page or CORS errors
Symptoms: Browser console shows CORS or CSRF errors when accessing apps.local.openedx.io:2003.
Checklist:
- Verify the
instructorplugin is enabled:bashtutor plugins list | grep instructor - Verify the plugin was applied to the running config:bash
tutor config printvalue LMS_HOST # Should return local.openedx.io - Rebuild the config and restart:bash
tutor config save tutor dev restart lms cms - Verify
INSTRUCTOR_MICROFRONTEND_URLis indevstack.py:bashgrep INSTRUCTOR_MICROFRONTEND_URL ~/openedx-instructor/openedx-platform/lms/envs/devstack.py
Instructor tab not visible in LMS
Symptom: The Instructor tab on the course page doesn't appear or doesn't redirect to the MFE.
Checklist:
- You must be logged in as a staff or superuser in a course where you have instructor access.
- The MFE must be running (
npm run devin a terminal). - Verify
INSTRUCTOR_MICROFRONTEND_URLis set indevstack.py(see above). - Verify
apps.local.openedx.ioresolves in/etc/hosts.
Port already in use
Error: Bind for 0.0.0.0:8000 failed: port is already allocated
Solution:
- Check what's using the port:
lsof -i :8000 - Stop any other running Tutor instance:bash
tutor dev stop tutor local stop
Useful Commands
Backend Operations
# Start backend (background)
tutor dev start -d
# Stop backend
tutor dev stop
# Restart backend
tutor dev restart
# Restart specific services
tutor dev restart lms cms
# View logs (all services)
tutor dev logs -f
# View logs (specific service)
tutor dev logs -f lmsMFE Operations
# Start Instructor MFE
cd ~/openedx-instructor/frontend-app-instruct
npm run dev
# Build for production (if needed)
npm run buildDevelopment Commands
# Run bash in LMS container
tutor dev run lms bash
# Run Django shell
tutor dev run lms ./manage.py lms shell
# Run a Django management command
tutor dev run lms ./manage.py lms <command>Configuration
# Check current TUTOR_ROOT
tutor config printroot
# Check plugins directory
tutor plugins printroot
# List enabled plugins
tutor plugins list
# List mounts
tutor mounts listUninstallation
Remove this instance
export TUTOR_ROOT=~/openedx-instructor
# Stop and remove containers
tutor dev dc down --remove-orphans
# Remove all data, config, and source code
rm -rf ~/openedx-instructorRemove the instructor plugin (if no longer needed)
PLUGINS_DIR=$(tutor plugins printroot)
rm "$PLUGINS_DIR/instructor.py"Post-Installation Summary Template
For LLM assistants: After completing the installation, copy and fill in this template to provide the user with all necessary information:
## Installation Complete
Your Open edX Instructor development environment is now running.
### Access URLs
| Service | URL | Description |
|---------|-----|-------------|
| **LMS** | http://local.openedx.io:8000 | Main learning platform |
| **Studio** | http://studio.local.openedx.io:8001 | Course authoring tool |
| **Django Admin** | http://local.openedx.io:8000/admin | Backend administration |
| **Instructor MFE** | http://apps.local.openedx.io:2003 | Instructor Dashboard |
### User Credentials
#### Administrator
| Field | Value |
|-------|-------|
| Username | admin |
| Password | admin123 |
| Email | admin@example.com |
| Access | LMS, Studio, Django Admin, Instructor MFE |
#### Student
| Field | Value |
|-------|-------|
| Username | student |
| Password | student123 |
| Email | student@example.com |
| Access | LMS only |
### Managing the Platform
#### Start the backend
\`\`\`bash
source ~/openedx-instructor/.venv/bin/activate
export TUTOR_ROOT=~/openedx-instructor
tutor dev start -d
\`\`\`
#### Start the Instructor MFE (separate terminal)
\`\`\`bash
cd ~/openedx-instructor/frontend-app-instruct
npm run dev
\`\`\`
#### Stop the backend
\`\`\`bash
source ~/openedx-instructor/.venv/bin/activate
export TUTOR_ROOT=~/openedx-instructor
tutor dev stop
\`\`\`
### Accessing the Instructor Dashboard
1. Log in as admin at http://local.openedx.io:8000/login
2. Create or enroll in a course via Studio
3. Navigate to the Instructor tab in the course, or go directly to:
`http://apps.local.openedx.io:2003/instructor/{COURSE_ID}/open_responses`
### Development Workflow
1. **Backend changes:** Edit files in `~/openedx-instructor/openedx-platform/` — Python changes auto-reload
2. **MFE changes:** Edit files in `~/openedx-instructor/frontend-app-instruct/` — Vite hot-reload applies automatically
3. Check backend logs if needed: `tutor dev logs -f lms`