Releases: mcansem/infra
Release list
v0.9.0 — Documentation
Ninth release of the infra repository: Documentation. The last two v0.1.0 stubs, plus the roadmap's remaining items - architecture diagrams, operational runbooks, onboarding documentation.
Added
docs/architecture.md- real content replacing the v0.1.0 stub: three Mermaid diagrams (component/data-flow, externally-reachable network topology matchingscripts/harden-host.sh'srole_ports(), CI/CD sequence matchingvars/standardDeployPipeline.groovy's stage order), rendered natively by GitHubdocs/recovery.md- real content replacing the v0.1.0 stub: the authoritative host-lost runbook, consolidating what was scattered acrossbackup.md/restore.md/platforms/homelab.md, plus explicit RPO (~24h, tied to the daily backup cadence) and RTO (an honest estimate - under two hours - explicitly caveated as untested, not a real SLA)docs/runbooks.md- one playbook per Prometheus alert (HostDown,DiskSpaceLow,ContainerMissing): what it means, likely causes, concrete investigate/fix commandsdocs/onboarding.md- how a new application repo starts using this infrastructure: Jenkinsfile shape, image/port expectations, what to do if it doesn't fit the existingdocker/app/service shape, new-subdomain certificate bootstrap
Changed
docs/project-specification.md's Documentation section gainsrunbooks.md,onboarding.md
What's next
v1.0.0 - Production Ready Stable Release. Final stabilization pass - the last phase on the current roadmap.
Full changelog: CHANGELOG.md
v0.8.0 — Platform Integration
Eighth release of the infra repository: Platform Integration - multi-target deployment guidance. Documentation only, no infrastructure changes, per the phase's own stated constraint.
Added
docs/deployment.md- real content replacing the v0.1.0 stub: the general deploy flow (git pull -> docker pull -> compose up -> health check -> rollback), themanagement/app/agentrole vocabulary, links to per-provider host provisioningdocs/platforms/aws.md,google-cloud.md,oracle-cloud.md,homelab.md- each covers only what's genuinely provider-specific (getting from nothing to a reachable Ubuntu host); everything past that point is already identical across providers by design, so these docs hand off to the existingscripts/harden-host.sh <role>+docker/*/README.mdsteps rather than re-describing themdocs/platforms/oracle-cloud.mdnotes the Always Free ARM (Ampere A1) tier is viable for theapprole's own images (nginx/postgres, both confirmed multi-arch) but flags the application's own images as a separate build-time concern for that repo's own CIdocs/platforms/homelab.mdis a migration guide, not a fresh-deploy guide - walks throughscripts/backup.sh->scripts/restore.shas the actual AWS-to-self-hosted migration mechanism for Jenkins, exercising the v0.6.0 tooling end to end
Changed
docs/project-specification.md's Documentation section gainsplatforms/
What's next
v0.9.0 - Documentation (architecture diagrams, operational runbooks, onboarding documentation, plus completing architecture.md and recovery.md, the two remaining stubs from v0.1.0).
Full changelog: CHANGELOG.md
v0.7.0 — Observability
Seventh release of the infra repository: Observability - metrics, dashboards, alerting, and external availability monitoring.
Added
docker/monitoring-agent/- Node Exporter (host metrics) + cAdvisor (per-container metrics), deployed identically on every host role. Both bind to127.0.0.1only by default (neither has any authentication) - cross-host Prometheus scraping is a documented, source-IP-scoped manual opt-in, not scripteddocker/observability/- Prometheus, Alertmanager, Grafana, Uptime Kuma on themanagementhost. Prometheus/Alertmanager stay internal-only (no meaningful auth of their own); Grafana/Uptime Kuma get a public URL through the new management proxy- Prometheus joins
monitoring_agent_netto scrapenode-exporter/cadvisorby container name - their127.0.0.1-published ports aren't reachable from inside another container, so same-host scraping goes over a shared Docker network instead - Three default alert rules (host down, disk >85%, container missing) with a no-op Alertmanager receiver - wiring a real notification channel needs deployment-specific credentials that don't belong in this repo
- Grafana's Prometheus datasource is provisioned as code; dashboards are a documented two-click import (Node Exporter Full, cAdvisor) rather than vendored JSON
docker/management-proxy/- TLS termination and name-based vhost routing (jenkins.<domain>,grafana.<domain>,uptime.<domain>) for every public UI on themanagementhost, replacing the single-vhostjenkins/nginx.conf. Domain names are injected via the official nginx image'senvsubsttemplating, not hardcoded
Changed
jenkins/docker-compose.yml: thenginxservice moved out todocker/management-proxy/-jenkins/is Jenkins-only again, still not published on a host port itselfscripts/harden-host.sh:role_ports()documents why the exporter ports are deliberately not in the default UFW allowlist
Notes
- None of this has been run against a live host yet - the AWS management host was still being provisioned while this was written, so the nginx-to-management-proxy migration had no live traffic to move
What's next
v0.8.0 - Platform Integration (multi-target deployment guidance for AWS/Google Cloud/Oracle Cloud/Homelab, documentation and examples only - infrastructure code stays cloud-agnostic).
Full changelog: CHANGELOG.md
v0.6.0 — Operations
Sixth release of the infra repository: Operations - backup, restore, update, cleanup, and manual deploy tooling.
Added
scripts/backup.sh- local, verified, rotated backups per host role (pg_dump -Fcfor Postgres, volume tars forjenkins_home/portainer_data/registry_data); off-host replication is documented (docs/backup.md), not scripted, since the destination varies per deploymentscripts/restore.sh- destructive, so it's a dry run unless--yes-i-am-sureis passed; validates Postgres connectivity and table presence after a restorescripts/update.sh- on-demandapt upgrade+docker compose pull/upper role, image prune, idempotent logrotate config installscripts/cleanup.sh- periodicdocker system prune/build-cache prune, never touches volumesscripts/deploy.sh- manual/fallback counterpart tovars/standardDeployPipeline.groovy's SSH deploy stage (pull infra config -> tag rollback images -> pull -> up -> wait-for-healthy -> roll back on failure), for when Jenkins isn't the one triggering deploymentscripts/logrotate/infra-nginx.conffor the file-based nginx logs added in v0.5.0- Real content for
docs/backup.mdanddocs/restore.md(stubs since v0.1.0), including a disaster-recovery walkthrough
Fixed
- Two internal-consistency gaps caught while writing this phase:
docs/roadmap.mdstill showed v0.5.0 as "In Progress" after it had already shipped;docs/project-specification.md's Operations section was missingrestore.sh/cleanup.sh
Notes
- None of these scripts have been run against a live host yet -
restore.shanddeploy.shboth have their own built-in safety gates for that first real run (explicit confirmation flag, automatic image rollback on failed healthcheck respectively)
What's next
v0.7.0 - Observability (Uptime Kuma, Prometheus, Grafana, Node Exporter, cAdvisor, alerting, monitoring dashboards).
Full changelog: CHANGELOG.md
v0.5.0 — Production Hardening
Fifth release of the infra repository: Production Hardening, end to end - container-level, documentation, and host-level.
Added
docs/roadmap.md- single source of truth for phase-by-phase scope/status and roadmap revision history (previously duplicated insideproject-specification.md), with a Guiding Principles section ("write once, deploy anywhere") and an explicit Out of Scope section (Kubernetes, Terraform, Ansible - deferred to v2.x)scripts/harden-host.sh- role-driven UFW firewall (management/app/agent, each with a different port set), Fail2ban (sshd+nginx-limit-req+nginx-botsearchjails),unattended-upgrades, and an opt-in-only--harden-sshflag- SSH is always allowed - including the current session's actual port, auto-detected - before any default-deny firewall policy, to avoid locking the operator out of a remote host
Changed
- Container-level hardening applied across all four stacks (
docker/portainer/,docker/registry/,jenkins/,docker/app/): healthcheck-baseddepends_on(condition: service_healthy),stop_grace_period, resource limits, a restart-policy split (statelessunless-stopped/alwaysvs. stateful/expensive-to-crash-loopon-failure:5), and${VAR:?message}environment validation nginx/app.confandjenkins/nginx.conf: rate limiting, aPermissions-Policyheader, a starterContent-Security-Policy(app only - Jenkins manages its own), and file-based logging so Fail2ban has something to tailREADME.mdanddocs/project-specification.mdno longer embed the roadmap inline - both point todocs/roadmap.md- Roadmap scope expanded per an architecture change request: v0.6.0/v0.7.0/v0.9.0 all gained additional items - see
docs/roadmap.md's Revision History
Notes
harden-host.shhas not been run against a real host yet ---harden-sshin particular should only be used after confirming key-based SSH access works, from a second terminal- No custom Jenkins-login Fail2ban jail - no bundled filter exists for its log format, and one written without a running Jenkins to test against would be unreliable
What's next
v0.6.0 - Operations (backup.sh, restore.sh, update.sh, cleanup.sh, backup/restore verification, log rotation).
Full changelog: CHANGELOG.md
v0.4.0 — Staging Environment
Fourth release of the infra repository: the Staging Environment, plus the self-hosted registry and TLS-fronted Jenkins it depends on.
Added
- Private Docker Registry (
docker/registry/) - self-hosted, htpasswd-authenticated, TLS-terminated; deliberately no Docker Hub/GHCR dependency ssl/obtain-cert.sh- shared Let's Encrypt (webroot) / self-signed certificate helper, domain-parametrized, used by every TLS-terminating service in this repo- Jenkins fronted by TLS-terminating Nginx (
jenkins/nginx.conf) - GitHub webhooks now have a real HTTPS endpoint; Jenkins no longer publishes a host port directly vars/standardDeployPipeline.groovy'sDocker Buildstage now also pushes to the private registry (registryUrl/registryCredentialsIdparams)- Staging/production app stack (
docker/app/): Nginx + PostgreSQL + Next.js + .NET API deployed as one unit - first real use of the base +docker-compose.staging.yml/docker-compose.production.ymloverride pattern decided back at v0.1.0 nginx/app.conf: TLS termination, gzip, security headers,/api/routed to the .NET API, everything else to Next.js
Fixed
- ShellCheck CI job now scans all
**/*.shrepo-wide instead of onlyscripts/**/*.sh - Added
.gitattributesforcing LF line endings - Windows git was about to ship shell scripts with CRLF, which breaks the shebang on the Linux hosts this repo targets
Notes
- App images (
nextjs,dotnet-api) are pulled from the private registry, never built in this repo, per the app/infra separation principle - healthchecks assume conventional ports/paths (3000,/health) until the real app images exist to confirm against - Postgres backup/restore automation is out of scope here - that's v0.6.0 (Operations)
What's next
v0.5.0 - Production Environment (Oracle Cloud deployment, hardened Nginx, real production config, healthchecks).
Full changelog: CHANGELOG.md
v0.3.0 — CI/CD (Jenkins)
Third release of the infra repository: CI/CD foundation via a Dockerized, config-as-code Jenkins.
Added
- Jenkins server stack (
jenkins/docker-compose.yml,jenkins/Dockerfile) -jenkins/jenkins:lts-jdk17+ Docker CLI for Docker-outside-of-Docker builds against the host daemon - Jenkins configured entirely via JCasC (
jenkins/casc.yaml): admin user from env vars, setup wizard disabled, plugin set pinned injenkins/plugins.txt - Jenkins Shared Library (
vars/standardDeployPipeline.groovy):Checkout -> Build -> Docker Build -> Deploy via SSH, parametrized bytargetHost/targetEnv/imageNameso the same pipeline will serve AWS/Google/Oracle/Homelab deploy targets later - Registered as the
infra-shared-libraryglobal pipeline library, ready for app repos (e.g.portfolio/) to consume with a 2-line Jenkinsfile
Notes
- Deploy SSH credentials are intentionally not in this repo - added manually via the Jenkins UI after first boot
- No build triggers (webhook/polling) yet; those are configured per app repo once onboarded, and webhooks become the natural choice once Nginx/SSL fronts Jenkins (v0.4.0+)
What's next
v0.4.0 - Staging Environment (Nginx, PostgreSQL, Next.js, .NET API, SSL).
Full changelog: CHANGELOG.md
v0.2.0 — Docker Infrastructure
Second release of the infra repository: Docker management foundation via Portainer.
Added
- Portainer CE server stack (
docker/portainer/docker-compose.yml) — deployed once on the management host (AWS EC2, per the Short Term roadmap) - Portainer Agent stack (
docker/portainer/agent-compose.yml) — deployed on each remote Docker host to be managed, fulfilling the "one Portainer instance manages multiple hosts" requirement - Both images pinned to
2.39.5-alpine(required for a working Docker healthcheck — the default scratch-based image ships no shell/wget) docker/README.mddocumenting the per-concern stack layout and deploy steps
Fixed
- markdownlint CI failures (fenced code block languages, heading structure, CHANGELOG/spec doc rule tuning)
What's next
v0.3.0 — CI/CD (Jenkins in Docker, declarative pipeline: GitHub → Build → Docker Build → Deploy via SSH).
Full changelog: CHANGELOG.md
v0.1.0 — Repository Foundation
First release of the infra repository: the foundational skeleton for a reusable, multi-application DevOps infrastructure platform.
This release does not deploy anything yet — it establishes the structure, conventions, and roadmap that every future phase (v0.2.0 → v1.0.0) builds on.
Added
- Repository skeleton:
scripts/,docker/,jenkins/,nginx/,ssl/,docs/,.github/ README.md— project vision, philosophy, and roadmapCONTRIBUTING.md— commit conventions and release processLICENSE(MIT).gitignore,.editorconfig- Documentation stubs for architecture, deployment, backup, restore, and disaster recovery
- GitHub Actions lint workflow (ShellCheck + markdownlint)
- Issue and pull request templates
What's next
v0.2.0 — Docker Infrastructure (Compose base + per-environment overrides, healthchecks, named volumes, Portainer).
Full changelog: CHANGELOG.md