The platform stays intentionally small enough to review without hiding behind tooling the host size does not need.
Containers provide isolation and deployability, while routing and service boundaries stay easy to inspect.
Last reviewed: April 2026Public surfaces: 5Primary ingress: Nginx + TLS
Why this choice
The platform is intentionally small enough to stay reviewable. Container boundaries, hostnames, and reverse-proxy rules
are easier to reason about here than a larger orchestration layer would be on one VM.
Public surfaces:shellr.net, dma.shellr.net, status.shellr.net, and protected grafana.shellr.net terminate at Nginx.
Private paths: MariaDB, Prometheus, and internal service traffic stay on Docker networks and are not exposed on the host.
Failure model: a broken app container should not collapse the rest of the platform, and docs remain outside the production VM on GitHub Pages.
Review model: each hostname maps to a clear runtime responsibility, which keeps routing and incident analysis simpler.
Trust and Failure Boundaries
What is public, what is internal, and what fails together.
Public ingress: only Nginx binds to host ports 80 and 443.
Loopback-only services: Grafana, Prometheus, Alertmanager, and Uptime Kuma stay on loopback or internal Docker networks.
Cross-host separation:docs.shellr.net is intentionally outside the VM so documentation does not disappear with an app incident.
Shared-risk boundary: app, DMA, monitoring, and logging still share one VM, so retention and recovery paths are designed with that limit in mind.
Deployment Flow
Build, stage, switch, verify.
sequenceDiagram
participant Dev as Developer
participant GH as GitHub
participant Actions as Actions
participant VM as VM
Dev->>GH: push
GH->>Actions: workflow
Actions->>VM: transfer release
VM->>VM: validate config
VM->>VM: update containers
VM->>VM: run healthchecks
alt ok
VM->>Actions: success
else failed
VM->>VM: rollback
end
Failure mode: deployments are not considered complete until health checks pass.
Rollback path: staged releases and backup copies exist so a bad change can be reverted without improvisation.
Operational limit: this stays intentionally SSH- and Compose-based instead of adding a local runner or control plane.