10 KiB
HTTP cache — HOT, COLD and invalidation
RustProxy provides an optional shared HTTP response cache with a bounded in-memory HOT tier and optional persistent-disk COLD tier. Both the global cache and a Vhost's effective policy must permit caching. COLD storage is disabled by default, and newly created Vhosts do not automatically cache dynamic content.
Enable caching safely
- Open Settings → Cache, enable the global cache and choose memory limits. Enable COLD only if you want durable disk storage and have enough private disk capacity.
- On the appropriate Vhost, enable cache for public, repeatable responses. Restrict or disable it for login, personalized pages, uploads, APIs and responses carrying secrets.
- Ensure the origin supplies a valid public freshness policy, or configure a safe default TTL where supported.
Cache-Control: privateandno-storemust prevent shared storage. - Optionally enable HIT-only diagnostics. Send repeated identical requests using
curl, then inspect Cache → Domains / Stored objects forMISS → HIT. - Review Varnish-compatible cache policy, enabled by default, then check TTL, revalidation and invalidation after updating the origin's content or configuration.
Varnish-compatible cache policy (0.34.7)
Settings → Cache → Varnish-compatible cache policy (cache.varnish_compatible, on by default) changes request-side cache lookup, not authentication or the cache key. Disabling it restores the earlier strict policy without a service restart. Changing this policy invalidates cached representations to avoid mixing storage semantics across modes; allow time for HOT/COLD to refill. Effective settings also apply to eligible embedded Web Server resources and HOT/COLD entries. Existing JSON configs with no new field inherit true.
| Condition | Enabled: Varnish-style | Disabled: legacy strict |
|---|---|---|
Client Cache-Control: no-cache, no-store, max-age=0, min-fresh, max-stale |
Ignore client cache directives for lookup and freshness; a fresh object stays HIT and keeps Age and hit count |
Revalidate/bypass or constrain freshness as instructed by the client |
Client Pragma: no-cache, only-if-cached |
Ignore both; do not force backend or a synthetic 504 purely because of these directives | Revalidate or give 504 for a missing only-if-cached representation |
Origin Cache-Control: no-cache |
Do not store, like Varnish's built-in VCL | Store only with a validator and require revalidation per request |
Origin Surrogate-Control: no-store |
Do not store | Existing RustProxy behavior |
| Origin zero/nonpositive remaining TTL | Do not store | May retain a zero-TTL representation for revalidation; never a fresh HIT |
| Expired but eligible object | Allow up to 10 seconds of background-refresh grace (or explicit larger stale-while-revalidate), unless must-revalidate / proxy-revalidate forbids stale delivery |
Only explicitly configured stale/grace conditions |
Origin private, no-store, Set-Cookie, Vary: *; client Authorization |
Existing RustProxy restrictions always apply | Same |
| Static-file cookie-ignore allowlist, custom bypass/force rules, TTL caps, BAN/PURGE, request collapse, compression/transform, HOT/COLD, tenant isolation | Unchanged RustProxy mechanisms | Same |
For /ui/style.css with Cache-Control: public, max-age=600 and no origin ETag/Last-Modified, a hard reload with Cache-Control: no-cache should now remain HIT while its cached representation is fresh. The request headers are not stripped before forwarding when an origin fetch actually occurs; RustProxy only ignores them for its own lookup/freshness checks. Client If-None-Match/If-Modified-Since, range conditions, URL query, Host and Vary are preserved. Strict mode remains available for installations requiring clients to force validation.
This is a documented policy subset, not a Varnish binary/VCL clone. RustProxy deliberately keeps an explicit zero-by-default fallback TTL (no implicit Varnish 120s TTL), configured cookie exceptions, multi-tenant security, stale prohibitions for must-revalidate, and no Varnish-style hit-for-miss/hit-for-pass markers. Not every Varnish configuration behaves like the default built-in VCL. Cookies continue to be omitted from the cache key only for the already-configured static-file exception; do not enable that exception for personalized static endpoints. A no-cache origin response must not be made cacheable merely to gain HITs.
Use a three-request GET comparison with curl (replace URL with your static resource):
URL=https://example.com/ui/style.css
curl -sS --compressed -D - -o /dev/null "$URL" | grep -iE '^(HTTP/|age:|x-cache:|x-cache-hits:|x-cache-reason:)'
curl -sS --compressed -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' -D - -o /dev/null "$URL" | grep -iE '^(HTTP/|age:|x-cache:|x-cache-hits:|x-cache-reason:)'
curl -sS --compressed -D - -o /dev/null "$URL" | grep -iE '^(HTTP/|age:|x-cache:|x-cache-hits:|x-cache-reason:)'
Enable diagnostic headers if needed. With compatibility on, the middle response should be HIT, and Age should not reset on a fresh object. With compatibility off, it can be MISS and reset if no origin validator is available. Explicit PURGE/BAN and stale/expired TTL remain authoritative.
Vhost editor options
In Vhosts → Cache, overrides for static extensions, bypass path prefixes and unsafe force targets each place the enable/override checkbox immediately above the associated multiline list. The fields are disabled while their individual override is off; their saved values and cache policy are unchanged. Never enable unsafe forced caching for personalized responses.
Stored object rules
- Reuse is scoped by frontend scheme, Host, exact client URL, Vhost/content policy and eligible
Varydimensions. HTTP and HTTPS objects do not cross-share. - GET and suitable HEAD requests may reuse a full object; changing request methods do not silently invalidate all cached GET results.
- Authorization, dynamic cookies,
Set-Cookie, sticky-affinity cookies, Tinyauth and other private signals normally cause BYPASS. A limited static-file cookie exception exists for configured static extensions and does not overrideprivate,no-store,Set-CookieorVary: Cookie. - Origin status, response size, TTL, unsupported metadata, range/conditional semantics and request/client cache directives can prevent fill or require validation.
- A Web Service selected as a Vhost source uses the same cache policy for eligible local files. File changes can be checked with
ETag/Last-Modified; a 304 validation may refresh a stored body without downloading it again.
Freshness and diagnostics
| State | Interpretation |
|---|---|
MISS |
No suitable fresh cached representation was found; the origin was consulted. The response may still be ineligible for storage. |
HIT |
A matching stored object was reused. |
BYPASS |
Cache was disabled or a policy intentionally skipped it (for example authorization, cookies or a path exclusion). |
| Revalidated | An existing representation was checked against the origin; a 304 can retain the body. |
Age is total HTTP age, not only the time spent in RustProxy. The optional X-Cache-Resident-Age reports the cache residency interval. Debug headers such as X-Cache, X-Cache-Hits and reason labels are optional and should be enabled deliberately. With varnish_compatible=true, browser hard reloads do not force revalidation while an object remains fresh. In strict mode hard reloads can force origin revalidation; compare with curl when investigating.
Example, replacing the listener and Host values with yours:
for n in 1 2 3; do
curl -sS -D - -o /dev/null -H 'Host: app.example.com' \
http://127.0.0.1:8080/public.css
sleep 2
done
Look for cache reason labels including request_cookie, request_authorization, response_cache_control, route_disabled and cache_hit when diagnostic headers are enabled. A MISS alone does not prove the object was admitted to HOT/COLD.
Advanced behavior
- Budget limits: HOT RAM capacity, object count/size, transient fill memory and optional COLD byte/object limits. Configure based on real workload and monitor disk/RSS.
- HOT/COLD movement: entries may be demoted, recovered or expired; a periodic/explicit COLD cleanup is available. Cache storage is not a permanent archive.
- Request collapsing: eligible concurrent MISS requests can share a bounded fill, limiting origin bursts.
- Stale-if-error and refresh: conditional options can help on eligible backend failures, but are not an unconditional stale-serving guarantee. Web Server local-file validation has a distinct policy.
- Compression/transformation: cached variants and validators must remain compatible with client encoding and content-modification settings.
Clear or invalidate content
Authenticated Cache page/API operations can purge selected entries, domains or larger scopes. The optional public HTTP PURGE/BAN interface is disabled by default. Enable it only by listing trusted client IPs/CIDRs under Settings → Cache → HTTP BAN / PURGE IP allowlist; operations are additionally subject to Vhost binding and normal access controls. PURGE addresses an exact URL; BAN applies the supported bounded matching rules. Never allow untrusted Internet clients to purge all tenants' objects.
In 0.34.0, changing operational Vhost settings is intended to preserve compatible HOT/COLD objects; content-affecting changes invalidate affected scopes and COLD carries an additional fingerprint against stale resurrection. This new behavior still needs release-level verification, so validate cache after configuration edits and during upgrades. Earlier persistent cache entries may need refilling following format/compatibility transitions.
Troubleshooting
- Always BYPASS: check both cache enable switches, login/cookies, exclusion rules, methods, Tinyauth and sticky sessions.
- MISS never becomes HIT: check response
Cache-Control, status, object size,Vary,Set-Cookie, incomplete origin streams and whether the same scheme/Host/query is used. - Content unexpectedly old: inspect Age, TTL, validators, stale rules and previous invalidation; purge only affected content after confirming its identity.
- Memory/disk pressure: review HOT/COLD budgets and cleanup, rather than increasing limits without measurements.
See Monitoring for cache telemetry and Security for privacy boundaries.