Files
webgpu-portfolio/DEPLOYMENT.md

5.1 KiB

Deployment Handover

How the migrated Hugo site is served, and how to adjust the server-side deploy workflow (Gitea Actions + webhook) for the new two-stage build.

Serving topology (unchanged)

The site is served as before. The host's system nginx (Certbot-managed TLS at djosen.one) proxies location / → 127.0.0.1:8080, where the Docker web container listens. Nothing changed in the system nginx (nginx/system-default.conf / nginx/reverse.conf) or the Certbot/DNS setup during this migration.

What changed is what's inside the container: instead of a Vite SPA (a single index.html plus JavaScript), the container now serves a Hugo static site — public/ with one real .html page per path.

What changed in the build

The build is now two steps:

  1. Engine — gpu-bg/ Vite/Typescript build → a static JS bundle (gpu-bg/dist/).
  2. Site — hugo --minify → public/.

The Dockerfile runs both in stages (node → hugo → nginx).

Key details for the server build:

  • Hugo image: the site stage uses hugomods/hugo:debian-dart-sass-go-0.165.0 — an extended Hugo build including dart-sass. This is required because hugo-coder compiles the theme's SCSS via Hugo Pipes (toCSS), and Hugo 0.129+ dropped libsass in favor of dart-sass. This replaced the deprecated klakegg/hugo image.
  • Theme submodule: hugo-coder lives as a git submodule at themes/hugo-coder.
  • Static serving only: the container nginx no longer does SPA fallback (try_files ... /index.html). It serves plain static files — each page is a real .html, and a 404 for a missing path is legitimate and intentional.

Mandatory server-side change (the #1 gotcha)

Your clone/checkout must initialize submodules before building. The themes/hugo-coder submodule must be pulled in before docker build; otherwise hugo fails with theme not found and the build breaks.

  • Gitea Actions deploy.yml: make the checkout recursive. With actions/checkout, set:

    - uses: actions/checkout@v3
      with:
        submodules: recursive
    
  • Plain webhook / shell: use a recursive clone, or run the update before building:

    git clone --recursive ...
    # or, on an existing clone:
    git pull
    git submodule update --init --recursive
    

Nothing else changes server-side: registry credentials, the SSH/webhook target, and the docker compose up -d deploy command are all the same. The image is slightly larger to build (node and Hugo-extended layers are discarded; the final nginx stage stays small).

Testing

Local (before pushing)

git submodule update --init --recursive
cd gpu-bg && npm install && npm run build && cd ..
hugo                                # builds public/
docker compose build                # 3-stage build
docker compose up -d                # maps 127.0.0.1:8080:8080

Smoke test (after up -d)

curl -sf http://127.0.0.1:8080/            | grep -q 'id="gpu"' && echo "canvas OK"
curl -sf http://127.0.0.1:8080/gpu/engine.js -o /dev/null && echo "engine bundle OK"
curl -sf http://127.0.0.1:8080/about/       -o /dev/null && echo "about OK"
curl -sf http://127.0.0.1:8080/projects/    -o /dev/null && echo "projects OK"
curl -sf http://127.0.0.1:8080/resume/      -o /dev/null && echo "resume OK"
curl -sf http://127.0.0.1:8080/posts/       -o /dev/null && echo "posts OK"
curl -s  http://127.0.0.1:8080/nonexistent  -o /dev/null -w "%{http_code}\n"   # expect 404

Browser check (manual — WebGPU is a real-GPU feature)

  • Homepage: emerald spiral animates behind the dark glass panel; text readable.
  • With WebGPU disabled, the WebGL2 fallback still animates.
  • With no WebGL at all, the page still shows its content; the canvas simply doesn't render.

After deploy (remote)

  • curl -s https://djosen.one/health → ok (system nginx health endpoint, unchanged).
  • Verify /, /about/, /projects/, /resume/, /posts/ over HTTPS.
  • Confirm the spiral actually renders in a real browser — the one thing curl cannot check.

Troubleshooting

Deploy status stuck/red on Gitea after a migration or restart

If the Actions/deploy status shows broken or stops updating (commits push but no run is registered), the per-repo git hooks may be stale or missing. Fix by resynchronizing hooks from the Gitea admin CLI (this regenerates pre-receive, update, post-receive and their .d/gitea delegates):

docker exec -u git gitea gitea admin regenerate hooks

For the full documented recovery, the Gitea FAQ steps are: "Sync missed branches from git data to databases", "Sync tags from git data to database", and "Resynchronize pre-receive, update and post-receive hooks of all repositories" (the last one is what the command above does). After regenerating, push a commit to refresh the status.

Rollback

The previous site is preserved in the git tag pre-hugo and the archive/ folder. To roll back: git checkout pre-hugo and redeploy with the old single-stage Dockerfile (also recoverable from git history).

No system nginx or DNS changes were made in this migration, so rollback is purely a container-image swap.