2.9 KiB
Website Runtime
The portfolio website keeps Apache at the core while moving PHP execution to PHP-FPM.
Runtime Shape
- Base image:
php:8.5-fpm-alpine - Web server: Alpine Apache, listening on container port
8080 - PHP runtime: PHP-FPM on
127.0.0.1:9000 - PHP cache: OPcache enabled, with timestamp validation disabled for immutable image deploys
- Dynamic storage:
/var/www/localhost/htdocs/dbmounted from the retainedwebsite-dbPVC
Apache routes *.php through proxy_fcgi to PHP-FPM. The startup script starts
PHP-FPM in the background and then runs Apache in the foreground.
Static Render Path
render-static-pages.sh runs during the image build and renders static HTML
for the read-heavy pages:
//cv.php/blog.php/demos.php/homelab-tree.php
Static output is generated for the committed static languages under
/static-pages/<lang>/. Apache rewrites supported static-language requests to
those generated HTML files. Requests for runtime-generated languages still fall
through to PHP so the translation workflow continues to work.
blog.php no longer renders visitor ideas directly into the HTML. Recent ideas
are served by visitor_ideas.php and loaded by visitor-ideas.js, which keeps
the blog page cacheable while preserving the write path through save_idea.php.
Cache Path
The website sets cache headers for pre-rendered HTML:
Cache-Control: public, max-age=300, s-maxage=3600
Dynamic write and translation endpoints are marked no-store:
save_idea.phpvisitor_ideas.phptranslate.phpsave_lang.php
The OCI edge nginx layer handles gzip, cache HITs, HTTP/2, TLS session reuse, client keepalive, and upstream keepalive to the Traefik backend. CSS and JavaScript keep the edge's longer immutable asset policy.
Translation Observability
translate.php emits one structured JSON log event for each valid translation
request. The event name is website_translation and the payload does not include
source text or translated text.
Useful fields:
cache_hitscache_missesollama_latency_msfailed_json_parse_counttimeout_countstatusreason
In Loki, filter website logs for "event":"website_translation" to inspect
cache behavior, Ollama latency, JSON parse failures, and timeout failures.
Validation
Do not build images locally. The image is built and deployed by the Debian homelab path and Gitea Actions.
Local source validation that does not build the image:
shellcheck apps/website/start-website.sh apps/website/render-static-pages.sh
find apps/website -name "*.php" -print0 | xargs -0 -n1 php -l
node --check apps/website/visitor-ideas.js
kubectl kustomize apps/website >/tmp/website-kustomize.yaml
Static rendering can be checked without Docker by copying the app to a temporary directory and running:
sh render-static-pages.sh /path/to/copied/apps/website