Documentation static service
Lifecycle: Current. Last verified: 2026-07-17.
Service record
| Field | Value |
|---|---|
| Purpose | Serve generated MkDocs files to ingress Caddy |
| Owner | IT Operations |
| Criticality / recovery priority | High / P3 |
| Host/runtime | CT 101, rootless Podman as podsvc |
| Image | docker.io/library/caddy:2-alpine |
| Unit | docs-static.service |
| Quadlet | /home/podsvc/.config/containers/systemd/docs-static.container |
| Data | /opt/podman/volumes/forgejo/runner-data/publish/kh3-it-infra-docs/site |
| Mount | Data path to /srv:ro |
| Listener | CT host 30084 to container 8080 |
| Public route | docs.kh3group.com through CT 103 |
Architecture and dependencies
Forgejo Actions owns the build and copy. This container owns only static
serving. It does not mount Git source, run MkDocs, or write the artifact. It
depends on CT 101, the publish directory, rootless user systemd, and Podman.
Public access additionally depends on CT 103, DNS, and OPNsense.
Reconstruction
Create the publish directory as podsvc, restore or rebuild the artifact, and
install this Quadlet:
[Unit]
Description=KH3 MkDocs static site rootless container
After=network-online.target
Wants=network-online.target
[Container]
Image=docker.io/library/caddy:2-alpine
ContainerName=docs-static
Network=kh3-backend.network
Volume=/opt/podman/volumes/forgejo/runner-data/publish/kh3-it-infra-docs/site:/srv:ro
Exec=caddy file-server --root /srv --listen :8080
PublishPort=30084:8080
AutoUpdate=registry
[Install]
WantedBy=default.target
No secret is required by this service.
Operate
ssh pvessh 'pct exec 101 -- runuser -l podsvc -c \
"XDG_RUNTIME_DIR=/run/user/2000 systemctl --user status docs-static.service --no-pager"'
ssh pvessh 'pct exec 101 -- runuser -l podsvc -c \
"podman logs --tail=100 docs-static"'
ssh pvessh 'pct exec 101 -- curl -sS -o /dev/null -w "%{http_code}\n" \
http://127.0.0.1:30084/'
Expected: active unit and 200.
After an approved Quadlet change:
ssh pvessh 'pct exec 101 -- runuser -l podsvc -c \
"XDG_RUNTIME_DIR=/run/user/2000 systemctl --user daemon-reload"'
Start, stop, or restart only docs-static.service during the approved action.
Upgrade, backup, and restore
Use a tested image digest/tag before upgrading. Back up the Quadlet and runner
configuration; rebuild the artifact from Git. An artifact snapshot may be kept
for rapid recovery. Restore into a new directory, validate index.html,
ownership, modes, and HTTP, then swap atomically. Keep the old directory for
rollback.
Monitoring and security
- Monitor unit state, backend
200, public200, and artifact age. - Treat a failed Forgejo post-publish backend or ingress check as a failed deployment even when the artifact copy completed.
- Keep the artifact mount read-only.
- Do not expose port
30084beyond intended DMZ/ingress sources. - Do not add tokens or ACME material; TLS belongs to CT
103.
Troubleshooting
| Symptom | Cause | Diagnosis | Remedy |
|---|---|---|---|
403 |
Directory/file traversal denied | namei -l and stat publish path |
Restore least-privilege read/execute modes |
404 |
Missing index.html or wrong mount |
Inspect Quadlet and file presence | Rebuild/publish correct artifact |
| Connection refused | Unit/container down | User systemd and Podman status | Repair/restart only this unit |
Public 502 with backend 200 |
CT 103 route/network |
Use Caddy runbook | Repair ingress layer |
| Old content | Artifact not updated | Compare Git/job/file/HTTP times | Use publishing runbook |