feat(landing): live server card backed by self-hosted mc-status

Add a featured live ServerCard to the landing (replaces the static
ServerListPanel in hero + status sections): server favicon, color MOTD,
online/offline pill, players online/max with fill bar, and a player-head
row rendered by our own NMSR from Drasl skins. Progressive enhancement —
SSG skeleton degrades gracefully when JS or the API is unavailable.

Back it with a self-hosted pinger instead of the public api.mcstatus.io:
mcstatus.io's API service is closed-source (only the mcutil library is
open), so docker/mc-status wraps mcutil and re-emits its v2 JSON shape,
keeping the frontend unchanged. The service ignores the path address and
only pings MC_STATUS_TARGET (no SSRF relay), with a 30s TTL cache.

Exposed same-origin via caddy at the apex /api/mcstatus/* path (no new DNS
subdomain or LE cert change, no CORS). Uptime Kuma stays the uptime
history + alerting backend; see plan/15-mc-status.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 22:08:30 +02:00
parent df8ffca53e
commit d21a7f0e92
11 changed files with 581 additions and 7 deletions

View File

@@ -51,12 +51,14 @@ export const site = {
avatarUrl: `https://avatar.${BASE_DOMAIN}`,
// Live server card (ServerCard.astro). `slots` is the SSG fallback cap shown
// before/without JS; live count comes from mcstatus.io pinging the public
// address. mcstatus.io sets Access-Control-Allow-Origin:* → direct browser
// fetch, no proxy/key. Uptime Kuma stays the history + alerting backend.
// before/without JS; live data comes from our SELF-HOSTED mc-status service
// (docker/mc-status, mcutil wrapper) reverse-proxied same-origin at the apex
// /api/mcstatus/* path — no CORS, no third-party calls. It emits mcstatus.io
// v2 JSON, so the URL stays drop-in compatible. Uptime Kuma stays the history
// + alerting backend (plan/10).
status: {
slots: 10,
statusApi: `https://api.mcstatus.io/v2/status/java/${BASE_DOMAIN}`,
statusApi: `/api/mcstatus/v2/status/java/${BASE_DOMAIN}`,
},
// Honest stat tiles. Keys (numbers/versions) are language-neutral; labels