Adds a Frappe LMS (Frappe Learning) template, following the proven erpnext-v16 blueprint pattern: configurator + create-site one-shots, gunicorn backend, nginx frontend (port 8080), 3 queue workers, scheduler, socketio websocket, MariaDB 11.8 and 3x Redis.
Image choice (important context)
The upstream images at ghcr.io/frappe/lms are currently in a rough state:
Tags v2.52.1 and newer (including stable/main) are published without any apps baked in — they contain only the bare Frappe framework, so --install-app lms cannot work with them (upstream CI regression after their switch to the new frappe_docker layout).
Tags v2.52.0 and older ship frappe + lms, but not the payments app, even though lms/hooks.py hard-requires frappe/payments at install time (ModuleNotFoundError: No module named 'payments', verified empirically).
This template therefore pins ghcr.io/frappe/lms:v2.52.0 (frappe 15.104.0 + lms 2.52.0, the newest usable image) and applies two small adjustments in the create-site one-shot:
Clears required_apps in lms/hooks.py (install-time only, inside the one-shot container) so bench new-site --install-app lms succeeds without the missing payments app. Paid-course checkout is unavailable; courses, batches, quizzes and certifications work normally (documented in instructions.md).
Runs bench clear-cache after install and touches a .create-site-done marker; the backend waits for that marker before starting gunicorn. Without this, requests served during the 3-6 minute first-boot install permanently poison gunicorn workers' in-process caches (AppNotInstalledError: App frappe is not installed).
Test evidence (deployed on demo instance)
Deploy: done; all long-running services running, one-shots exited cleanly
During first boot: clean nginx 502 (no half-installed responses), then:
GET / → 200<title>Login</title> (Frappe login)
GET /lms → 200 (LMS SPA, lms/frontend/assets/...)
GET /api/method/ping → {"message":"pong"} (stable across workers)
POST /api/method/login as Administrator + generated ADMIN_PASSWORD → {"message":"Logged In","home_page":"/lms"}
Installed apps on site: frappe 15.104.0, lms 2.52.0
Redeploy with existing volumes: create-site exits 0 via the "already exists" path
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
## 📋 Pull Request Information
**Original PR:** https://github.com/Dokploy/templates/pull/1025
**Author:** [@Siumauricio](https://github.com/Siumauricio)
**Created:** 7/14/2026
**Status:** ✅ Merged
**Merged:** 7/14/2026
**Merged by:** [@Siumauricio](https://github.com/Siumauricio)
**Base:** `canary` ← **Head:** `feat/frappe-lms`
---
### 📝 Commits (1)
- [`8c15db8`](https://github.com/Dokploy/templates/commit/8c15db8a2cfaadda64db6cc65ecaef01fc6568a9) feat: add Frappe LMS template
### 📊 Changes
**5 files changed** (+379 additions, -0 deletions)
<details>
<summary>View changed files</summary>
➕ `blueprints/frappe-lms/docker-compose.yml` (+313 -0)
➕ `blueprints/frappe-lms/instructions.md` (+17 -0)
➕ `blueprints/frappe-lms/lms-logo.png` (+0 -0)
➕ `blueprints/frappe-lms/meta.json` (+19 -0)
➕ `blueprints/frappe-lms/template.toml` (+30 -0)
</details>
### 📄 Description
## Summary
Adds a **Frappe LMS (Frappe Learning)** template, following the proven `erpnext-v16` blueprint pattern: `configurator` + `create-site` one-shots, gunicorn backend, nginx frontend (port 8080), 3 queue workers, scheduler, socketio websocket, MariaDB 11.8 and 3x Redis.
## Image choice (important context)
The upstream images at `ghcr.io/frappe/lms` are currently in a rough state:
- Tags `v2.52.1` and newer (including `stable`/`main`) are published **without any apps baked in** — they contain only the bare Frappe framework, so `--install-app lms` cannot work with them (upstream CI regression after their switch to the new frappe_docker layout).
- Tags `v2.52.0` and older ship `frappe` + `lms`, but **not** the `payments` app, even though `lms/hooks.py` hard-requires `frappe/payments` at install time (`ModuleNotFoundError: No module named 'payments'`, verified empirically).
This template therefore pins **`ghcr.io/frappe/lms:v2.52.0`** (frappe 15.104.0 + lms 2.52.0, the newest usable image) and applies two small adjustments in the `create-site` one-shot:
1. Clears `required_apps` in `lms/hooks.py` (install-time only, inside the one-shot container) so `bench new-site --install-app lms` succeeds without the missing `payments` app. Paid-course checkout is unavailable; courses, batches, quizzes and certifications work normally (documented in `instructions.md`).
2. Runs `bench clear-cache` after install and touches a `.create-site-done` marker; the backend waits for that marker before starting gunicorn. Without this, requests served during the 3-6 minute first-boot install permanently poison gunicorn workers' in-process caches (`AppNotInstalledError: App frappe is not installed`).
## Test evidence (deployed on demo instance)
- Deploy: `done`; all long-running services `running`, one-shots exited cleanly
- During first boot: clean nginx `502` (no half-installed responses), then:
- `GET /` → **200** `<title>Login</title>` (Frappe login)
- `GET /lms` → **200** (LMS SPA, `lms/frontend/assets/...`)
- `GET /api/method/ping` → `{"message":"pong"}` (stable across workers)
- `POST /api/method/login` as `Administrator` + generated `ADMIN_PASSWORD` → `{"message":"Logged In","home_page":"/lms"}`
- Installed apps on site: `frappe 15.104.0`, `lms 2.52.0`
- Redeploy with existing volumes: `create-site` exits 0 via the "already exists" path
- `node build-scripts/generate-meta.js --check` → 477 templates validated
Closes #517
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/Dokploy/templates/pull/1025
Author: @Siumauricio
Created: 7/14/2026
Status: ✅ Merged
Merged: 7/14/2026
Merged by: @Siumauricio
Base:
canary← Head:feat/frappe-lms📝 Commits (1)
8c15db8feat: add Frappe LMS template📊 Changes
5 files changed (+379 additions, -0 deletions)
View changed files
➕
blueprints/frappe-lms/docker-compose.yml(+313 -0)➕
blueprints/frappe-lms/instructions.md(+17 -0)➕
blueprints/frappe-lms/lms-logo.png(+0 -0)➕
blueprints/frappe-lms/meta.json(+19 -0)➕
blueprints/frappe-lms/template.toml(+30 -0)📄 Description
Summary
Adds a Frappe LMS (Frappe Learning) template, following the proven
erpnext-v16blueprint pattern:configurator+create-siteone-shots, gunicorn backend, nginx frontend (port 8080), 3 queue workers, scheduler, socketio websocket, MariaDB 11.8 and 3x Redis.Image choice (important context)
The upstream images at
ghcr.io/frappe/lmsare currently in a rough state:v2.52.1and newer (includingstable/main) are published without any apps baked in — they contain only the bare Frappe framework, so--install-app lmscannot work with them (upstream CI regression after their switch to the new frappe_docker layout).v2.52.0and older shipfrappe+lms, but not thepaymentsapp, even thoughlms/hooks.pyhard-requiresfrappe/paymentsat install time (ModuleNotFoundError: No module named 'payments', verified empirically).This template therefore pins
ghcr.io/frappe/lms:v2.52.0(frappe 15.104.0 + lms 2.52.0, the newest usable image) and applies two small adjustments in thecreate-siteone-shot:required_appsinlms/hooks.py(install-time only, inside the one-shot container) sobench new-site --install-app lmssucceeds without the missingpaymentsapp. Paid-course checkout is unavailable; courses, batches, quizzes and certifications work normally (documented ininstructions.md).bench clear-cacheafter install and touches a.create-site-donemarker; the backend waits for that marker before starting gunicorn. Without this, requests served during the 3-6 minute first-boot install permanently poison gunicorn workers' in-process caches (AppNotInstalledError: App frappe is not installed).Test evidence (deployed on demo instance)
done; all long-running servicesrunning, one-shots exited cleanly502(no half-installed responses), then:GET /→ 200<title>Login</title>(Frappe login)GET /lms→ 200 (LMS SPA,lms/frontend/assets/...)GET /api/method/ping→{"message":"pong"}(stable across workers)POST /api/method/loginasAdministrator+ generatedADMIN_PASSWORD→{"message":"Logged In","home_page":"/lms"}frappe 15.104.0,lms 2.52.0create-siteexits 0 via the "already exists" pathnode build-scripts/generate-meta.js --check→ 477 templates validatedCloses #517
🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.