Restricting HTTP methods at the Nginx edge prevents unexpected verbs from reaching an application, shrinking the exposed surface area and cutting down noisy scanner traffic. A tight method allow-list also makes behavior predictable for static sites, reverse proxies, and APIs that only support a small set of verbs.

Nginx selects a server block for a request, then routes the URI into the best matching location block. The limit_except directive applies an allow-list of methods in a location, and its nested access rules run only when the request method is not in that allow-list.

Method filtering belongs as close as possible to the endpoint that needs it, since broad blocks can break APIs, WebDAV-style clients (PROPFIND), and browser CORS preflight requests (OPTIONS). Always run nginx -t before reloading the service to avoid taking the site offline due to a syntax error.

Steps to restrict HTTP methods in Nginx:

  1. Choose an allow-list of methods that matches the endpoint behavior.

    Common allow-lists: GET + HEAD for static content, GET + HEAD + POST for form handlers, GET + HEAD + POST + PUT + PATCH + DELETE for APIs. Add OPTIONS on endpoints that must pass browser preflight checks.

  2. Open the site’s server block configuration file in /etc/nginx/sites-available.
    $ sudoedit /etc/nginx/sites-available/example.conf

    Layouts without /etc/nginx/sites-available commonly use /etc/nginx/conf.d or edit /etc/nginx/nginx.conf directly.

  3. Add a limit_except block inside the target location to deny every method not on the allow-list.
    location / {
        limit_except GET HEAD {
            deny all;
        }
    }

    Blocking POST breaks logins, forms, and many APIs. Blocking OPTIONS breaks browser CORS preflight.

  4. Save the configuration file.
  5. Test the updated Nginx configuration for syntax errors.
    $ 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 change without dropping active connections.
    $ sudo systemctl reload nginx

    Use

    sudo systemctl restart nginx

    when reload fails due to a module or binary change.

  7. Send a HEAD request to confirm allowed methods succeed.
    $ curl -I http://127.0.0.1/
    HTTP/1.1 200 OK
    Server: nginx
    Date: Tue, 30 Dec 2025 00:25:39 GMT
    Content-Type: text/html
    Content-Length: 20
    Connection: keep-alive
    Keep-Alive: timeout=15
    Vary: Accept-Encoding
    Last-Modified: Mon, 29 Dec 2025 22:23:50 GMT
    X-Cache-Status: STALE
  8. Send a blocked method request to confirm the restriction triggers.
    $ curl -i -X PUT http://127.0.0.1/
    HTTP/1.1 403 Forbidden
    Server: nginx
    Date: Tue, 30 Dec 2025 00:25:39 GMT
    Content-Type: text/html
    Content-Length: 146
    Connection: keep-alive
    Keep-Alive: timeout=15
    Vary: Accept-Encoding
    
    <html>
    <head><title>403 Forbidden</title></head>
    <body>
    <center><h1>403 Forbidden</h1></center>
    <hr><center>nginx</center>
    </body>
    </html>