NMSR has no per-request avatar refresh (the `?skin=` override is ignored by this build), so the only lever for a changed skin to appear is the resolve cache. Drop resolve_cache_duration 15m -> 60s so account-page skin changes propagate within ~1 min; texture cache stays 48h (Drasl skin URLs are content-hashed, so a new skin is always a new URL — never stale). Cost is one extra internal Drasl profile lookup per avatar per minute, trivial for 4-10 players. Update the now-stale "~15 min" copy (skinLead + skinPreviewNote, en/es/eu) and code comments to "~1 min". Add plan/19-routes.md: a reference for the nmsr / landing / auth HTTP routes (public via caddy + browser->Drasl + internal service-to-service), indexed in plan/00-overview.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.3 KiB
4.3 KiB
19 — HTTP route reference (nmsr, landing, auth)
Quick map of the public + internal HTTP routes. caddy (
caddy/conf.d/*.caddy) is the internal router; the host nginx terminates TLS and forwards each vhost to it by Host header. All${BASE_DOMAIN}=ulicraft.netin prod.
Vhost → service (caddy)
| Vhost | caddy file | Upstream |
|---|---|---|
${BASE_DOMAIN} (apex) |
10-static.caddy |
static /srv/www + /srv/launcher + mc-status |
auth.${BASE_DOMAIN} |
00-core.caddy |
drasl:25585 |
avatar.${BASE_DOMAIN} |
40-avatar.caddy |
nmsr:8080 |
status.${BASE_DOMAIN} |
50-status.caddy |
uptime-kuma:3001 |
distribution.${BASE_DOMAIN} |
30-distribution.caddy |
static /srv/distribution (other repo) |
NMSR — avatar.${BASE_DOMAIN} (skin/avatar renderer)
reverse_proxy nmsr:8080. Stateless renderer; pulls profiles+skins from Drasl
over mcnet (no public round-trip).
GET /{mode}/{uuid}?size=N— render an avatar PNG.mode= any NMSR render mode (headisois the configured default viaAVATAR_MODE; others incl.head,face,fullbody,fullbodyiso).uuid= Drasl player UUID;size= px.- Landing usage:
${avatarUrl}/${avatarMode}/<uuid>?size=64|96.
- No per-request refresh. A
?skin=<url>override is ignored by this build (tested). Skin changes propagate via the resolve cache only. - Caching (
nmsr/config.toml):resolve_cache_duration = 60s(uuid→profile, bounds stale-avatar window),texture_cache_duration = 48h(safe — Drasl skin URLs are content-hashed, new skin = new URL). Instant global flush = restart nmsr. Seeplan/03-drasl.mdfor the Drasl-backed mojank wiring.
Landing — ${BASE_DOMAIN} (apex)
10-static.caddy. Three handlers:
handle_path /launcher/*→/srv/launcher(file browse) — launcher downloads.handle /api/mcstatus/*→uri strip_prefix /api/mcstatus→mc-status:8080:/api/mcstatus/v2/status/java/<addr>→ internal/v2/status/java/— live server status JSON (mcstatus.io-compatible,CORS: *,<addr>ignored — it only pingsMC_STATUS_TARGET). LandingstatusApi./api/mcstatus/players→ internal/players— registered-players roster, sanitized[{uuid,name}], ~60s cache (mc-status admin-logs-in to DraslGET /players). LandingrosterApi./healthz— mc-status liveness (internal).
handle {}→/srv/wwwstatic (Astro output). Pages:/,/es,/eu(index),/{lang}/register,/{lang}/account,/{lang}/fjord.
Browser → Drasl directly (CORS-scoped to apex via Drasl CORSAllowOrigins),
base https://auth.${BASE_DOMAIN}/drasl/api/v2 (site.draslApiUrl):
register.astro:POST /users(register),POST /login,PATCH /players/{uuid}(set initial skin).account.astro:POST /login,PATCH /players/{uuid}with{skinBase64,skinModel}(upload) or{deleteSkin:true}(reset).
Auth / Drasl — auth.${BASE_DOMAIN}
reverse_proxy drasl:25585. One service exposes three surfaces:
- Web UI:
/(login / register / profile pages),/web/texture/skin/<sha256>.png,/web/texture/cape/<sha256>.png. - Yggdrasil / authlib-injector:
/authlib-injector(API root — server JVM agent + clients point here),/session/minecraft/..., mojang-compat/users/profiles/minecraft/{name}and/session/minecraft/profile/{uuid}(also what NMSR calls internally). - Drasl REST API v2 (
/drasl/api/v2):POST /login{username,password}→{apiToken}POST /users{username,password[,inviteCode]}— register (invite-gated whenRequireInvite=true; admins fromDefaultAdminsare promoted at startup, seeplan/03-drasl.md)GET /players— admin only, full rosterPATCH /players/{uuid}— skin CRUD (own player, or admin)POST /invites— admin, mint invite codes
Internal (service → service, over mcnet)
minecraft→-javaagent authlib-injector=http://auth.${BASE_DOMAIN}/authlib-injector(caddy mcnet alias → drasl).nmsr→http://auth.${BASE_DOMAIN}(mojang-compat session/textures/api).mc-status→http://drasl:25585/drasl/api/v2(DRASL_API_URL) for the roster; pingsMC_STATUS_TARGETfor live status.mc-backup→ RCONminecraft:25575.