Blocking abusive User-Agent strings in Nginx can cut scanner noise, reduce log clutter, and stop low-effort scrapers before they waste upstream bandwidth or application capacity.

Nginx exposes client request headers as embedded variables, so the User-Agent header is available as $http_user_agent. A simple if condition in a server block can match that value with a case-insensitive regular expression using ~* and return 403 Forbidden before the request reaches a local application or upstream proxy target.

The User-Agent header is easy to spoof, so this works best as a coarse filter rather than a primary security control. Keep the pattern list narrow, keep the conditional body limited to a simple return, and validate the configuration with nginx -t before reloading so a typo does not break the active site.

Steps to block user agents in Nginx:

  1. Open the target virtual host configuration file in a text editor.
    $ sudoedit /etc/nginx/sites-available/example.conf

    Many packaged installs load site files from /etc/nginx/sites-available/ plus /etc/nginx/sites-enabled/, while other layouts use /etc/nginx/conf.d/ or edit /etc/nginx/nginx.conf directly.

  2. Choose narrow tokens or regular expressions that match only the abusive clients you actually want to stop.

    Broad patterns can block legitimate browsers, uptime checks, or search crawlers that happen to share a substring with a bad client.

  3. Add a User-Agent match rule inside the relevant server block.
    server {
        ##### snipped #####
        if ($http_user_agent ~* (masscan|sqlmap|zgrab|nikto)) {
            return 403;
        }
        ##### snipped #####
    }

    Keep the if block limited to return so the rule stays predictable and easy to audit.

    Replace 403 with 444 to close the connection without sending a response header.

    If several virtual hosts need the same block list, define a shared map in the http block and test the mapped variable inside each server block.

  4. Save the configuration file.
  5. Test the updated Nginx configuration before applying it.
    $ sudo nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
  6. Reload Nginx to apply the new rule without dropping active connections.
    $ sudo systemctl reload nginx

    Use sudo nginx -s reload on systems that do not manage Nginx with systemd.

  7. Send a request with a blocked User-Agent string to confirm the rule returns 403 Forbidden.
    $ curl --include --user-agent 'masscan' http://127.0.0.1/
    HTTP/1.1 403 Forbidden
    Server: nginx/1.24.0 (Ubuntu)
    Date: Thu, 09 Apr 2026 12:42:51 GMT
    Content-Type: text/html
    Content-Length: 162
    Connection: keep-alive
    
    <html>
    <head><title>403 Forbidden</title></head>
    <body>
    <center><h1>403 Forbidden</h1></center>
    <hr><center>nginx/1.24.0 (Ubuntu)</center>
    </body>
    </html>

    Test the real protected hostname instead of 127.0.0.1 when the rule lives in a non-default virtual host.

  8. Send a request with a normal browser-style User-Agent string to confirm legitimate traffic still passes.
    $ curl --head --user-agent 'Mozilla/5.0' http://127.0.0.1/
    HTTP/1.1 200 OK
    Server: nginx/1.24.0 (Ubuntu)
    Date: Thu, 09 Apr 2026 12:42:51 GMT
    Content-Type: text/html
    Content-Length: 24
    Last-Modified: Thu, 09 Apr 2026 12:42:51 GMT
    Connection: keep-alive
    ETag: "69d79ecb-18"
    Accept-Ranges: bytes