niklas‑stephan.de

niklas-stephan.de site: Astro rewrite with Wiki.js MCP content source (nsde container)

Last updated 06/11/2026 · handtrixxx, website, astro, wikijs, mcp, migrated-from-outline

  • kb-id: site-astro-rewrite
  • importance: high
  • tags: handtrixxx,website,astro,wikijs,mcp,migrated-from-outline
  • updated: 2026-11-06
  • summary: niklas-stephan.de rewritten Hugo+Outline Astro 5; content synced Wiki.js via MCP endpoint; nsde container builds on boot and rebuilds every REFRESH_MINUTES. Staging live at qas.niklas-stephan.de; production swap pending approval.

Current state (since 2026-11-06)

  • Repo: Gitea handtrixxx/niklas-stephan.de (main). Old Hugo/Outline pipeline (hugo/, scripts/, nginx/) removed; site is Astro 5 static site at repo root.
  • Content source: Wiki.js MCP at https://wiki.niklas-stephan.de/_mcp (bearer WIKI_MCP_TOKEN), path prefixes from WIKI_PATHS (default kb,home). Loader src/loaders/wiki.ts caches pages in .wiki-cache/ keyed on updatedAt, retries on HTTP 429 backoff, strips kb header block, converts {.is-info} admonitions callout divs, absolutizes root-relative image URLs.
  • Loader also generates public/search-index.json (fuse.js client search at /search/) and public/rss.xml; @astrojs/sitemap registered in integrations provides /sitemap-index.xml + /sitemap-0.xml.
  • Static pages about/imprint/privacy live in src/pages-static/; wiki pages served under /wiki/<path>/.
  • Container: node:22-alpine; scripts/start.mjs serves dist/ on port 80, runs npm run build on boot and every REFRESH_MINUTES (default 60). Traefik routing unchanged (niklas-stephan.de, www, handtrixxx.com, www; certresolver letsencrypt-tls; service nsde port 80).
  • Deploy env (/data/docker/niklas-stephan.de/.env on handtrixxx.com) needs WIKI_MCP_TOKEN, WIKI_PATHS=kb,home, REFRESH_MINUTES, SITE_BASE_URL. Token also in /data/ai-persistence/.env.

Staging: qas.niklas-stephan.de (live since 2026-11-06)

  • Dir /data/docker/qas.niklas-stephan.de on handtrixxx.com; compose service nsde-qas, image git.handtrixxx.com/handtrixxx/niklas-stephan.de:qas, Traefik router nsde-qas with Host(qas.niklas-stephan.de) and certresolver letsencrypt-tls (TLS challenge works because the subdomain already resolves to 148.251.15.253), REFRESH_MINUTES=15. The repo ships this compose as qas.example.yml.
  • Verified over HTTPS: home, /wiki/kb/… pages, /search/, /rss.xml, /sitemap-index.xml (73 URLs), /robots.txt, /humans.txt all 200; boot rebuild built 74 pages. /blog/ 404 is expected (no blog pages in the wiki yet).

Gotchas verified 2026-11-06

  • MCP get_page returns page as multiple text blocks (metadata JSON first, then markdown body); search_pages limit caps at 25, paginate offset.
  • Astro 5: sitemap: true in astro.config does nothing by itself; register integrations: [sitemap()], and the files are sitemap-index.xml/sitemap-0.xml, not sitemap.xml.
  • Dockerfile build step runs before runtime env set, so initial dist has only static pages; boot rebuild in start.mjs compensates (pulls wiki immediately on start).
  • Docker COPY a b scripts ./ flattens scripts directory into ./ — copy scripts separately.
  • Gitea repo is not anonymously cloneable (404); clone with auth or copy tree.
  • Copying the repo tree into a deploy directory overwrites that directory’s compose.yml: the repo-root compose is the production one (container nsde). On qas this made docker compose up try to create a second nsde container (failed with name conflict, production untouched). Keep the staging compose outside the tar or restore it after copying.

Not yet done

  • Production nsde container still runs old Hugo image; deploy new image only after Niklas approves.

Source: Wiki.js