Architecture

Single host, explicit surfaces.

The core design choice is not to hide complexity behind orchestration layers that the host size does not justify. Containers are used for isolation and deployability, while networking and runtime boundaries stay inspectable.

flowchart TD User["Client"] --> DNS["Public DNS"] DNS --> Nginx["Nginx reverse proxy"] Nginx --> Shellr["shellr.net"] Nginx --> DMA["dma.shellr.net"] Nginx --> Grafana["grafana.shellr.net"] Nginx --> Status["status.shellr.net"] Shellr --> App["Portfolio app container"] DMA --> DMAApp["DMA app container"] DMAApp --> DB["MariaDB"] Grafana --> Metrics["Prometheus metrics"] Grafana --> Logs["Loki logs"] Status --> Kuma["Uptime Kuma"] Docs["docs.shellr.net"] --> Pages["GitHub Pages"]

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