113 lines
5.0 KiB
YAML
113 lines
5.0 KiB
YAML
name: next-chair-infra
|
|
|
|
# Shared infrastructure for the multi-business VPS deployment: Caddy
|
|
# (reverse proxy + automatic TLS via Let's Encrypt) and one MySQL server
|
|
# shared by every business (a separate database + user per business, NOT
|
|
# one shared schema — see step 1 below).
|
|
#
|
|
# Lives in stacks/infra/, one directory per stack (each with its own
|
|
# compose.yaml) — see stacks/demo-business/, stacks/marios/ for the same
|
|
# shape per business, and stacks/manager/ for the management UI's own
|
|
# stack. Deliberately separate from docker-compose.local.yaml at the
|
|
# repo root, which is the single-business local/Docker-Desktop setup and
|
|
# stays untouched by any of this.
|
|
#
|
|
# Stack management/provisioning is handled by NextChair Manager (see
|
|
# manager/ at the repo root) — there is no separate stack-management UI
|
|
# alongside it.
|
|
#
|
|
# ── One-time setup ───────────────────────────────────────────────────────
|
|
# docker network create next-chair-edge
|
|
# cp .env.infra.example stacks/infra/.env (then fill in real values)
|
|
# docker compose -f stacks/infra/compose.yaml --env-file stacks/infra/.env up -d
|
|
#
|
|
# ── Per business ──────────────────────────────────────────────────────
|
|
# Use the management UI (manager/) once it's running — it automates all
|
|
# of the steps below. To do it by hand instead:
|
|
# 1. Create that business's database + user on the shared MySQL server.
|
|
# There's no automatic way to do this per business via env vars —
|
|
# the mysql:8.0 image's MYSQL_DATABASE/USER/PASSWORD vars only
|
|
# provision ONE database at first boot, and /docker-entrypoint-
|
|
# initdb.d scripts only ever run once against an empty data
|
|
# directory — so this one step is manual, run once per business:
|
|
# docker exec -it next-chair-mysql mysql -uroot -p
|
|
# CREATE DATABASE demo_business CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
|
# CREATE USER 'demo_business'@'%' IDENTIFIED BY 'choose-a-strong-password';
|
|
# GRANT ALL PRIVILEGES ON demo_business.* TO 'demo_business'@'%';
|
|
# FLUSH PRIVILEGES;
|
|
# 2. Copy .env.business.example to stacks/<slug>/.env, fill it in with
|
|
# the credentials just created and that business's domain.
|
|
# 3. Add stacks/infra/sites/<slug>.caddy (see that directory's own
|
|
# note) and reload Caddy:
|
|
# docker exec next-chair-caddy caddy reload --config /etc/caddy/Caddyfile
|
|
# 4. docker compose -f stacks/<slug>/compose.yaml --env-file stacks/<slug>/.env up -d
|
|
|
|
services:
|
|
caddy:
|
|
image: caddy:2-alpine
|
|
container_name: next-chair-caddy
|
|
restart: unless-stopped
|
|
env_file:
|
|
- .env
|
|
ports:
|
|
# Overridable for local testing (a machine already running
|
|
# something else on 80/443) — a real deployment leaves these at
|
|
# their defaults, since Let's Encrypt's HTTP challenge and normal
|
|
# HTTPS traffic both expect the standard ports.
|
|
- "${CADDY_HTTP_PORT:-80}:80"
|
|
- "${CADDY_HTTPS_PORT:-443}:443"
|
|
volumes:
|
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
|
# One .caddy file per business, imported by the Caddyfile — see
|
|
# sites/.gitkeep's own note. Adding/removing a file here needs a
|
|
# `caddy reload` (see the per-business setup steps above) to take
|
|
# effect; Caddy doesn't watch this directory on its own.
|
|
- ./sites:/etc/caddy/sites
|
|
# Caddy's own automatic-HTTPS certificate storage — must persist
|
|
# across restarts or every restart re-issues every certificate
|
|
# against Let's Encrypt's rate limits.
|
|
- next-chair-caddy-data:/data
|
|
- next-chair-caddy-config:/config
|
|
networks:
|
|
- next-chair-edge
|
|
|
|
next-chair-mysql:
|
|
image: mysql:8.0
|
|
container_name: next-chair-mysql
|
|
restart: unless-stopped
|
|
env_file:
|
|
- .env
|
|
# No MYSQL_DATABASE/MYSQL_USER/MYSQL_PASSWORD here deliberately — this
|
|
# server hosts one database per business (see step 1 above), not one
|
|
# shared schema. Only MYSQL_ROOT_PASSWORD (in .env) is required for
|
|
# the image to boot.
|
|
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_0900_ai_ci
|
|
ports:
|
|
# Host-machine access (e.g. a GUI client over an SSH tunnel) — every
|
|
# business's app container reaches this over the shared Docker
|
|
# network via the service name `next-chair-mysql`, never this.
|
|
- "${MYSQL_HOST_PORT:-3306}:3306"
|
|
volumes:
|
|
- next-chair-mysql-data:/var/lib/mysql
|
|
healthcheck:
|
|
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-change-me-too}"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 20
|
|
start_period: 10s
|
|
networks:
|
|
- next-chair-edge
|
|
|
|
volumes:
|
|
next-chair-mysql-data:
|
|
name: next-chair-mysql-data
|
|
next-chair-caddy-data:
|
|
name: next-chair-caddy-data
|
|
next-chair-caddy-config:
|
|
name: next-chair-caddy-config
|
|
|
|
networks:
|
|
next-chair-edge:
|
|
name: next-chair-edge
|
|
external: true
|