Caching behavior¶
The charm uses nginx to cache static content from upstream backends. Understanding how nginx fetches, stores, and expires cached responses helps operators predict behavior and plan capacity, especially when caching large binary files such as Ubuntu ISO images.
How caching works¶
Cache miss: first request for a URL¶
When nginx receives a request for a URL that is not in the cache, it forwards the request to an upstream backend. As the response arrives, nginx simultaneously:
Streams the response body to the client.
Writes the response body to disk at
/data/nginx/cache/<hostname>/.
The charm sets
use_temp_path=off
on proxy_cache_path, so nginx writes directly to the final cache location during the
download. There is no intermediate temporary file.
Cache hit: subsequent requests¶
Once a response is cached on disk, nginx serves it directly from disk without contacting the upstream backend. The client receives the response faster, and the backend sees no load.
Cache expiry and eviction¶
Two independent mechanisms remove cached responses.
TTL expiry: The proxy-cache-valid configuration on content-cache-backends-config
sets how long a cached response is considered fresh. For example, 200 1d means a cached
200 response is valid for one day. After the TTL expires, the next request for that URL
triggers a fresh upstream fetch.
Inactive eviction: nginx also tracks when each cache entry was last accessed. If a
cached response is not requested within the
inactive
period, nginx evicts it from disk regardless of its TTL. The charm does not override this
parameter, so the nginx default of 10 minutes applies. A cached file that receives no
requests for 10 minutes is removed from disk, even if its TTL has not yet expired.
These two mechanisms are independent. The inactive timeout can evict a response before its TTL expires, and a long TTL does not prevent eviction if the content is not accessed.
There is currently no charm configuration option to change the inactive timeout directly.
Upstream cache headers¶
nginx evaluates upstream response headers before applying proxy_cache_valid. As documented
in proxy_cache_valid,
response headers take higher priority:
X-Accel-Expires: sets the cache TTL in seconds; overridesproxy_cache_valid.Cache-ControlorExpires: used to determine TTL whenX-Accel-Expiresis absent.Set-Cookie: if present, the response is not cached, regardless ofproxy_cache_valid.Vary: *: if present, the response is not cached.
The charm does not set
proxy_ignore_headers,
so these defaults apply. Backends that send Cache-Control: no-store or Set-Cookie on
responses intended to be cached will silently bypass the cache.
The inactive
timeout applies to all cached entries regardless of their upstream cache headers. A response
cached with Cache-Control: max-age=86400 is still evicted if it receives no requests within
the inactive window.
Concurrent first-hit requests¶
The charm does not enable
proxy_cache_lock.
When multiple clients simultaneously request the same uncached URL, nginx
starts a separate upstream fetch for each request rather than having the first fetch complete
while the rest wait.
For small files this behavior is usually acceptable. The window of concurrent cache misses is brief and the bandwidth consumed is modest. For large files the impact is more significant (see the next section).
Large-file considerations¶
The behaviors above are amplified when caching large binary files such as Ubuntu ISO images. Each file can be several gigabytes.
Disk capacity¶
The charm does not set max_size or min_free on
proxy_cache_path.
nginx’s cache manager only performs LRU eviction when one of those parameters is configured —
without them, it has no threshold to act on. nginx will therefore cache files until the
filesystem is full, with no automatic cleanup.
Operators should:
Provision a dedicated large volume mounted at
/data/nginx/cache/before deploying for large-file caching.Monitor disk usage and set up alerts before the filesystem fills up.
When the disk fills up, nginx fails to write new cache entries. Existing cached files remain accessible, but requests for uncached files will fail if nginx cannot write the response to disk during the upstream fetch.
Inactive eviction impact¶
For files accessed periodically (for example, ISO images downloaded during machine provisioning runs), the 10-minute inactive timeout may cause repeated upstream re-fetches. Each re-fetch transfers the full file again from the upstream backend.
Concurrent first-hit bandwidth¶
Without proxy_cache_lock, multiple concurrent first-hit requests for the same uncached
large file each trigger a separate upstream fetch. For a multi-gigabyte file, this multiplies
upstream bandwidth consumption during the caching window. Once the file is fully cached, all
subsequent requests are served from disk. The concurrent-fetch problem only affects the window
before the file is fully stored.