Development Site
Overview
| Field | Value |
|---|---|
| Purpose | Serve development/static deployment content |
| Owner | Development team; named owner to be recorded |
| Criticality | Low |
| Image | caddy:2-alpine |
Architecture
The restored Forgejo Actions runner publishes build artifacts under the
rootless runner data volume on CT 101. A rootless static Caddy container
serves the published directory on CT 101, and ingress Caddy on CT 103
should proxy the public/internal hostname to that service.
Installation
Legacy Docker-era deployment paths such as /root/kh3-dev-site are no longer
the target design. Use the Forgejo runner data volume, matching the
documentation publishing pattern.
Configuration
- Actions publish path:
/opt/podman/volumes/forgejo/runner-data/publish/kh3-dev-site - Image cache path:
/opt/podman/volumes/forgejo/runner-data/cache/kh3-dev-site-images - Static service Quadlet:
/home/podsvc/.config/containers/systemd/kh3-dev-site-static.container - Static service mount:
/opt/podman/volumes/forgejo/runner-data/publish/kh3-dev-site:/srv:ro - Static service port:
192.168.2.20:30085 - Podman network:
kh3-backend - Ingress route:
kh3-dev-site.kh3group.com -> 192.168.2.20:30085 - Required internal DNS:
kh3-dev-site.kh3group.com -> 192.168.2.3
Current Status
Validated on 2026-07-15:
- Rootless static service
kh3-dev-site-staticis running on CT101. - Static backend
http://127.0.0.1:30085/returns200. - Ingress Caddy on CT
103routeskh3-dev-site.kh3group.comto192.168.2.20:30085. - Caddy obtained Let's Encrypt certificates for
kh3-dev-site.kh3group.comandproxy.kh3group.com. - Internal Caddy test with SNI forced to
192.168.2.3returned200. - Public
https://kh3-dev-site.kh3group.com/returned200. - Forgejo Actions task
56, triggered by site repo commit62426aa, refreshed the publish directory. Top-level artifacts under/opt/podman/volumes/forgejo/runner-data/publish/kh3-dev-sitenow have 2026-07-15 timestamps.
Pending:
- Add Technitium split-DNS record
kh3-dev-site.kh3group.com -> 192.168.2.3. As of the 2026-07-15 validation, Technitium still resolves this name to public Cloudflare addresses104.21.13.63and172.67.198.148. The Technitium API requires an authenticated token; do not edit/etc/dns/zones/*.zonedirectly because the zone files are Technitium binary format.
On 2026-07-15, validation found the publish directory present but stale, with top-level files last modified on 2026-07-08 before the workflow fix. The live runner config allowed only these bind roots:
/opt/podman/volumes/forgejo/runner-data
/opt/podman/volumes/forgejo/runner-ssh
The site workflow in kh3-dev-site previously referenced /root/kh3-dev-site,
which the hardened runner rejects. Commit 2d6c63c in the site repo updated it
to mount the runner data volume and publish to
/runner-data/publish/kh3-dev-site.
Operational Procedures
ssh pvessh 'pct exec 101 -- runuser -l podsvc -c "XDG_RUNTIME_DIR=/run/user/2000 systemctl --user status kh3-dev-site-static.service --no-pager"'
ssh pvessh 'pct exec 101 -- runuser -l podsvc -c "podman ps --filter name=kh3-dev-site-static"'
ssh pvessh 'curl -I http://192.168.2.20:30085/'
Coordinate changes with Forgejo Actions because the runner writes to the rootless runner artifact directory. The serving container should read the published directory only; it should not own the build or copy step.
Expected workflow volume and deploy target:
container:
image: node:20-bullseye
volumes:
- /opt/podman/volumes/forgejo/runner-data:/runner-data
target=/runner-data/publish/kh3-dev-site
mkdir -p "$target"
rm -rf "$target"/*
cp -a ./dist/. "$target"/
chmod -R 755 "$target"
The deploy step should verify that /runner-data is actually mounted before it
copies artifacts. Treat is not a valid volume, will be ignored as a publish
failure.
Troubleshooting
Check the most recent Actions deployment, runner volume warnings, file ownership, the static Caddy container logs, ingress Caddy routing, Cloudflare Tunnel origin, and the Technitium local A record.
On 2026-07-15, Cloudflare Tunnel logs showed public requests for
kh3-dev-site.kh3group.com reaching the tunnel but being sent to the legacy
origin https://proxy.kh3group.com, which failed before routing with
tls: internal error. Caddy now has a minimal proxy.kh3group.com
compatibility site so the legacy origin can complete TLS. Still prefer
correcting the remotely managed Cloudflare Tunnel origin to point directly at
the current Caddy ingress path.