mcma-bootstrap
Interactive installer for MCMA (My Cool Music App) — a self-hosted music
service. One command asks a few questions, writes a .env.deploy and a
docker-compose.yml, pulls the images, runs database migrations, creates the
first admin, and verifies the stack is healthy.
Zero dependencies beyond bash 4+, Docker, and Docker Compose v2. No jq, no Python, no yq. Secrets are generated for you and never printed.
Quick start
make deploy
That's it. The wizard walks you through:
- Language (English / Русский)
- Which services to run (backend is required; web UI optional)
- Image tag (
latestor a pinned version) - Database — built-in Postgres or an external one
- Redis — built-in or external
- Media storage — local directory, built-in MinIO (S3), or external S3
- Network — bundled Caddy proxy (plain HTTP, or automatic HTTPS for a domain), or no bundled proxy when you publish ports / run your own
- The first administrator account
- An optional ML service URL
- Metadata enrichment — an optional AcoustID key + contact email
- YouTube Music source — enable search/download, with an optional folder for a
yt-dlp
cookies.txt(mounted into the backend for restricted items)
Then it generates the config, pulls images, migrates, seeds the admin, starts everything, and waits for the API health check before declaring success.
Commands
make deploy # run the installer (fresh install, or update/reconfigure menu)
make update # pull fresh images of the current tag, migrate, restart
make up # start the stack from the existing config
make down # stop the stack (data volumes are kept)
make logs # tail logs from all services
make status # container status + API health
make clean # stop and remove generated config (prompts before deleting data)
What gets generated
| File | Purpose | Committed? |
|---|---|---|
.env.deploy |
All settings + generated secrets (0600) | No |
docker-compose.yml |
The stack, assembled from your choices | No |
Caddyfile |
Reverse-proxy routing (if proxy enabled) | No |
All three are in .gitignore. Re-running make deploy over an existing install
offers to update images or reconfigure (backing up the old config first); it
never silently overwrites.
Architecture notes
- One backend image, two roles.
git.ollyhearn.ru/olly/mcma-backendruns the API (uvicorn, port 8000) and the background worker (arq app.workers.arq_worker.WorkerSettings) — same image, different command. - The web UI and API must be same-origin.
git.ollyhearn.ru/olly/mcma-webuiis a prebuilt static SPA, and the backend sends no CORS headers — so the UI and API have to share an origin. By default the installer puts Caddy in front as the single entrypoint, routing/api/*,/health*and/rest/*to the backend and everything else to the UI (plain HTTP on a port, or automatic HTTPS for a domain). The UI's browser-facing API base URL is set at container start fromPUBLIC_API_BASE_URL(injected intowindow.__APP_CONFIG__, no rebuild needed), defaulting to the same-origin/api/v1. If you run your own reverse proxy, pick the "no bundled proxy" option: the installer publishes the UI and API ports and lets you set that base URL. A backend-only deploy publishes the API port directly. - Startup is ordered and fails loud. Backing services come up and become
healthy → migrations run → the first admin is created → app services start →
the API
/healthendpoint is polled. The backend is never started over a database that failed to migrate.
Private registry
The images live in a private registry. If make deploy reports unauthorized
while pulling, log in first:
docker login git.ollyhearn.ru
Creating an admin later
If you skipped admin creation during setup:
docker compose --project-name mcma --env-file .env.deploy -f docker-compose.yml \
run --rm --no-deps api mcma create-admin <username>
Layout
mcma-bootstrap/
├── Makefile # thin entrypoint → deploy.sh
├── deploy.sh # wizard + lifecycle orchestrator
├── lib/ # bash modules (ui, i18n, checks, secrets, generators, lifecycle)
├── templates/
│ ├── compose/ # per-service compose fragments, glued by choice
│ └── env/env.template # base .env with @TOKEN@ placeholders
└── i18n/ # ru / en string tables