Skip to content

Simple nginx module that returns 403 if stat() of specified path succeeds

License

Notifications You must be signed in to change notification settings

mk-fg/nginx-stat-check

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 

Repository files navigation

ngx_http_stat_check module

Description

Simple nginx module that returns HTTP "403 Forbidden" error if stat() of specified path succeeds.

Intended use is trivial djbdns-style filesystem-db blacklisting by any nginx variable set on request, for example $remote_addr (think fail2ban).

Build / install

Module requires source code for same-ish nginx version as it will be loaded by:

% ver=1.16.1 # make sure it matches installed nginx version
% curl -L https://nginx.org/download/nginx-$ver.tar.gz | tar -xz

% cd nginx-$ver
% test -e Makefile || ./configure --with-compat --add-dynamic-module=..
% make modules

% cd objs
% install -m755 -t /usr/lib/nginx/modules/ ngx_http_stat_check.so

Re-run two last bits to rebuild after any code or nginx updates.

Usage

Module adds single "stat_check" directive, which takes path template as its one argument, and is only allowed in "location" context.

load_module /usr/lib/nginx/modules/ngx_http_stat_check.so;
...
location /my-files {
  alias /srv/www/my-files;
  autoindex on;
  stat_check /tmp/blacklist/$remote_addr;
}

This will have module run single stat() call for every request, checking if "/tmp/blacklist/$remote_addr" path exists, returning "403 Forbidden" if that's the case.

For example, if request comes from 1.2.3.4 IP address (be sure to check docs on remote_addr first!), path /tmp/blacklist/1.2.3.4 will be checked, and if exists, any request to /my-files location will be denied for this client.

Any other nginx variables can be used in the same way, including regexp-matched path fragments, mapped or custom-set values.

Why it exists

Intended use is blocking access dynamically to various unwanted http spam and bots on relatively idle servers (see also nginx-access-log-stat-block script).

Regular nginx configuration does not allow that, as it lacks any kind of external/dynamic configuration.

It is however available in a premium Nginx Plus version via "keyval" module via JSON API, and maybe will be merged into open version someday, so be sure to check for that first.

While I don't think that extra per-request stat() might make a difference performance-wise, this module is not intended or tested for/in any kind of high-load environments, and might not be suitable against something like a DDoS attack - use CloudFlare, firewalls, Nginx Plus functionality or whatever dedicated solutions for that.

See "Dynamic blacklisting configuration" blog post here for even more info.

Room for improvement

Items here look like an obvious improvements, mostly for flexibility and unlocking new vast use-cases, but doubt I'll get to these unless will need it myself.

  • Make HTTP error page configurable, e.g. like =403 in try_files directive.
  • Separate more complex directive that respects "root" and "alias" paths.
  • Option to invert exists/missing logic for returning errors.
  • Allow to specify $uri or @named-location to jump to on this condition.
  • Allow/use hashed paths to avoid storing plaintext request info and to allow easy nesting of these on filesystem (instead of having all nodes in one dir).

About

Simple nginx module that returns 403 if stat() of specified path succeeds

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages