Directive mapping

NGINX directivebouine configNotes
proxy_cache_path ... max_size=1gstorage.hot_max_bytes: 1GiBbouine uses in-RAM storage, no filesystem levels
proxy_cache_path ... keys_zone=api:10mNot neededbouine manages shard count automatically (N=NumCPU)
proxy_cache_valid 200 60sroutes[].cache.ttl_default: 60sPer-route, respects Cache-Control by default
proxy_cache_valid 404 10sroutes[].cache.negative_ttl: 10sNegative caching for error responses
proxy_cache_use_stale error http_500 http_502 http_503 http_504routes[].cache.stale_if_error: 30sServes stale on origin 5xx or timeout
proxy_cache_background_update onroutes[].cache.stale_while_revalidate: 10sBackground revalidation while serving stale
proxy_cache_revalidate onBuilt-inConditional requests (If-None-Match, If-Modified-Since)
proxy_cache_key $scheme$host$request_uriAutomaticxxhash128 of scheme+host+path+sorted query
proxy_cache_key $scheme$host$request_uri$http_acceptcache.key.include_headers: [Accept]Explicit header keying
proxy_ignore_headers Varycache.key.include_headers: [...]Explicit header keying instead of Vary
proxy_no_cache $variableroutes[].cache.enabled: falsePer-route disable
proxy_cache_bypass $variableNot neededUse route matching to separate cached/uncached
proxy_cache_lock onBuilt-in (request collapsing)Single-flight per cache key
proxy_cache_lock_timeout 5sBuilt-inSubscribers wait for leader fetch
proxy_cache_min_uses 3Not neededbouine caches on first response (RFC 9111)
add_header X-Cache-Status $upstream_cache_statusBuilt-inX-Cache header (HIT, MISS, STALE, BYPASS, REVALIDATED)
proxy_next_upstream error timeoutupstream_pools[].health.passivePassive health checks with outlier ejection
upstream backend { keepalive 32; }upstream_pools[].connect.max_idle_conn_duration: 60sDurée de vie des connexions inactives vers l’origine. Gardez la valeur de bouine en dessous de tout timeout inactif de LB entre bouine et l’origine (ex. AWS NLB 350s) pour que bouine ferme les connexions inactives en premier.
keepalive_timeout 65slisten.idle_timeout: 65sTimeout keep-alive inactif des connexions côté client. Gardez la valeur du frontal en dessous de celle de bouine pour que le frontal ferme les connexions inactives en premier ; sinon bouine peut fermer une connexion en cours de réutilisation et l’upstream journalise upstream prematurely closed connection.

Key differences

  • No zone configuration — bouine manages memory automatically with SIEVE eviction
  • No filesystem cache — bouine uses in-RAM hot tier + mmap warm tier (no proxy_cache_path on disk)
  • Clustering built-in — NGINX requires third-party modules for cache sharing; bouine has gossip + peer fetch
  • RFC 9111 native — bouine implements the spec directly, not via directives
  • Observability built-in — Prometheus /metrics, structured JSON access logs with cache_status
  • No proxy_pass needed — upstream pools are declared separately and referenced by name in routes
  • Declarative config — no if blocks, no map directives, no embedded Lua

Example: API gateway

NGINX:

proxy_cache_path /var/cache levels=1:2 keys_zone=api:10m max_size=1g;

server {
    location /api/ {
        proxy_cache api;
        proxy_cache_valid 200 60s;
        proxy_cache_use_stale error http_500 http_502;
        proxy_pass http://backend;
    }
}

bouine:

listen:
  http: ":80"
  admin: ":9000"
storage:
  hot_max_bytes: 1GiB
upstream_pools:
  - name: backend
    targets: [backend:8080]
routes:
  - match: { path_prefix: /api/ }
    pool: backend
    cache:
      ttl_default: 60s
      stale_if_error: 30s

Example: Static site with long TTLs

NGINX:

proxy_cache_path /var/cache levels=1:2 keys_zone=static:10m max_size=2g;

server {
    location /assets/ {
        proxy_cache static;
        proxy_cache_valid 200 1y;
        proxy_cache_lock on;
        add_header X-Cache-Status $upstream_cache_status;
        proxy_pass http://origin;
    }

    location / {
        proxy_cache static;
        proxy_cache_valid 200 10m;
        proxy_pass http://origin;
    }
}

bouine:

listen:
  http: ":80"
  admin: ":9000"
storage:
  hot_max_bytes: 2GiB
upstream_pools:
  - name: origin
    targets: [origin:8080]
routes:
  - match: { path_prefix: /assets/ }
    pool: origin
    cache:
      ttl_default: 8760h  # 1 year
  - match: {}
    pool: origin
    cache:
      ttl_default: 10m

Example: Multiple backends with health checks

NGINX:

upstream backend {
    server backend1:8080 max_fails=3 fail_timeout=30s;
    server backend2:8080 max_fails=3 fail_timeout=30s;
}

server {
    location / {
        proxy_pass http://backend;
        proxy_next_upstream error timeout http_502 http_503;
    }
}

bouine:

upstream_pools:
  - name: backend
    targets: [backend1:8080, backend2:8080]
    health:
      active:
        path: /healthz
        interval: 10s
        timeout: 2s
        unhealthy_threshold: 3
      passive:
        consecutive_5xx: 3
        eject_for: 30s
routes:
  - match: {}
    pool: backend
    cache:
      ttl_default: 60s

Behavioral differences

BehaviorNGINXbouine
Caching by defaultOpt-in (proxy_cache directive)Opt-in (cache.enabled: true per route)
Cache keyManual (proxy_cache_key)Automatic (scheme+host+path+sorted query)
Vary headerIgnored by default (proxy_ignore_headers Vary is common)Honored by default (RFC 9111)
Set-Cookie responsesCached by defaultNot cached by default (opt-in per route)
Authorization requestsCached if response allowsNot cached unless response has public or s-maxage (RFC 9111 §3.5)
Stale servingRequires proxy_cache_use_stale directivestale_if_error and stale_while_revalidate per route
Negative cachingVia proxy_cache_valid 404 10snegative_ttl per route
Response header$upstream_cache_status (MISS, HIT, EXPIRED, STALE, UPDATING, REVALIDATED, BYPASS)X-Cache (HIT, MISS, STALE, BYPASS, REVALIDATED)

Migration gotchas

  1. Vary is honored by default in bouine — if your NGINX config ignores Vary (common for performance), check that your Vary responses won’t create excessive variants. Use cache.key.include_headers for explicit header keying instead of Vary.

  2. Set-Cookie responses are not cached by default — NGINX caches them. If you need Set-Cookie caching, set cache.allow_set_cookie: true per route.

  3. No proxy_cache_path on disk — bouine’s warm tier uses mmap-backed segments, not filesystem cache files. The warm tier is optional and configured via storage.warm_dir.

  4. No if blocks — NGINX configs often use if for conditional cache behavior. In bouine, use separate routes with different match conditions and cache policies.

  5. Clustering changes the cache model — in NGINX, each instance has an independent cache. In bouine strong mode, the consistent hash ring routes each URL to one owner node. This improves hit rates but requires peer fetch for non-owner nodes.