LessonCraft is a web-based e-learning environment built to provide a simple and straightforward way to build and experience e-learning lessons that utilize a customized markdown syntax alongside interactive, live environments dynamically created using Docker containers and clusters.
LessonCraft enables educators to:
- Create Interactive Lessons: Build lessons using a specialized Markdown format with code blocks for commands, expected outputs, and questions.
- Provide Live Environments: Give learners access to real Docker environments where they can execute commands and see results in real-time.
- Validate Learning: Automatically validate learner progress by comparing command outputs with expected results.
A live deployment of LessonCraft is coming soon. Stay tuned for updates!
- Docker
18.06.0+ - Go
1.24.0+(stable release) - MongoDB (for lesson storage)
-
Clone the repository:
git clone https://github.com/ringo380/lessoncraft cd lessoncraft -
Verify Docker is installed and running:
docker run hello-world
-
Load the IPVS kernel module (required for Docker swarm functionality):
sudo modprobe xt_ipvs
-
Initialize Docker swarm mode:
docker swarm init
-
Pull the required Docker image:
docker pull franela/dind
-
Configure environment variables (optional):
# Copy the sample environment file cp .env.sample .env # Edit the .env file to customize your configuration nano .env
-
Prepare Go modules:
go mod tidy go mod vendor # Optional: pre-fetch dependencies -
Start LessonCraft:
docker-compose up
-
Access the application: Navigate to http://localhost and click "Start" to begin a new LessonCraft session, followed by "ADD NEW INSTANCE" to launch a new terminal instance.
LessonCraft can be configured using environment variables. A sample configuration file (.env.sample) is provided as a starting point.
HOST_PORT: The port to expose on the host (default: 80)
HAPROXY_CONTAINER_NAME: Name for the HAProxy container (default: haproxy)LESSONCRAFT_CONTAINER_NAME: Name for the main application container (default: lessoncraft)L2_CONTAINER_NAME: Name for the L2 networking container (default: l2)MONGODB_CONTAINER_NAME: Name for the MongoDB container (default: mongodb)
MONGODB_URI: MongoDB connection string (default: mongodb://mongodb:27017)MONGODB_DATABASE: MongoDB database name (default: lessoncraft)
LESSONCRAFT_UNSAFE: Enable unsafe mode (default: false)PLAYGROUND_DOMAIN: Domain for the playground (default: localhost)DEFAULT_DIND_IMAGE: Default Docker-in-Docker image (default: franela/dind)AVAILABLE_DIND_IMAGES: Available Docker-in-Docker images (default: franela/dind)ALLOW_WINDOWS_INSTANCES: Allow Windows instances (default: false)DEFAULT_SESSION_DURATION: Default session duration (default: 4h)MAX_LOAD_AVG: Maximum allowed load average (default: 100)
APPARMOR_PROFILE: AppArmor profile for containers (default: docker-dind)DOCKER_CONTENT_TRUST: Enable Docker content trust (default: 1)COOKIE_HASH_KEY: Hash key for secure cookiesCOOKIE_BLOCK_KEY: Block key for secure cookiesADMIN_TOKEN: Token for admin endpoints
SSH_PORT: Port for SSH access (default: 8022)DNS_PORT: Port for DNS service (default: 8053)TLS_PORT: Port for TLS connections (default: 443)
LessonCraft uses several Docker volumes for persistent data:
sessions: Stores session data for the main applicationnetworks: Stores network configuration for the L2 containerdata: Stores application data for the main applicationmongodb_data: Stores MongoDB database files
You can customize the volume names using environment variables:
SESSIONS_VOLUME: Name for the sessions volume (default: sessions)NETWORKS_VOLUME: Name for the networks volume (default: networks)DATA_VOLUME: Name for the data volume (default: data)MONGODB_DATA_VOLUME: Name for the MongoDB data volume (default: mongodb_data)
Resource limits are configured directly in the docker-compose.yml file:
- HAProxy: 256MB memory, 0.5 CPU cores
- LessonCraft: 512MB memory, 1.0 CPU cores
- L2: 512MB memory, 1.0 CPU cores
- MongoDB: 512MB memory, 0.5 CPU cores
Run all tests:
go test ./...Run tests with verbose output:
go test -v ./...Run specific tests:
go test -v ./lesson
go test -v ./api
go test -v ./api/storeIn order for port forwarding to work correctly in development you need to make *.localhost resolve to 127.0.0.1. That way when you try to access pwd10-0-0-1-8080.host1.localhost, you're forwarded correctly to your local LessonCraft server.
You can achieve this by setting up a dnsmasq server (you can run it in a docker container also) and adding the following configuration:
address=/localhost/127.0.0.1
Don't forget to change your computer's default DNS to use the dnsmasq server to resolve.
LessonCraft provides a RESTful API for managing lessons:
| Endpoint | Method | Description |
|---|---|---|
/api/lessons |
GET | List all lessons |
/api/lessons/{id} |
GET | Get a specific lesson by ID |
/api/lessons |
POST | Create a new lesson |
/api/lessons/{id} |
PUT | Update an existing lesson |
/api/lessons/{id} |
DELETE | Delete a lesson |
| Endpoint | Method | Description |
|---|---|---|
/api/lessons/{id}/start |
POST | Start a lesson |
/api/lessons/{id}/steps/{step}/complete |
POST | Complete a step in a lesson |
/api/lessons/{id}/validate |
POST | Validate a step in a lesson |
For detailed API documentation, including request and response formats, see docs/lesson_format.md.
LessonCraft uses a specialized Markdown format for creating interactive lessons. Lessons consist of:
- Title: A level 1 heading (
# Title) - Description: Text following the title
- Steps: A series of steps, each containing content, commands, expected outputs, and/or questions
LessonCraft uses specialized code blocks:
- Docker Blocks (````docker`): Define commands to execute
- Expect Blocks (````expect`): Define expected command output
- Question Blocks (````question`): Define questions for the user
For a complete guide to the lesson format, see docs/lesson_format.md.
-
Port conflicts: Ensure ports 80 and 443 are available
# Check if ports are in use sudo lsof -i :80 sudo lsof -i :443 -
Docker permissions: Make sure your user has permissions to access the Docker socket
# Add your user to the docker group sudo usermod -aG docker $USER # Then log out and back in
-
DNS resolution: For port forwarding, ensure
*.localhostresolves to127.0.0.1# Test DNS resolution ping test.localhost # Should resolve to 127.0.0.1
-
MongoDB connection: Ensure MongoDB is running and accessible
# Test MongoDB connection mongo --eval "db.version()"
No, it needs to run on those ports for DNS resolution to work. Ideas or suggestions about how to improve this are welcome.
- Copy: Ctrl + Insert
- Paste: Shift + Insert
See the docs/lesson_format.md guide and check out the example lessons in the examples/lessons directory.