Skip to content

Open edX Development Environment Installation with Tutor

Not sure where to start? Read getting-started.md first 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 using Tutor. The dev environment allows you to modify the Open edX source code and see changes in real-time.

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:

  1. All access URLs (LMS, Studio, Django Admin)
  2. Admin credentials (username and password)
  3. Student credentials (username and password)
  4. Instructions on how to start/stop the platform

See the Post-Installation Summary Template section for the exact format to use.


Table of Contents


Dev vs Local: When to Use Each

AspectDev ModeLocal Mode
PurposeModify Open edX source codeRun Open edX without code changes
Hot-reloadYes (changes reflect automatically)No
Ports8000 (LMS), 8001 (CMS)80/443
Docker imageopenedx-dev (includes debug tools)openedx
Code mountingYes (local edx-platform)No
Use caseContributing to Open edX, developing featuresTesting, demos, production-like environment

Use this guide (Dev) if you want to:

  • Modify Open edX Python/Django code
  • Develop new features or fix bugs
  • Contribute to the Open edX project
  • Debug with tools like ipython, ipdb

Use the Local guide if you want to:

  • Run Open edX without modifying code
  • Test courses and content
  • Deploy a production-like instance

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
  • Git

Hardware Requirements

ResourceMinimumRecommended
RAM4 GB8 GB
CPU24
Disk8 GB25 GB
  • Ports 8000 and 8001 must be available

Docker Desktop RAM Configuration (Important)

Before installing, ensure Docker has enough RAM allocated:

  1. Open Docker Desktop
  2. Go to Settings (gear icon)
  3. Navigate to Resources
  4. Set Memory to at least 4 GB (recommended: 6 GB)
  5. 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:

bash
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:

bash
grep openedx /etc/hosts

Expected output:

127.0.0.1 local.openedx.io studio.local.openedx.io apps.local.openedx.io meilisearch.local.openedx.io

Note: Without this configuration, the URLs won't resolve and you won't be able to access the platform.


Understanding TUTOR_ROOT

What is TUTOR_ROOT?

TUTOR_ROOT is the directory where Tutor stores all its configuration and data. It's essentially the "home" of a Tutor installation.

TUTOR_ROOT/
├── config.yml      # Main configuration (hostnames, passwords, plugins)
├── data/           # Persistent data (MySQL, MongoDB, uploaded files)
│   ├── mysql/
│   ├── mongodb/
│   ├── redis/
│   ├── lms/
│   ├── cms/
│   └── ...
└── env/            # Generated environment files

Default Locations

OSDefault TUTOR_ROOT
Linux~/.local/share/tutor
macOS~/Library/Application Support/tutor
Windows (WSL)~/.local/share/tutor

Why is this important?

  • 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
  • You can have both dev and local instances without conflicts

Installation Steps

Step 1: Create Project Directory

bash
mkdir -p ~/openedx-dev
cd ~/openedx-dev

Step 2: Clone Required Repositories

bash
# Clone the Open edX platform (official repository)
git clone https://github.com/openedx/openedx-platform.git

# Clone Tutor (for editable installation)
git clone https://github.com/overhangio/tutor.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 the master branch for production-like stability. Check the latest release at https://github.com/overhangio/tutor/releases

Step 3: Select Branch

bash
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

bash
python3 -m venv .venv
source .venv/bin/activate

Step 5: Install Tutor in Editable Mode

Installing Tutor in editable mode allows you to modify Tutor itself if needed (useful for workarounds).

bash
pip install -U pip
pip install -e "./tutor[full]"

Step 6: Set TUTOR_ROOT (Important for Isolation)

bash
export TUTOR_ROOT=~/openedx-dev

Step 7: Mount the edx-platform Repository

bash
tutor mounts add ~/openedx-dev/openedx-platform

Verify the mount:

bash
tutor mounts list

Expected output:

- name: /Users/youruser/openedx-dev/openedx-platform
  build_mounts:
  - image: openedx
    context: edx-platform
  - image: openedx-dev
    context: edx-platform
  compose_mounts:
  - service: openedx
    container_path: /openedx/edx-platform

Step 8: Build the Development Image

bash
tutor images build openedx-dev

This builds a Docker image with debugging tools (ipython, ipdb, etc.).

Step 9: Enable Plugins

bash
tutor plugins enable mfe
tutor config save

Step 10: Launch the Development Environment

bash
tutor dev launch

This command will:

  1. Stop any existing locally-running Tutor containers
  2. Configure the platform for development
  3. Disable HTTPS
  4. Start all services in development mode
  5. Run database migrations

Step 11: Access the Platform

ServiceURL
LMShttp://local.openedx.io:8000
Studiohttp://studio.local.openedx.io:8001
Django Adminhttp://local.openedx.io:8000/admin

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

bash
# Create project directory
mkdir -p ~/openedx-dev
cd ~/openedx-dev

# Clone repositories
git clone https://github.com/openedx/openedx-platform.git
git clone https://github.com/overhangio/tutor.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-dev

Step 2: Mount repository and configure

bash
# Mount edx-platform
tutor mounts add ~/openedx-dev/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 Dev"

Step 3: Enable plugins and build image

bash
tutor plugins enable mfe
tutor config save
tutor images build openedx-dev

Step 4: Start containers

bash
tutor dev start -d

Step 5: Initialize the platform

This step creates databases, runs migrations, and sets up the platform. It may take several minutes.

bash
tutor dev do init

Step 6: Verify installation

bash
# Check all containers are running
docker ps --format "table {{.Names}}\t{{.Status}}" | grep tutor_dev

Expected 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 minutes
...

Step 7: Verify URLs are accessible

bash
# 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:8001

Expected output: 200 or 302 (redirect to login).

If you get 000 or connection errors:

  1. Verify /etc/hosts is configured correctly
  2. Check container logs: tutor dev logs -f lms
  3. Try restarting: tutor dev stop && tutor dev start -d

Creating Users

After installation, you need to create users to access the platform.

Create an Admin User (Staff/Superuser)

bash
tutor dev do createuser --staff --superuser --password admin123 admin admin@example.com

Admin credentials:

  • Username: admin
  • Email: admin@example.com
  • Password: admin123
  • Permissions: Staff + Superuser (full admin access)

Create a Student User

bash
tutor dev do createuser --password student123 student student@example.com

Student credentials:

  • Username: student
  • Email: student@example.com
  • Password: student123
  • Permissions: Regular user (student)

Alternative: Manual user creation

If the createuser command fails, you can create users manually:

bash
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()
"

Access URLs

User TypeLogin URL
Adminhttp://local.openedx.io:8000/admin
All Usershttp://local.openedx.io:8000/login
Studio (Admin only)http://studio.local.openedx.io:8001

Installing Without Affecting Existing Installations

If you already have a Tutor installation (dev or local) and want to install a new instance without affecting it:

1. Stop the existing instance first (to free ports)

bash
# If you have aliases configured
tutor-local local stop   # or tutor-dev dev stop

# Or manually
source ~/existing-instance/.venv/bin/activate
export TUTOR_ROOT=~/existing-instance
tutor local stop  # or tutor dev stop

2. Create a completely separate directory

bash
mkdir -p ~/openedx-dev-new
cd ~/openedx-dev-new

3. Follow the installation steps above

Use a different TUTOR_ROOT:

bash
export TUTOR_ROOT=~/openedx-dev-new

What stays isolated?

ResourceInstance 1Instance 2
ConfigurationTUTOR_ROOT_1/config.ymlTUTOR_ROOT_2/config.yml
DatabaseTUTOR_ROOT_1/data/mysql/TUTOR_ROOT_2/data/mysql/
FilesTUTOR_ROOT_1/data/TUTOR_ROOT_2/data/
Containerstutor_dev-*Different prefix if LOCAL_PROJECT_NAME differs
Source codeCan share or use different reposCan share or use different repos

Managing Multiple Instances

Add these aliases to your ~/.bashrc or ~/.zshrc:

bash
# Dev instance
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:

bash
source ~/.bashrc   # or source ~/.zshrc

Usage:

bash
tutor-dev dev start       # Start dev instance
tutor-dev dev stop        # Stop dev instance
tutor-local local start   # Start local instance

Option 2: Manual Environment Setup

Each time you want to work with a specific instance:

bash
# Activate the environment
source ~/openedx-dev/.venv/bin/activate
export TUTOR_ROOT=~/openedx-dev

# Now run tutor commands
tutor dev start

Important: Port Conflicts

Dev and local instances use different ports, but two dev instances would conflict:

ModeLMS PortCMS Port
Dev80008001
Local8080 (via Caddy)

Never run two dev instances simultaneously or you'll get port conflicts.


Troubleshooting

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!

Solutions:

  1. Open Docker Desktop → Settings → Resources
  2. Set Memory to 4 GB or more
  3. Click Apply & Restart

Option B: Use non-interactive commands (Workaround)

Run the steps separately to bypass the RAM check:

bash
tutor config save
tutor plugins enable mfe
tutor config save
tutor images build openedx-dev
tutor dev start -d
tutor dev do init

Option C: Modify Tutor source (Advanced)

Since Tutor is installed in editable mode, you can disable the check:

  1. Edit tutor/utils.py in your tutor clone
  2. Find the function warn_macos_docker_memory()
  3. 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.AmbiguousPluginError

Cause: The Open edX package was renamed from Open_edX to openedx-platform.

Solution:

bash
# Clean up old installation inside the container
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

# Restart services
tutor dev restart lms cms

Interactive prompt hangs or fails

Problem: Commands like tutor dev launch require interactive input and fail in automated environments.

Solution: Use the Non-Interactive Installation method.

Containers not starting

Check container status:

bash
docker ps -a --format "table {{.Names}}\t{{.Status}}" | grep tutor_dev

Check logs:

bash
tutor dev logs -f lms
tutor dev logs -f cms

Restart all services:

bash
tutor dev stop
tutor dev start -d

Port already in use

Error: Bind for 0.0.0.0:8000 failed: port is already allocated

Solution:

  1. Check what's using the port: lsof -i :8000
  2. Stop the conflicting service or other Tutor instances:
    bash
    tutor dev stop
    tutor local stop

MySQL authentication error after init

Error message:

django.db.utils.OperationalError: (1045, "Access denied for user 'openedx'@'...' (using password: YES)")

Cause: Sometimes the MySQL credentials aren't synced properly after the initial setup.

Solution: Stop and restart all services:

bash
tutor dev stop
tutor dev start -d

Wait a few seconds for MySQL to fully initialize, then verify with:

bash
curl -s -o /dev/null -w "%{http_code}" -H "Host: local.openedx.io" http://127.0.0.1:8000

Changes not reflecting (hot-reload not working)

Solution:

  1. Verify the mount is active:
    bash
    tutor mounts list
  2. Restart the affected service:
    bash
    tutor dev restart lms  # or cms
  3. For static files, run:
    bash
    tutor dev run lms npm run build-dev

Useful Commands

Basic Operations

bash
# Check container status
tutor dev status

# Stop the platform
tutor dev stop

# Start the platform (background)
tutor dev start -d

# Restart the platform
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 lms
tutor dev logs -f cms

Development Commands

bash
# Run bash in LMS container
tutor dev run lms bash

# Run Django shell
tutor dev run lms ./manage.py lms shell

# Run Django management command
tutor dev run lms ./manage.py lms <command>

# Run CMS commands
tutor dev run cms ./manage.py cms <command>

# Build static assets
tutor dev run lms npm run build-dev

# Run tests
tutor dev run lms pytest <path-to-tests>

Configuration

bash
# Check current TUTOR_ROOT
tutor config printroot

# View a config value
tutor config printvalue LMS_HOST

# List mounts
tutor mounts list

# List enabled plugins
tutor plugins list

# Enable a plugin
tutor plugins enable <plugin-name>
tutor config save

User Management

bash
# Create admin user
tutor dev run lms ./manage.py lms manage_user admin admin@example.com --staff --superuser

# Create regular user
tutor dev run lms ./manage.py lms manage_user student student@example.com

# Change user password
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('newpassword')
u.save()
"

Uninstallation

Remove a specific dev instance

bash
# Set the TUTOR_ROOT of the instance to remove
export TUTOR_ROOT=~/openedx-dev

# Stop and remove containers
tutor dev dc down --remove-orphans

# Remove all data and configuration
rm -rf ~/openedx-dev

Complete cleanup

bash
# Remove containers
tutor dev dc down --remove-orphans

# Remove configuration and data
rm -rf "$(tutor config printroot)"

# Deactivate virtual environment
deactivate

# Remove project directory
rm -rf ~/openedx-dev

# Remove Docker images (optional, frees disk space)
docker rmi $(docker images | grep "openedx" | awk '{print $3}')

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:

markdown
## Installation Complete

Your Open edX 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 |

### User Credentials

#### Administrator
| Field | Value |
|-------|-------|
| Username | admin |
| Password | admin123 |
| Email | admin@example.com |
| Access | LMS, Studio, Django Admin |

#### Student
| Field | Value |
|-------|-------|
| Username | student |
| Password | student123 |
| Email | student@example.com |
| Access | LMS only |

### Managing the Platform

#### Start the platform
\`\`\`bash
source ~/openedx-dev/.venv/bin/activate
export TUTOR_ROOT=~/openedx-dev
tutor dev start -d
\`\`\`

#### Stop the platform
\`\`\`bash
source ~/openedx-dev/.venv/bin/activate
export TUTOR_ROOT=~/openedx-dev
tutor dev stop
\`\`\`

#### Or use Docker Desktop
Open Docker Desktop and find the `tutor_dev` container group. Use the Play/Stop buttons to control the platform.

### Development Workflow

1. Make changes to files in `~/openedx-dev/openedx-platform/`
2. Changes to Python files auto-reload (wait a few seconds)
3. For static file changes, run: `tutor dev run lms npm run build-dev`
4. Check logs if needed: `tutor dev logs -f lms`

### Next Steps
1. Log in to Studio and create your first course
2. Test your code changes
3. Run tests with: `tutor dev run lms pytest <path>`

Note: Adjust the paths and credentials based on the actual values used during installation.


Quick Reference

Installation Checklist

  • [ ] Docker installed and running (v24.0.5+)
  • [ ] Docker has 4+ GB RAM allocated
  • [ ] Python 3.9+ installed
  • [ ] Git installed
  • [ ] Created project directory
  • [ ] Cloned openedx-platform repository
  • [ ] Cloned tutor repository
  • [ ] Selected correct branch (master or release)
  • [ ] Created Python virtual environment
  • [ ] Installed Tutor in editable mode
  • [ ] Set TUTOR_ROOT environment variable
  • [ ] Mounted edx-platform repository
  • [ ] Built openedx-dev image
  • [ ] Ran tutor dev launch or non-interactive steps
  • [ ] Created admin user
  • [ ] Created student user
  • [ ] Verified access to LMS and Studio

Default URLs (Dev Mode)

ServiceURL
LMShttp://local.openedx.io:8000
Studiohttp://studio.local.openedx.io:8001
Adminhttp://local.openedx.io:8000/admin

Sources

Schema Education — Internal Research