5.2 KiB
Assets mirror — offline Minecraft asset objects for clients
Summary
Guest launchers (FjordLauncherUnlocked, a Prism soft-fork) download ~400–600 MB of
asset objects (textures, sounds, lang) from resources.download.minecraft.net
on first instance launch. For an air-gapped party that's the single biggest
client-side download. Fjord/Prism expose an "Assets Server" override, so we
mirror the objects onto our host and point guests at it.
tooling/mirror-assets.sh downloads + verifies every asset object for the pinned
Minecraft version and lays them out so Caddy can serve them in the exact path
shape the launcher expects.
Fjord/Prism override fields (confirmed)
Settings → APIs → Services tab:
| Field | Setting key | Default | What it overrides |
|---|---|---|---|
| Assets Server | ResourceURL |
https://resources.download.minecraft.net/ |
asset objects only |
| Metadata Server | (meta URL) | https://meta.prismlauncher.org/v1/ |
Prism-format version meta |
- Added in Prism 10.0.0 (PR #3875); inherited by Fjord.
- There is NO libraries-URL field. Library + client.jar URLs live inside the version/meta JSON; only a meta mirror (or DNS spoof) can redirect them.
⚠️ HTTPS is forced
PR #3875 validates the Assets Server URL as HTTPS and auto-rewrites http://
→ https://. So the assets mirror must be served over TLS — plain :80
Caddy will not work for this endpoint. This pulls local TLS forward for one
subdomain ahead of the rest of the stack.
Options to satisfy it:
- Caddy TLS on
assets.${BASE_DOMAIN}with a cert from a local CA (step-ca); guests import the CA root once. Cleanest, matches homelab. - Caddy
internalCA / self-signed — guests must trust it (more friction, per machine). - Sidestep entirely with pre-seed (below) and skip the Assets Server override.
What this mirror does and does NOT cover
| Client download | Host | Covered here? |
|---|---|---|
| asset objects (bulk) | resources.download.minecraft.net | ✅ this mirror + Assets Server field |
| asset index json | meta/piston | ⚠️ fetched here for completeness; launcher still pulls it from meta unless meta is also mirrored |
| libraries | libraries.minecraft.net | ❌ no override field |
| client.jar | piston-data.mojang.com | ❌ |
| version/meta json | meta.prismlauncher.org | ❌ (separate Metadata Server field) |
Full client air-gap therefore needs more than this. For the uncovered, small (~150 MB) remainder, the pragmatic fallback is pre-seed: each guest launches the instance once while online (on arrival, before air-gapping); Prism caches libraries/jar/meta locally. The assets mirror still saves the heavy 400 MB+ per guest. A full meta+libraries mirror (mcm-style / PrismLauncher-meta gen) is the heavyweight alternative, deferred.
tooling/mirror-assets.sh — design
Input: MC_VERSION (default 1.21.1, or read from the pre-baked server's
version.json). Cautious: verifies SHA1 on every file, halts on mismatch,
idempotent (skips already-valid files).
1. GET https://piston-meta.mojang.com/mc/game/version_manifest_v2.json
→ find entry for $MC_VERSION → version-json URL
2. GET version-json → read .assetIndex { id, url, sha1 }
3. GET asset index → mirror/assets/indexes/<id>.json (verify sha1)
4. For each object in index .objects{}:
hash=<sha1>; rel="${hash:0:2}/${hash}"
dest="mirror/assets/objects/${rel}"
[ -f "$dest" ] && sha1 ok → skip
else GET https://resources.download.minecraft.net/${rel} → $dest ; verify sha1
5. Report counts; non-zero exit on any failure.
Layout served by Caddy:
mirror/assets/
├── indexes/<id>.json # e.g. 17.json / 1.21.json (for pre-seed/meta use)
└── objects/<2hex>/<sha1> # launcher requests <ResourceURL>/<2hex>/<sha1>
Caddy wiring
Serve the objects dir at the web root of an HTTPS vhost so the launcher's
<ResourceURL>/<2hex>/<hash> resolves directly:
https://assets.{$BASE_DOMAIN} {
tls <local-ca-cert> <key> # or `tls internal`
root * /srv/assets/objects
file_server
}
Mount ./mirror/assets/objects:/srv/assets/objects:ro. Add network alias
assets.${BASE_DOMAIN} to Caddy (same trick as auth/packwiz).
Fjord "Assets Server" = https://assets.${BASE_DOMAIN}/.
Tasks
- Write
tooling/mirror-assets.sh(above);chmod +x; depscurl+jq+sha1sum - Decide MC_VERSION source: hardcode
1.21.1vs read pre-bakedversion.json - Run pre-party while online; verify
mirror/assets/objects/populated + sha1 clean - Stand up TLS for
assets.${BASE_DOMAIN}(step-ca ortls internal) — REQUIRED (HTTPS forced) - Add
assets.Caddy vhost + network alias + mount - Document guest step: Settings → APIs → Assets Server =
https://assets.${BASE_DOMAIN}/ - Document guest CA-trust step (import local CA root) if not using a publicly-trusted cert
- Confirm in Fjord's actual UI that the field exists + HTTPS-forcing behavior matches Prism
- Fallback path: pre-seed instructions (launch once online) for libraries/jar/meta
- Defer decision: full meta+libraries mirror (mcm / PrismLauncher-meta) vs pre-seed
.gitignorealready coversmirror/