Skip to content

nginx-modules/ngx_cache_purge

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

117 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ngx_cache_purge

An nginx module that adds cache purge support for FastCGI, proxy, SCGI, and uWSGI caches. A purge operation removes the cached entry whose key matches the purge request.


Contents


Features

  • Inline purge — dedicated HTTP method (PURGE) with IP access control
  • Separate purge location — 3-arg proxy_cache_purge zone key syntax for regex-captured key purging without a proxy_pass
  • Wildcard / partial purge — trailing * walks the cache directory and removes all matching entries
  • purge_all — removes every entry in the cache zone in one request
  • Background queue — async purge processing with configurable batch size and throttling so purge I/O does not block worker event loops
  • Vary-aware purge — after an exact-key purge, removes all filesystem variants (gzip, Vary header) sharing the same cache key
  • Response typeshtml (default), json, xml, text

Compatibility

nginx status
1.20.x ✓ tested
1.26.x ✓ tested
1.28.x ✓ tested
1.29.x ✓ tested

Older releases back to 1.7.9 compile but are not covered by CI.


Installation

cd /path/to/nginx-source
./configure --add-module=/path/to/ngx_cache_purge
make
make install

Dynamic module:

./configure --add-dynamic-module=/path/to/ngx_cache_purge
make modules

Directives

proxy_cache_purge

Syntax:  proxy_cache_purge on | off | <method> [purge_all] from all | <cidr> ...
         proxy_cache_purge <zone> "<key_expression>"
Default: —
Context: http, server, location

Inline form (from …) — intercepts the named HTTP method on a proxy location and purges the matching cache entry. on is a shorthand for method PURGE; off disables purging. Optionally restrict to a list of CIDR ranges or use from all to allow from any address. Adding purge_all before from empties the entire cache zone regardless of the request URI.

Separate-location form (two arguments) — use inside a dedicated purge location (typically a regex location capturing the cache key). Looks up the cache zone by name and purges the compiled key expression. This form is incompatible with proxy_cache and proxy_pass in the same location.

fastcgi_cache_purge

Syntax:  fastcgi_cache_purge on | off | <method> [purge_all] from all | <cidr> ...
         fastcgi_cache_purge <zone> "<key_expression>"
Default: —
Context: http, server, location

Equivalent to proxy_cache_purge but for FastCGI cache zones configured with fastcgi_cache / fastcgi_cache_path.

scgi_cache_purge

Syntax:  scgi_cache_purge on | off | <method> [purge_all] from all | <cidr> ...
         scgi_cache_purge <zone> "<key_expression>"
Default: —
Context: http, server, location

Equivalent to proxy_cache_purge but for SCGI cache zones configured with scgi_cache / scgi_cache_path.

uwsgi_cache_purge

Syntax:  uwsgi_cache_purge on | off | <method> [purge_all] from all | <cidr> ...
         uwsgi_cache_purge <zone> "<key_expression>"
Default: —
Context: http, server, location

Equivalent to proxy_cache_purge but for uWSGI cache zones configured with uwsgi_cache / uwsgi_cache_path.

cache_purge_response_type

Syntax:  cache_purge_response_type html | json | xml | text
Default: html
Context: server, location

Sets the Content-Type and body format of purge responses. Has no effect on cache-miss responses (412 / 404), which are generated by nginx's built-in error-page renderer.

cache_purge_background_queue

Syntax:  cache_purge_background_queue on | off
Default: off
Context: http

When enabled, wildcard and purge_all purge requests are enqueued and return 202 Accepted immediately; a per-worker background timer drains the queue in batches. Has no effect on exact-key purges, which are always synchronous. When disabled, all purges are processed synchronously in the request handler.

cache_purge_queue_size

Syntax:  cache_purge_queue_size <number>
Default: 1024
Context: http

Maximum number of entries the background queue can hold. Each slot occupies roughly 1–2 KB of shared memory (2048 slots ≈ 3 MB). When the queue is full, new wildcard / purge_all purge requests fall back to synchronous processing. Only meaningful when cache_purge_background_queue on.

cache_purge_batch_size

Syntax:  cache_purge_batch_size <number>
Default: 10
Max:     64
Context: http

Number of queue entries processed per background timer tick. Values above 64 are clamped to 64 at startup (a warning is logged). Reduce this value if purge operations cause iowait spikes; increase it for faster queue drain on fast storage. Only meaningful when cache_purge_background_queue on.

cache_purge_throttle_ms

Syntax:  cache_purge_throttle_ms <milliseconds>
Default: 10
Context: http

Interval between background processing ticks. Also introduces a brief yield every 100 files within a single directory walk to limit I/O pressure. Increase on constrained or spinning-disk storage; decrease on NVMe. Only meaningful when cache_purge_background_queue on.

cache_purge_legacy_status

Syntax:  cache_purge_legacy_status on | off
Default: on
Context: http

Controls the HTTP status code returned when a purge request targets an entry that is not in the cache:

value status on miss
on 412 Precondition Failed
off 404 Not Found

Default is on (412) for backwards compatibility with earlier releases. Set to off to return 404 Not Found, the correct HTTP status for a resource that does not exist (RFC 9110 §15.5.5).

cache_purge_vary_aware

Syntax:  cache_purge_vary_aware on | off
Default: off
Context: http

When on, an exact-key purge walks the cache directory after deleting the primary file and removes any remaining files that carry the same KEY: string. This covers all Vary and gzip_vary variants of a cached response, which are stored at different filesystem paths but share one logical key. The byte immediately after the key string in each file is verified to be \n, preventing false matches against keys that share only a common prefix.

Disabled by default because it adds a full cache directory walk per exact-key purge. Enable it when gzip_vary on or Vary: headers cause multiple cache files to be created for a single logical entry. Wildcard and purge_all purges do not need this option — the walk they already perform catches every variant regardless.


Partial key purge

When the exact cache key is not known — for example because it includes cookie values or query parameters — append * to the key to request a prefix match:

PURGE /images/header*

The * must be the last character of the URI. Ensure $uri appears at the end of proxy_cache_key when using this feature, otherwise the prefix match will not align with the stored key.


Sample configurations

Basic — inline purge method

http {
    proxy_cache_path /var/cache/nginx keys_zone=main:10m;

    server {
        location / {
            proxy_pass        http://backend;
            proxy_cache       main;
            proxy_cache_key   "$host$uri$is_args$args";
            proxy_cache_purge PURGE from 127.0.0.1;
        }
    }
}
curl -X PURGE http://localhost/images/logo.png
# 200 — entry purged
# 412 — entry not in cache  (or 404 with cache_purge_legacy_status off)
# 403 — client IP not in the allowed list

Basic — separate purge location

http {
    proxy_cache_path /var/cache/nginx keys_zone=main:10m;

    server {
        location / {
            proxy_pass      http://backend;
            proxy_cache     main;
            proxy_cache_key "$host$uri$is_args$args";
        }

        # Capture the cache key from the URI and pass it to the 3-arg form.
        # No proxy_pass or proxy_cache required in this location.
        location ~ ^/purge(/.*) {
            allow             127.0.0.1;
            deny              all;
            proxy_cache_purge main "$host$1$is_args$args";
        }
    }
}

Background queue enabled

http {
    proxy_cache_path /var/cache/nginx keys_zone=main:10m;

    cache_purge_background_queue on;
    cache_purge_queue_size        2048;
    cache_purge_batch_size        20;
    cache_purge_throttle_ms       10;

    server {
        location / {
            proxy_pass        http://backend;
            proxy_cache       main;
            proxy_cache_key   "$host$uri$is_args$args";
            proxy_cache_purge PURGE from 127.0.0.1;
        }
    }
}

Purge all entries

http {
    proxy_cache_path /var/cache/nginx keys_zone=main:10m;

    server {
        location /content {
            proxy_pass        http://backend;
            proxy_cache       main;
            proxy_cache_key   "$host$uri$is_args$args";
            proxy_cache_purge PURGE purge_all from 127.0.0.1;
        }
    }
}
curl -X PURGE http://localhost/anything
# 200 — entire cache zone cleared

JSON responses with per-location override

http {
    proxy_cache_path /var/cache/nginx keys_zone=main:10m;

    cache_purge_background_queue on;

    server {
        cache_purge_response_type json;   # default for all locations in this server
        location / {
            proxy_pass        http://backend;
            proxy_cache       main;
            proxy_cache_key   "$host$uri$is_args$args";
            proxy_cache_purge PURGE from all;
        }

        location /admin/purge {
            # Override to plain text for scripting
            cache_purge_response_type text;
            proxy_cache_purge         main "$arg_key";
        }
    }
}

Vary-aware purge

http {
    cache_purge_vary_aware on;
    gzip_vary              on;
}

After purging a key, all gzip and Vary variants stored at different filesystem paths are also removed automatically.


Performance tuning

The appropriate values depend on storage type, cached file count, and purge request rate. The table below gives reasonable starting points.

Environment queue_size batch_size throttle_ms
Small VPS — 1–2 cores, ≤ 2 GB RAM 512 5 25
Mid-range VDS — 4–8 cores, SSD 2048 20 10
Dedicated server — 16+ cores, NVMe 8192 50 5
High purge rate, any hardware 8192 5 50

Queue memory: queue_size × ~1.5 KB. 2048 slots ≈ 3 MB of shared memory.

Throughput ceiling: batch_size ÷ throttle_ms × 1000 purges/sec. At defaults: 10 ÷ 10 × 1000 = 1 000/s. On spinning disk or network storage, keep batch_size low and throttle_ms high to avoid iowait spikes.


Monitoring and debugging

Successful background purges return 202 Accepted. The response body uses the format set by cache_purge_response_type.

Relevant log messages:

Level Condition
warn Queue full; item timed out in queue
error Cache zone not found
crit File deletion failed
tail -f /var/log/nginx/error.log | grep "cache purge"

Troubleshooting

Purge requests block worker processes Enable cache_purge_background_queue on.

Queue full warnings in the log Increase cache_purge_queue_size, or reduce the purge request rate.

High iowait during purges Decrease cache_purge_batch_size and increase cache_purge_throttle_ms.

Queue drains too slowly Increase cache_purge_batch_size and decrease cache_purge_throttle_ms.

412 responses where 404 is expected Set cache_purge_legacy_status off.

Vary / gzip variants remain after purge Enable cache_purge_vary_aware on.


Testing

The test suite uses Test::Nginx.

prove -r t/

Individual suites:

prove t/basic.t
prove t/background_queue.t
prove t/config.t
prove t/memory.t
prove t/performance.t

See t/TESTING.md for Docker-based testing and the full testing guide.


Migration

From the original FRiCKLE module

The module is backwards compatible. No configuration changes are required. To opt in to background processing, add:

http {
    cache_purge_background_queue on;
}

From nginx-selective-cache-purge-module

Replace the module. Background queue functionality is now built in. Map your previous queue parameters to cache_purge_queue_size, cache_purge_batch_size, and cache_purge_throttle_ms.


Security

  • Restrict purge endpoints with allow / deny directives or an upstream authentication layer. Never expose them publicly.
  • Set cache_purge_queue_size to a value appropriate for your traffic to limit shared memory consumption under request floods.
  • Consider pairing purge locations with limit_req to rate-limit purge requests independently of normal traffic.

License

Copyright (c) 2009-2014, FRiCKLE <info@frickle.com>
Copyright (c) 2009-2014, Piotr Sikora <piotr.sikora@frickle.com>
Copyright (C) 2016-2026, Denis Denisov

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in
   the documentation and/or other materials provided with the
   distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.

See also

About

nginx module which support to purge ngx_http_(fastcgi|proxy|scgi|uwsgi)_module cache backend

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

No contributors

Languages

  • C 84.2%
  • Makefile 10.0%
  • Dockerfile 4.1%
  • Shell 1.7%