id: 234 slug: web-server-setup-for-on-the-fly-asset-loading title_en: "Web Server Setup for On-the-Fly Asset Loading" tags: [vr-ar]
Web Server Setup for On-the-Fly Asset Loading
VR-game APK with full content easily exceeds 2 GB — Quest Store limit and close to Google Play limit. Asset streaming solves this: build includes only critical startup resources, rest loaded on demand. But "load on-the-fly" and "load fast and reliably" are different tasks, second entirely depends on properly configured server.
What Server Needs for AssetBundle Streaming Work Properly
AssetBundle — not just HTTP file. It has several properties affecting server requirements.
Range requests mandatory. UnityWebRequest.GetAssetBundle() with caching uses HTTP Range header for verification: is fragment already downloaded, need to download more? If server responds to Range: bytes=0-1023 with full file instead of 206 Partial Content — Unity cache doesn't work, each run redownloads entire bundle. Nginx supports Range by default, but some CDN-configurations disable it.
ETag / Last-Modified for cache validation. Unity AssetBundle Cache verifies version via CacheControlParams or hash. If server doesn't send ETag or Last-Modified, Unity can't determine if bundle changed — either redownloads every time or works with outdated version. ETag setup in Nginx: etag on; — single line, but often forgotten.
GZIP/Brotli only for text resources. AssetBundle in LZ4 format (optimal for real-time loading) doesn't need additional HTTP compression — only extra CPU-cycles for decompression. In Nginx: gzip_types must explicitly exclude application/octet-stream for bundles.
CORS for WebGL. If VR-content runs via WebXR in browser — server must send correct CORS-headers: Access-Control-Allow-Origin, Access-Control-Expose-Headers: Content-Length (needed for progress bar on load).
Server Architecture for Asset Streaming
Typical scheme: Origin server (master storage, version management) + CDN (distribution, edge-cache).
For Origin use Nginx or Caddy. Caddy attractive for small teams: automatic HTTPS via Let's Encrypt, configuration in single Caddyfile, correct headers by default.
Asset URL structure includes version: /assets/v{hash}/{bundleName}. On content update hash in path changes — CDN doesn't serve cache, client gets new bundle. More reliable than cache-busting via query string (?v=123), which some CDN ignore.
For CDN serving VR-audience (global distribution), work well: Cloudflare R2 + Cloudflare CDN (free egress) or AWS S3 + CloudFront. Key CloudFront setup: Cache-Control: max-age=31536000, immutable for versioned bundles, Cache-Control: no-cache for manifest-file (list of current bundle URLs and hashes).
Asset Bundle Manifest — separate lightweight file (~10 KB) containing all bundles with hashes and dependencies. Client downloads on startup, compares with local cache, downloads only changed bundles. Content update without app reinstall — via manifest entry changes and new bundles on CDN.
Client Side
In Unity — UnityWebRequestAssetBundle.GetAssetBundle(url, cachedVersion, crc). cachedVersion taken from manifest. crc — additional integrity check (not required if TLS configured correctly).
Build loading via queue with priorities: current scene assets — high priority, next scene assets — medium, decorative content — low. Max parallel requests — 4–6 (HTTP/1.1 limitation, with HTTP/2 can be more, but Unity WebRequest not always correct with multiplexing).
For Quest (Android) important: Application.temporaryCachePath limit — recommended max 1 GB for bundle cache, otherwise OS aggressively clears. Implement CacheEvictionPolicy with LRU: on limit reached delete unused bundles via Caching.ClearCachedVersion().
Work Stages
Content audit. Which assets go to build, which stream, versioning strategy.
Origin + CDN setup. Nginx/Caddy configuration, S3/R2 bucket, CDN caching rules.
Bundle build tools. AssetBundle Browser or Addressables with automatic build pipeline in CI.
Client loader. Queue, priorities, cache management, network error fallback.
Load testing. 1000 simultaneous clients, degradation with 50% packet loss.
| Scale | Estimated Timeline |
|---|---|
| Simple CDN + AssetBundle loader | 1–2 weeks |
| Complete system with versioning and manifest | 3–5 weeks |
| Global CDN + load analytics + A/B content | 2–3 months |
Cost calculated after content volume and availability requirements analysis.





