Skip to content

Commit faf69d8

Browse files
committed
feat: Add Makefile, Traefik support, and direnv integration
Added: - Makefile with convenient commands: - make clone-moodle: Clone Moodle (shallow, depth=1, tip only) - make setup: Create .env file - make start: Start stack - make start-traefik: Start with Traefik integration - make logs/status/health: Monitoring commands - make clean: Cleanup commands - compose.traefik.yml: Traefik reverse proxy configuration - Disables exposed ports - Adds Traefik labels for routing - Automatic HTTPS with Let's Encrypt - HTTP to HTTPS redirect - .envrc: direnv integration for auto-loading environment - Helper function: moodle-help - Auto-loads .env when entering directory - Updated .env.example with Traefik variables: - MOODLE_DOMAIN - TRAEFIK_NETWORK - TRAEFIK_CERTRESOLVER - Updated README with: - Makefile usage (recommended quick start) - Traefik integration section - Collapsible manual setup instructions
1 parent ca19229 commit faf69d8

File tree

6 files changed

+290
-11
lines changed

6 files changed

+290
-11
lines changed

.env.example

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,22 @@ VALKEY_PORT=6379
4141
# SECURITY: Generate secure password!
4242
VALKEY_PASSWORD=CHANGE_ME_SECURE_VALKEY_PASSWORD_HERE
4343

44+
# ============================================================================
45+
# Traefik Configuration (optional - for production with Traefik)
46+
# ============================================================================
47+
# Domain for Moodle (used when starting with Traefik)
48+
MOODLE_DOMAIN=moodle.example.com
49+
50+
# Traefik network name (must exist)
51+
TRAEFIK_NETWORK=traefik
52+
53+
# TLS certificate resolver configured in Traefik
54+
TRAEFIK_CERTRESOLVER=letsencrypt
55+
4456
# ============================================================================
4557
# Notes
4658
# ============================================================================
4759
# 1. Never commit .env file to version control (add to .gitignore)
4860
# 2. Generate strong passwords: openssl rand -base64 32
4961
# 3. For production, use actual domain in MOODLE_SITE_URL
50-
# 4. Traefik labels in compose.yml are commented out by default
62+
# 4. For Traefik mode: use 'make start-traefik' or 'docker compose -f compose.yml -f compose.traefik.yml up -d'

.envrc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# direnv configuration for Moodle Docker Stack
2+
# This file is loaded automatically by direnv when you cd into this directory
3+
# Install direnv: https://direnv.net/
4+
5+
# Load .env file if it exists
6+
dotenv_if_exists .env
7+
8+
# Set compose file for Traefik mode (uncomment to enable)
9+
# export COMPOSE_FILE=compose.yml:compose.traefik.yml
10+
11+
# Helper functions
12+
function moodle-help() {
13+
echo "Moodle Docker Stack - Quick Commands:"
14+
echo ""
15+
echo " make help - Show all available commands"
16+
echo " make clone-moodle - Clone Moodle repository"
17+
echo " make setup - Create .env file"
18+
echo " make start - Start the stack"
19+
echo " make logs - View logs"
20+
echo " make status - Check container status"
21+
echo ""
22+
}
23+
24+
# Show help on first load
25+
if [ -z "$MOODLE_DIRENV_LOADED" ]; then
26+
export MOODLE_DIRENV_LOADED=1
27+
echo "✅ Moodle Docker environment loaded"
28+
echo " Run 'moodle-help' for available commands"
29+
fi

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Environment configuration (contains secrets)
22
.env
3+
.envrc.local
34

45
# Moodle code (managed via git clone separately)
56
/moodle/

Makefile

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
.PHONY: help clone-moodle setup start stop restart logs clean build traefik
2+
3+
# Default target
4+
.DEFAULT_GOAL := help
5+
6+
# Variables
7+
MOODLE_BRANCH ?= MOODLE_405_STABLE
8+
COMPOSE_FILES := -f compose.yml
9+
COMPOSE_TRAEFIK := -f compose.yml -f compose.traefik.yml
10+
11+
help: ## Show this help message
12+
@echo "Moodle Docker Stack - Available commands:"
13+
@echo ""
14+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'
15+
@echo ""
16+
@echo "Quick start:"
17+
@echo " 1. make clone-moodle # Clone Moodle code"
18+
@echo " 2. make setup # Create .env file"
19+
@echo " 3. make start # Start the stack"
20+
@echo ""
21+
22+
clone-moodle: ## Clone Moodle repository (shallow clone, tip only)
23+
@if [ -d "moodle" ]; then \
24+
echo "⚠️ Moodle directory already exists"; \
25+
read -p "Delete and re-clone? [y/N] " confirm; \
26+
if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \
27+
rm -rf moodle; \
28+
else \
29+
echo "Aborted."; \
30+
exit 1; \
31+
fi; \
32+
fi
33+
@echo "📥 Cloning Moodle $(MOODLE_BRANCH) (depth=1)..."
34+
git clone -b $(MOODLE_BRANCH) --depth 1 git://git.moodle.org/moodle.git
35+
@cd moodle && git branch
36+
@echo "✅ Moodle cloned successfully"
37+
38+
setup: ## Create .env file from template
39+
@if [ -f ".env" ]; then \
40+
echo "⚠️ .env file already exists"; \
41+
read -p "Overwrite? [y/N] " confirm; \
42+
if [ "$$confirm" != "y" ] && [ "$$confirm" != "Y" ]; then \
43+
echo "Aborted."; \
44+
exit 1; \
45+
fi; \
46+
fi
47+
cp .env.example .env
48+
@echo "⚠️ IMPORTANT: Edit .env and set secure passwords!"
49+
@echo " Required: DB_PASSWORD, DB_ROOT_PASSWORD, VALKEY_PASSWORD"
50+
51+
start: ## Start all services (pulls pre-built image)
52+
docker compose $(COMPOSE_FILES) up -d
53+
@echo ""
54+
@echo "✅ Stack started!"
55+
@echo " Moodle: http://localhost:8080"
56+
@echo ""
57+
@echo "Check status: make status"
58+
@echo "View logs: make logs"
59+
60+
start-traefik: ## Start with Traefik (no exposed ports, uses Traefik labels)
61+
docker compose $(COMPOSE_TRAEFIK) up -d
62+
@echo ""
63+
@echo "✅ Stack started with Traefik!"
64+
@echo " Access via your configured Traefik domain"
65+
@echo ""
66+
@echo "Check status: make status"
67+
68+
stop: ## Stop all services
69+
docker compose $(COMPOSE_FILES) down
70+
@echo "✅ Stack stopped"
71+
72+
restart: ## Restart all services
73+
docker compose $(COMPOSE_FILES) restart
74+
@echo "✅ Stack restarted"
75+
76+
build: ## Build Moodle image locally
77+
docker compose $(COMPOSE_FILES) build
78+
@echo "✅ Image built"
79+
80+
logs: ## Show logs from all services
81+
docker compose $(COMPOSE_FILES) logs -f
82+
83+
logs-moodle: ## Show Moodle logs only
84+
docker compose $(COMPOSE_FILES) logs -f moodle
85+
86+
logs-db: ## Show database logs only
87+
docker compose $(COMPOSE_FILES) logs -f database
88+
89+
logs-valkey: ## Show Valkey logs only
90+
docker compose $(COMPOSE_FILES) logs -f valkey
91+
92+
logs-ofelia: ## Show Ofelia cron logs only
93+
docker compose $(COMPOSE_FILES) logs -f ofelia
94+
95+
status: ## Show container status
96+
docker compose $(COMPOSE_FILES) ps
97+
98+
health: ## Check service health
99+
@echo "=== Service Health Status ==="
100+
@docker compose $(COMPOSE_FILES) ps --format "table {{.Name}}\t{{.Status}}\t{{.Health}}"
101+
102+
shell-moodle: ## Open shell in Moodle container
103+
docker compose $(COMPOSE_FILES) exec moodle bash
104+
105+
shell-db: ## Open MariaDB shell
106+
docker compose $(COMPOSE_FILES) exec database mariadb -uroot -p
107+
108+
clean: ## Stop and remove all containers, volumes, and networks
109+
@echo "⚠️ This will remove all containers, volumes, and data!"
110+
@read -p "Continue? [y/N] " confirm; \
111+
if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \
112+
docker compose $(COMPOSE_FILES) down -v; \
113+
echo "✅ Stack cleaned"; \
114+
else \
115+
echo "Aborted."; \
116+
fi
117+
118+
clean-moodle: ## Remove Moodle clone directory
119+
@echo "⚠️ This will delete the moodle/ directory!"
120+
@read -p "Continue? [y/N] " confirm; \
121+
if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \
122+
rm -rf moodle; \
123+
echo "✅ Moodle directory removed"; \
124+
else \
125+
echo "Aborted."; \
126+
fi
127+
128+
pull: ## Pull latest pre-built image from GHCR
129+
docker compose $(COMPOSE_FILES) pull moodle
130+
@echo "✅ Latest image pulled"
131+
132+
upgrade-moodle: ## Upgrade Moodle code to latest in branch
133+
@if [ ! -d "moodle" ]; then \
134+
echo "❌ Moodle directory not found. Run 'make clone-moodle' first."; \
135+
exit 1; \
136+
fi
137+
@echo "📥 Pulling latest Moodle updates..."
138+
cd moodle && git pull
139+
@echo "✅ Moodle updated"
140+
@echo "⚠️ Remember to run the Moodle upgrade: http://localhost:8080/admin"

README.md

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,39 @@ The `compose.yml` includes both `image:` and `build:` directives:
7070

7171
## Quick Start
7272

73-
### 1. Clone Moodle Repository
73+
### Using Makefile (Recommended)
7474

7575
```bash
76-
# Clone Moodle 4.5 stable branch
77-
git clone -b MOODLE_405_STABLE --depth 1 git://git.moodle.org/moodle.git
76+
# 1. Clone Moodle code
77+
make clone-moodle
7878

79-
# Verify branch
80-
cd moodle
81-
git branch
82-
# Should show: * MOODLE_405_STABLE
83-
cd ..
79+
# 2. Create .env file
80+
make setup
81+
# Edit .env and set secure passwords!
82+
83+
# 3. Start the stack
84+
make start
85+
86+
# Check status
87+
make status
88+
89+
# View all available commands
90+
make help
91+
```
92+
93+
### Manual Setup
94+
95+
<details>
96+
<summary>Click to expand manual setup instructions</summary>
97+
98+
#### 1. Clone Moodle Repository
99+
100+
```bash
101+
# Clone Moodle 4.5 stable branch (shallow clone)
102+
git clone -b MOODLE_405_STABLE --depth 1 git://git.moodle.org/moodle.git
84103
```
85104

86-
### 2. Configure Environment
105+
#### 2. Configure Environment
87106

88107
```bash
89108
# Copy environment template
@@ -104,7 +123,7 @@ nano .env
104123
- `VALKEY_PASSWORD`: Set secure password
105124
- `MOODLE_SITE_URL`: Update for production (e.g., `https://moodle.example.com`)
106125

107-
### 3. Start Services
126+
#### 3. Start Services
108127

109128
```bash
110129
# Pull pre-built image and start all services
@@ -117,6 +136,34 @@ docker compose ps
117136
docker compose logs -f moodle
118137
```
119138

139+
</details>
140+
141+
## Traefik Integration
142+
143+
For production deployments with Traefik reverse proxy:
144+
145+
```bash
146+
# 1. Configure Traefik variables in .env
147+
MOODLE_DOMAIN=moodle.example.com
148+
MOODLE_SITE_URL=https://moodle.example.com
149+
TRAEFIK_NETWORK=traefik
150+
TRAEFIK_CERTRESOLVER=letsencrypt
151+
152+
# 2. Start with Traefik
153+
make start-traefik
154+
155+
# Or manually:
156+
docker compose -f compose.yml -f compose.traefik.yml up -d
157+
```
158+
159+
**Traefik features:**
160+
- ✅ Automatic HTTPS with Let's Encrypt
161+
- ✅ No exposed ports (Traefik handles routing)
162+
- ✅ HTTP to HTTPS redirect
163+
- ✅ Custom domain support
164+
165+
## Installation
166+
120167
### 4. Install Moodle
121168

122169
**Option A: Web Installer (Recommended)**

compose.traefik.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Traefik Override Configuration
2+
# Usage: docker compose -f compose.yml -f compose.traefik.yml up -d
3+
# Or: make start-traefik
4+
5+
services:
6+
moodle:
7+
# Disable direct port exposure (Traefik handles routing)
8+
ports: []
9+
10+
# Enable Traefik labels
11+
labels:
12+
# Ofelia cron labels (keep these)
13+
ofelia.enabled: "true"
14+
ofelia.job-exec.moodle-cron.schedule: "@every 1m"
15+
ofelia.job-exec.moodle-cron.command: "php /var/www/html/admin/cli/cron.php"
16+
ofelia.job-exec.moodle-cron.user: "www-data"
17+
18+
# Traefik configuration
19+
traefik.enable: "true"
20+
21+
# HTTP router
22+
traefik.http.routers.moodle.rule: "Host(`${MOODLE_DOMAIN:-moodle.localhost}`)"
23+
traefik.http.routers.moodle.entrypoints: "websecure"
24+
traefik.http.routers.moodle.tls: "true"
25+
traefik.http.routers.moodle.tls.certresolver: "${TRAEFIK_CERTRESOLVER:-letsencrypt}"
26+
27+
# Service configuration
28+
traefik.http.services.moodle.loadbalancer.server.port: "80"
29+
30+
# Middleware (optional - uncomment if needed)
31+
# traefik.http.routers.moodle.middlewares: "moodle-headers"
32+
# traefik.http.middlewares.moodle-headers.headers.customResponseHeaders.X-Frame-Options: "SAMEORIGIN"
33+
# traefik.http.middlewares.moodle-headers.headers.customResponseHeaders.X-Content-Type-Options: "nosniff"
34+
35+
# HTTP to HTTPS redirect
36+
traefik.http.routers.moodle-http.rule: "Host(`${MOODLE_DOMAIN:-moodle.localhost}`)"
37+
traefik.http.routers.moodle-http.entrypoints: "web"
38+
traefik.http.routers.moodle-http.middlewares: "moodle-redirect"
39+
traefik.http.middlewares.moodle-redirect.redirectscheme.scheme: "https"
40+
traefik.http.middlewares.moodle-redirect.redirectscheme.permanent: "true"
41+
42+
networks:
43+
- frontend
44+
- backend
45+
- traefik # Add Traefik network
46+
47+
networks:
48+
traefik:
49+
external: true
50+
name: ${TRAEFIK_NETWORK:-traefik}

0 commit comments

Comments
 (0)