Version: 1.2.0
Status: Active
The single source of truth for production infrastructure: a reproducible, secure, automated Docker Compose platform that hosts multiple independently-owned applications on a single Ubuntu server, with Git as the only place infrastructure is ever defined.
Build a reproducible, secure, automated, and maintainable production platform that can host multiple applications using Docker while keeping infrastructure simple, predictable, and fully documented — recreatable from scratch using only this repository, application repositories, backups, and deployment pipelines.
Full vision and non-goals: ARCH-001 — Platform Vision.
- Provide a consistent production runtime for every application.
- Standardize deployment so onboarding a new application is mechanical, not bespoke.
- Eliminate manual deployment and eliminate application source code from production servers.
- Make disaster recovery predictable and rehearsed, not improvised.
- Keep documentation as the single source of architectural truth — implementation follows documentation, never the other way around.
flowchart TB
Dev["Developer"]
subgraph GitHub["GitHub"]
PlatformRepo["platform-production\n(this repository)"]
AppRepo["Application Repositories\n(one per app)"]
Actions["GitHub Actions"]
end
GHCR["GitHub Container Registry"]
subgraph Prod["Production Server (Ubuntu 24.04 LTS, Docker Runtime Only)"]
Traefik["Traefik\n(sole public entrypoint)"]
Platform["Platform Services\n(Beszel, Uptime Kuma, Backup)"]
Apps["Business Applications"]
end
Client["Client / Browser"]
Dev -->|"push"| AppRepo
Dev -->|"push"| PlatformRepo
AppRepo --> Actions
PlatformRepo --> Actions
Actions -->|"build, tag: commit SHA, push"| GHCR
Actions -->|"SSH: manifest sync + compose pull/up + health"| Prod
Actions -->|"SSH: staged infrastructure sync + compose apply"| Prod
GHCR -->|"pull only"| Prod
Client -->|"443 / 80"| Traefik
Traefik --> Apps
Traefik --> Platform
This is the platform's system context: developers push to Git, GitHub Actions builds and pushes immutable, commit-SHA-tagged application images to GHCR, and separately syncs and applies platform-service configuration directly from platform-production — the production server only ever pulls and runs, it never builds, never clones source, and is reachable only through Traefik. Full architecture: ARCH-002 — Platform Architecture. Full platform-service deployment rationale: ADR-0011.
- Production never stores application source code, and never builds applications or clones Git repositories.
- Production only holds
compose.yaml,.env, persistent data, Docker volumes, Docker images, and running containers. - GitHub is the only source of truth; production only ever receives deployments.
- Every application has its own repository; infrastructure and application code never mix.
- Every image is tagged with its Git commit SHA —
latestis never used.
See ARCH-001, ADR-0001 through ADR-0005, and ADR-0011 for the full reasoning behind each rule.
platform-production/
├── docs/ # Architecture, decisions, standards, operations, roadmap
│ ├── 00-templates/
│ ├── 01-architecture/
│ ├── 02-decisions/
│ ├── 03-standards/
│ ├── 04-operations/
│ └── 05-roadmap/
├── infrastructure/ # Deployable platform-service configuration
│ ├── automation/
│ ├── backup/
│ ├── compose/
│ ├── monitoring/
│ ├── networks/
│ └── traefik/
├── templates/ # Application onboarding scaffolding
│ ├── backend/
│ ├── frontend/
│ ├── telegram-bot/
│ └── worker/
├── .github/workflows/ # Validation, plus this repository's platform-service deploy pipeline
├── README.md
├── LICENSE
├── CHANGELOG.md
└── VERSION
Full rationale and rules for this layout: ARCH-003 — Directory Structure.
| Layer | Component |
|---|---|
| Operating System | Ubuntu 24.04 LTS |
| Container Runtime | Docker Engine, containerd, Docker Compose Plugin |
| Reverse Proxy / TLS | Traefik |
| CI/CD | GitHub Actions |
| Image Registry | GitHub Container Registry (GHCR) |
| Resource Monitoring | Beszel |
| Uptime Monitoring | Uptime Kuma |
| Logging | Docker json-file with rotation |
| Backup | Scheduled, encrypted, offsite |
Explicitly not part of the stack: Kubernetes, Docker Swarm, Portainer. See ADR-0001 — Runtime Only for why.
Provisioning a new production server:
trusted workstation/provider console
↓ transfer bootstrap.sh, install-rclone.sh, platform-doctor.sh, keys
fresh VPS: bootstrap.sh provision --hostname ... --admin-key ... --deploy-key ...
↓ platform-doctor host; verify new admin/deploy SSH sessions
fresh VPS: bootstrap.sh harden
↓ configure PROD_* secrets and runtime files
GitHub Actions: Deploy Platform (networks first, dependents after)
The server never needs a permanent clone of platform-production; GitHub
Actions synchronizes platform configuration into /srv/platform. Populate
runtime files on the server out of band (never committed to Git):
cd /srv/platform/traefik && cp .env.example .env # then edit it
cd /srv/platform/monitoring && cp .env.example .env # then edit it
Add PROD_HOST, PROD_DEPLOY_USER, PROD_DEPLOY_KEY, and verified
PROD_KNOWN_HOSTS as encrypted secrets on the platform-production repository,
then push to main (or run the Deploy Platform workflow manually) to bring
up platform components — see ADR-0011
and OPS-011 — Deploy Platform Service.
docker compose up -d run by hand on the server remains only the documented
emergency fallback.
Then continue with the full procedure: OPS-001 — Server Provisioning.
Onboarding a new application:
- Copy the relevant directory from
templates/(backend/,frontend/,telegram-bot/, orworker/) into a new application repository, then set the language-specific images and commands in its committedbuild.env. - Follow OPS-002, Section 3.2 — Onboarding a New Application.
Deploying an application change: merge to the application's deploy branch. GitHub Actions handles the rest — see ARCH-005 — Deployment Strategy.
Deploying a platform-service change (Traefik, monitoring, backup, networks): merge a change under infrastructure/<component>/ to this repository's main. GitHub Actions deploys only the component(s) that changed — see ARCH-005, Section 11 and OPS-011.
The full documentation set lives in docs/, organized as:
| Category | Contents |
|---|---|
| 01-architecture/ | What the platform is and why it is shaped this way (ARCH-001–ARCH-010) |
| 02-decisions/ | Architecture Decision Records — the specific choices behind the architecture (ADR-0001–ADR-0011) |
| 03-standards/ | Enforceable, checkable engineering standards (STD-001–STD-011) |
| 04-operations/ | Step-by-step operational runbooks (OPS-001–OPS-011) |
| 05-roadmap/ | Shipped scope, planned scope, and known gaps |
Start with ARCH-001 — Platform Vision and ARCH-002 — Platform Architecture for the complete picture.
- Every infrastructure or documentation change is proposed via pull request — nothing is edited directly on the production server, per ADR-0002 — Git Source of Truth.
- A change that introduces a new technology choice or reverses an existing one requires a new ADR in
docs/02-decisions/, using adr-template.md, before implementation begins. - A change to
infrastructure/ortemplates/must comply with every applicable standard indocs/03-standards/; review against STD-001, STD-007, and STD-010 at minimum. - New documents are created from the templates in
docs/00-templates/, not written ad hoc, and follow the ID scheme in STD-002, Section 3.8. - This repository's own
.github/workflows/validate documentation links and Compose file syntax on every pull request, and deployinfrastructure/platform-service changes to production on every push tomain— see STD-011.
- ROADMAP v1 — current shipped scope (this version,
1.2.0). - ROADMAP v2 — planned next-scope candidates and their triggers (staging environment, multi-server scaling, HA Traefik, and more).
- Technical Debt — tracked gaps between documentation and implementation.