Implementing Negative File Matching in Apache 2: Excluding “ban” Files from Hotlink Protection


2 views

When configuring Apache's hotlink protection, we often need to apply rules to most files while excluding specific patterns. The standard directive works well for positive matching, but what about negative cases?

The directive only supports positive pattern matching. For example:


    deny from env=hotlink

This blocks hotlinking for all matched extensions, but provides no built-in way to exclude files containing "ban" in their names.

The most elegant solution is to modify your regex pattern to include a negative lookahead:


    deny from env=hotlink

This pattern will match image files that don't contain "ban" in their names. The (?

If you prefer not to use complex regex, you can combine multiple directives:


    
        deny from env=hotlink
    

This uses Apache's expression syntax to add a negative condition within the FilesMatch block.

The regex solution generally performs better as it's evaluated at a lower level in Apache's processing chain. For high-traffic servers, benchmark both approaches to determine which works better in your environment.

Always test changes with:

apachectl configtest

And verify the behavior with different file names:

  • test.jpg (should be blocked)
  • banner.jpg (should be allowed)
  • adban.jpg (should be allowed)

Apache's directive is powerful for applying rules to specific file patterns, but sometimes we need the inverse logic - applying rules to all files except certain patterns. The original example shows this common scenario:


    deny from env=hotlink

Apache doesn't have a native directive, but we can achieve the same result using regex negative lookaheads:


    
        deny from env=hotlink
    

Alternatively, using pure regex:


    deny from env=hotlink

For more complex exclusions:

# Exclude multiple patterns

    
        deny from env=hotlink
    


# Case-insensitive exclusion

    
        deny from env=hotlink
    

When implementing negative matches:

  • The regex negative lookahead approach ((?) is generally more performant
  • Avoid overly complex regex patterns that might impact server performance
  • Consider using containers for static exclusions when possible

For more control, you might consider:

# Using SetEnvIf for more complex logic
SetEnvIf Request_URI "\.(gif|jpg|jpeg|png|mpg|avi)$" is_media
SetEnvIf Request_URI "ban" is_banner
deny from env=is_media=1 env=!is_banner

This approach separates the matching logic from the action, making the configuration more maintainable.