How to Restrict Nginx Directory Access Based on Custom HTTP Headers


4 views

As a developer with a dynamic IP address, I frequently face the challenge of securing access to my development server. Whitelisting IPs becomes impractical when my public IP changes daily. Apache's SetEnvIf provided an elegant solution by checking custom headers, but how can we achieve similar functionality in Nginx?

Nginx's map directive offers a powerful way to create conditional variables based on request headers. Here's how to implement header-based access control:


map $http_x_custom_auth $is_allowed {
    default 0;
    "secret-token-123" 1;
}

server {
    listen 80;
    server_name dev.example.com;
    
    location /protected/ {
        if ($is_allowed = 0) {
            return 403;
        }
        # Your regular configuration here
    }
}

For simpler cases, you can use Nginx's if directive directly:


location /private/ {
    if ($http_x_my_header != "expected-value") {
        return 403;
    }
    # Rest of your configuration
}

While this method is convenient, consider these security enhancements:

  • Combine with basic authentication for multi-factor security
  • Use HTTPS to prevent header sniffing
  • Rotate your secret token periodically

To test your setup, you can add custom headers using browser extensions or curl:


curl -H "X-Custom-Auth: secret-token-123" https://dev.example.com/protected/

For team access, you can validate against multiple possible values:


map $http_x_dev_access $valid_user {
    default "";
    "dev1-pass" "developer1";
    "dev2-pass" "developer2";
}

server {
    # ...
    location /team/ {
        if ($valid_user = "") {
            return 403;
        }
        # Log access by developer name
        access_log /var/log/nginx/team_access.log combined;
        add_header X-Developer $valid_user;
    }
}

Many developers working with dynamic IP addresses face the challenge of securely accessing development servers. While IP-based restrictions are common, they become impractical when your IP changes frequently. The Apache approach using SetEnvIf to check custom headers provides an elegant solution, and here's how to implement similar functionality in Nginx.

The key directive we'll use is if combined with $http_ variables that represent request headers. For a header named X-Secret-Token, Nginx exposes it as $http_x_secret_token (note the lowercase conversion).

location /protected/ {
    if ($http_x_secret_token != "your-secret-value") {
        return 403;
    }
    # Your normal configuration for the protected area
    try_files $uri $uri/ =404;
}

For better security and flexibility, consider these enhancements:

map $http_x_dev_access $is_allowed {
    default 0;
    "sup3rS3cr3t!" 1;
}

server {
    # ... other server configuration ...
    
    location /dev/ {
        if ($is_allowed = 0) {
            return 403;
        }
        
        # Development configuration
        autoindex on;
        # ... other dev-specific settings ...
    }
}

Here's a complete configuration snippet for a development environment:

http {
    # Define header validation at http level for reuse
    map $http_x_dev_auth $valid_dev {
        default "";
        "Bearer dGVzdDEyMzQ=" "authorized"; # Base64-encoded token
    }

    server {
        listen 80;
        server_name dev.example.com;

        location / {
            if ($valid_dev != "authorized") {
                return 401 'Authentication Required';
            }

            root /var/www/dev;
            index index.html;
            autoindex on;
        }
    }
}
  • Always use HTTPS when implementing header-based authentication
  • Consider combining with basic auth for additional security
  • Rotate your secret tokens periodically
  • Log failed attempts to monitor for brute force attacks

For more complex scenarios, you might consider:

  1. Nginx's auth_request module
  2. Lua scripting with OpenResty
  3. Third-party modules like nginx-auth-ldap