Skip to content

Nginx /traefik endpoint returns unexpected status codes 304 and 412 #75

@subDesTagesMitExtraKaese

Description

Using this docker-compose config:

services:
   geoipfilter:
      image: mpdcampbell/traefik-geoip-filter
      container_name: geoipfilter
      volumes:
         - ./goeip:/geoip
      ports:
         - 8080:8080
      environment:
         - MAXMIND_ID=yourIDhere
         - MAXMIND_KEY=yourKeyhere
         #Set the filter to act as an allowlist or blocklist
         - FILTER_TYPE=block
         - COUNTRY_CODES=FR
         - BLOCK_STATUS_CODE=403

The /traefik location is intended to return only 200 (or 403 when the request IP matches $inIPList).

location /traefik {
    add_header Content-Type "default_type text/plain";
    if ($inIPList = 1) {
        return 403;
    }
    return 200;
}

But there are some edge cases in which other HTTP status codes are returned, which messes with the Traefik filter. Traefik is relying on a strict 200/403 response and misinterprets the additional status codes, causing authorization failures.

Test setup

#!/usr/bin/env bash

BASE_URL="http://localhost:8080/traefik"

run_test() {
    local description="$1"
    shift  # move command-line arguments to the left
    local http_code
    http_code=$(curl -s -o /dev/null -w "%{http_code}" "$@")
    printf "%-45s → %s\n" "$description" "$http_code"
}

run_test "200 OK (plain request)" -i "$BASE_URL"

run_test "200 OK (If-Modified-Since)" \
    -i -H "If-Modified-Since: $(date -R)" "$BASE_URL"

run_test "304 Not Modified (If-None-Match: *)" \
    -i -H 'If-None-Match: *' "$BASE_URL"

run_test "412 Precondition Failed (If-Match)" \
    -i -H 'If-Match: "non-existent-etag"' "$BASE_URL"

run_test "412 Precondition Failed (If-Unmodified-Since)" \
    -i -H "If-Unmodified-Since: $(date -d '1 day ago' -R)" "$BASE_URL"

run_test "403 X-Forwarded-For France is Blocked" \
    -i -H "X-Forwarded-For: 1.178.90.1" "$BASE_URL"

Observed behavior

200 OK (plain request)                        → 200
200 OK (If-Modified-Since)                    → 200
304 Not Modified (If-None-Match: *)           → 304
412 Precondition Failed (If-Match)            → 412
412 Precondition Failed (If-Unmodified-Since) → 412
403 X-Forwarded-For France is Blocked         → 403

Expected behavior

Only 200 (when $inIPList = 1) or 404 (otherwise). No conditional GET or precondition handling should affect the response.

Possible cause

Nginx’s built‑in conditional request handling (e.g., if_modified_since, if_none_match, if_match, if_unmodified_since) is automatically applied when the response body is empty or when certain headers are present, overriding the explicit return directives.

Suggested fix

Strip all headers except X-Forwarded-For using nginx as a proxy to itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions