Site icon GetPageSpeed

NGINX Request Cookies Filter Module

NGINX Request Cookies Filter Module: Strip, Rewrite, and Control Cookies

The Problem: Unwanted Cookies Bloat Your Backend Requests

Every time a client visits your website, their browser accumulates cookies — Google Analytics (_ga, _gid), Facebook Pixel (_fbp, _fbc), HubSpot (__hstc, hubspotutk), and many more. When NGINX proxies those requests to your upstream servers, every single cookie travels along, even though your application never needs them. The NGINX request cookies filter module exists to solve exactly this problem.

This causes real issues for production systems:

The Solution: NGINX Request Cookies Filter Module

The NGINX request cookies filter module solves these problems with clean, declarative directives. It lets you strip, rewrite, add, or clear individual cookies in the Cookie request header before the request reaches your upstream server. No regex hacks, no Lua scripts, no fragile workarounds.

Here is what a typical configuration looks like:

location / {
    # Strip tracking cookies your backend doesn't need
    clear_request_cookie _ga;
    clear_request_cookie _gid;
    clear_request_cookie _fbp;

    # Forward only the cookies your app actually uses
    proxy_set_header Cookie $filtered_request_cookies;
    proxy_pass http://backend;
}

With this configuration, your backend receives only the cookies it needs. Tracking cookies never reach your application, your cache starts working again, and your compliance surface shrinks.

How the Request Cookies Filter Works

The module operates on the Cookie request header during variable evaluation. When you reference the $filtered_request_cookies variable, the module:

  1. Parses all Cookie headers into individual name-value pairs
  2. Applies your filter rules in order (set, add, rewrite, clear)
  3. Rebuilds a clean Cookie string from the surviving cookies

You then pass this filtered string to your upstream via proxy_set_header. The original request headers remain untouched — the filtering affects only what gets forwarded.

Installation

RHEL, CentOS, AlmaLinux, Rocky Linux

Install the NGINX request cookies filter module from the GetPageSpeed RPM repository:

sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-request-cookies-filter

Then load the module by adding this line at the top of /etc/nginx/nginx.conf:

load_module modules/ngx_http_request_cookies_filter_module.so;

Debian and Ubuntu

First, set up the GetPageSpeed APT repository, then install:

sudo apt-get update
sudo apt-get install nginx-module-request-cookies-filter

On Debian/Ubuntu, the package handles module loading automatically. No load_module directive is needed.

You can find additional details on the module page.

Directives

The module provides four directives for manipulating request cookies. All directives are valid in http, server, and location contexts. Cookie names are matched case-insensitively.

Syntax: set_request_cookie cookie_name value;

Default:

Context: http, server, location

Sets a cookie to the given value. If the cookie already exists, its value is replaced. If not, it is added. This combines add and rewrite into one operation.

location /app {
    # Always ensure the "source" cookie is set to "nginx"
    set_request_cookie source "nginx";

    proxy_set_header Cookie $filtered_request_cookies;
    proxy_pass http://backend;
}

Syntax: add_request_cookie cookie_name value;

Default:

Context: http, server, location

Adds a cookie only if it does not already exist. If the client already sent a cookie with the same name, this directive is ignored. Use it for setting default values.

location /app {
    # Set a default theme if the client hasn't chosen one
    add_request_cookie theme "light";

    proxy_set_header Cookie $filtered_request_cookies;
    proxy_pass http://backend;
}

Syntax: rewrite_request_cookie cookie_name value;

Default:

Context: http, server, location

Changes an existing cookie’s value. If the cookie does not exist, this directive does nothing. Use it when you need to transform a value without creating new cookies.

location /app {
    # Normalize the session type cookie
    rewrite_request_cookie session_type "standard";

    proxy_set_header Cookie $filtered_request_cookies;
    proxy_pass http://backend;
}

Syntax: clear_request_cookie cookie_name [if=condition];

Default:

Context: http, server, location

Removes a cookie from the request. If the cookie does not exist, this directive does nothing. This is the most commonly used directive for stripping tracking and analytics cookies.

The clear_request_cookie directive supports an optional if= parameter for conditional execution. The cookie is cleared only when the condition variable evaluates to a non-empty, non-zero value.

location /api {
    # Strip common tracking cookies
    clear_request_cookie _ga;
    clear_request_cookie _gid;
    clear_request_cookie _fbp;
    clear_request_cookie _fbc;

    proxy_set_header Cookie $filtered_request_cookies;
    proxy_pass http://api_backend;
}

Conditional clearing example:

You can use the if= parameter with any NGINX variable to conditionally clear cookies. For example, clear tracking cookies only when a query parameter is present:

location /app {
    # Clear the tracking cookie only when ?strip=1 is in the URL
    clear_request_cookie _ga if=$arg_strip;

    proxy_set_header Cookie $filtered_request_cookies;
    proxy_pass http://backend;
}

Variables

$filtered_request_cookies

Contains the rebuilt Cookie header string after all filter rules are applied. Cookies are joined with ; (semicolon and space), following the standard format.

If no filter rules exist in the current context, this variable returns the same value as $http_cookie. This makes it safe to use across locations where some filter cookies and others do not.

Important: You must forward this variable to your upstream with proxy_set_header. Defining filter rules alone does not modify the forwarded cookies:

proxy_set_header Cookie $filtered_request_cookies;

Practical Examples

Strip All Analytics Cookies

This is the most common use case. Remove tracking cookies your backend does not need:

server {
    listen 80;
    server_name example.com;

    location / {
        # Google Analytics
        clear_request_cookie _ga;
        clear_request_cookie _gid;
        clear_request_cookie _gat;

        # Facebook Pixel
        clear_request_cookie _fbp;
        clear_request_cookie _fbc;

        # HubSpot
        clear_request_cookie __hstc;
        clear_request_cookie hubspotutk;
        clear_request_cookie __hssc;
        clear_request_cookie __hssrc;

        proxy_set_header Cookie $filtered_request_cookies;
        proxy_pass http://backend;
    }
}

Improve Proxy Cache Hit Rate

Cookies prevent NGINX from caching by default. Strip unnecessary cookies from static asset requests to let the proxy cache work:

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

server {
    listen 80;
    server_name example.com;

    location /static/ {
        # Remove all cookies for static content
        clear_request_cookie _ga;
        clear_request_cookie _gid;
        clear_request_cookie _fbp;
        clear_request_cookie session;

        proxy_set_header Cookie $filtered_request_cookies;
        proxy_cache app_cache;
        proxy_pass http://backend;
    }

    location / {
        # Keep all cookies for dynamic content
        proxy_pass http://backend;
    }
}

Inject Server-Side Cookies

Add cookies that your backend expects but the client does not provide, like a routing hint or feature flag:

location / {
    # Add a routing cookie for the backend
    add_request_cookie route_hint "$server_addr";

    # Mark requests processed by this instance
    set_request_cookie processed_by "nginx-frontend";

    proxy_set_header Cookie $filtered_request_cookies;
    proxy_pass http://backend;
}

Isolate Cookies per Microservice

In a microservices architecture, prevent cookies from leaking between services. The NGINX request cookies filter lets you control exactly which cookies each backend receives:

upstream auth_service {
    server 10.0.1.10:8080;
}

upstream api_service {
    server 10.0.1.20:8080;
}

server {
    listen 80;

    location /auth/ {
        # Auth only needs session cookies
        clear_request_cookie _ga;
        clear_request_cookie _gid;
        clear_request_cookie _fbp;

        proxy_set_header Cookie $filtered_request_cookies;
        proxy_pass http://auth_service;
    }

    location /api/ {
        # API only needs the token cookie
        clear_request_cookie _ga;
        clear_request_cookie _gid;
        clear_request_cookie _fbp;
        clear_request_cookie session;

        proxy_set_header Cookie $filtered_request_cookies;
        proxy_pass http://api_service;
    }
}

Why Not Use Native NGINX Features?

You might wonder whether NGINX can strip cookies without a module. There are native approaches, but each has significant drawbacks.

The map + Regex Approach

A common workaround uses a map block with regex to strip cookies:

map $http_cookie $cleaned_cookies {
    default $http_cookie;
    "~*(?:^|;\s*)_ga=[^;]+(?:;\s*|$)" "";
}

This breaks quickly with multiple cookies. Regex patterns for cookie strings are brittle — they must handle cookies at the beginning, middle, and end of the header string. They must also deal with varying whitespace and avoid matching substrings.

You can strip all cookies with one directive:

proxy_set_header Cookie "";

However, this is all-or-nothing. You cannot keep the cookies your application needs while stripping only the unwanted ones.

Lua and njs Scripting

Both Lua (OpenResty) and njs can manipulate cookies programmatically. However, they add runtime dependencies and are harder to audit. They are overkill when declarative cookie filtering is all you need. The NGINX request cookies filter module is lighter and purpose-built for this task.

Configuration Inheritance

Directives in a parent context (http or server) are inherited by child contexts. If a child defines its own rules for a cookie, those override the parent for that cookie name. Rules for other cookies are still inherited.

server {
    # These apply to all locations
    clear_request_cookie _ga;
    clear_request_cookie _gid;

    location /analytics {
        # Override: keep _ga for analytics
        # _gid is still cleared (inherited)
        set_request_cookie _ga $cookie__ga;

        proxy_set_header Cookie $filtered_request_cookies;
        proxy_pass http://analytics_backend;
    }

    location /app {
        # Both _ga and _gid are cleared (inherited)
        proxy_set_header Cookie $filtered_request_cookies;
        proxy_pass http://app_backend;
    }
}

Performance Considerations

The NGINX request cookies filter module adds minimal overhead. It processes cookies only when $filtered_request_cookies is evaluated. If you do not reference this variable, no parsing occurs.

The module performs a single pass through the cookie string and rule list. For a typical configuration with 5–10 filter rules, processing time is negligible compared to network latency.

Using NGINX variables in cookie values (e.g., set_request_cookie routing "$upstream_addr") adds a small evaluation cost per request, but this is still extremely fast.

Troubleshooting

Cookies Are Not Being Filtered

The most common mistake is forgetting proxy_set_header. Filter rules alone do not modify the request:

# Wrong — missing proxy_set_header
location /app {
    clear_request_cookie _ga;
    proxy_pass http://backend;
}

# Correct — forward filtered cookies
location /app {
    clear_request_cookie _ga;
    proxy_set_header Cookie $filtered_request_cookies;
    proxy_pass http://backend;
}

Unknown Directive Error

If NGINX reports unknown directive "set_request_cookie", the module is not loaded. Add the load_module directive at the top of nginx.conf, before the events block:

load_module modules/ngx_http_request_cookies_filter_module.so;

Verifying the Filter

Add filtered cookies as a response header for debugging:

location /debug {
    clear_request_cookie _ga;
    set_request_cookie test "hello";

    add_header X-Filtered-Cookies $filtered_request_cookies always;
    return 200 "debug\n";
}

Test with curl:

curl -I -b "_ga=GA1.2.123; session=abc" http://localhost/debug

You should see _ga removed and test=hello added:

X-Filtered-Cookies: session=abc; test=hello

Remove the debug header before deploying to production.

Conclusion

The NGINX request cookies filter module provides a clean, declarative way to control which cookies reach your upstream servers. Whether you need to strip tracking cookies for privacy, improve cache hit rates, or isolate cookies between microservices, this module handles it without scripting or fragile regex patterns.

Install the module from the GetPageSpeed repository for RHEL-based or Debian/Ubuntu systems. The source code is available on GitHub.

D

Danila Vershinin

Founder & Lead Engineer

NGINX configuration and optimizationLinux system administrationWeb performance engineering

10+ years NGINX experience • Maintainer of GetPageSpeed RPM repository • Contributor to open-source NGINX modules

Exit mobile version