Web Server Configuration for On-the-Fly Graphics Asset Loading

Our video game development company runs independent projects, jointly creates games with the client and provides additional operational services. Expertise of our team allows us to cover all gaming platforms and develop an amazing product that matches the customer’s vision and players preferences.
Showing 1 of 1 servicesAll 242 services
Web Server Configuration for On-the-Fly Graphics Asset Loading
Medium
~3-5 business days
FAQ
Our competencies
What are the stages of Game Development?
Latest works
  • image_games_mortal_motors_495_0.webp
    Game development for Mortal Motors
    663
  • image_games_a_turnbased_strategy_game_set_in_a_fantasy_setting_with_fire_and_sword_603_0.webp
    A turn-based strategy game set in a fantasy setting, With Fire and Sword
    859
  • image_games_second_team_604_0.webp
    Game development for the company Second term
    490
  • image_games_phoenix_ii_606_0.webp
    3D animation - teaser for the game Phoenix 2.
    533

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.