Updated: 12 October 2026 · Applies to: Nginx 1.28, Apache 2.4.66 and PHP 8.5 (tested on Ubuntu 26.04), Laravel 13.35, Flask 3.1, WordPress 7.1 and IIS (according to Microsoft)
405 Method Not Allowed means the server found the URL but refuses the HTTP method of the request: GET, POST, PUT, DELETE and so on. Nginx shows the same error as 405 Not Allowed. The page exists, but it does not accept that kind of request: most often a form that POSTs to a static page, PHP that Nginx does not hand to PHP-FPM, an API called with the wrong method, or a redirect that turned a POST into a GET. If the response has an Allow header, it lists the methods that do work.
If you are only visiting the site
A 405 is not caused by your browser or connection. Go back and open the page again from the site's own menu rather than reloading after a form was sent. If a form keeps failing, tell the site owner which page and which button gave the error.
Find the cause
- Repeat the request with curl and look at the status and the
Allowheader:curl -si -X POST -d test=1 https://example.com/contact | grep -iE "^HTTP|^allow" curl -si -X OPTIONS https://example.com/api/items | grep -iE "^HTTP|^allow"
- Open the browser's developer tools (F12), Network tab, send the form again and check the request method, the status and whether a 301 or 302 came first.
- Read the access log (
/var/log/nginx/access.logor/var/log/apache2/access.log). This lab log shows the redirect trap described below: a POST got a 301, and the browser-style follow-up GET got the 405:"POST /old-subscribe HTTP/1.1" 301 178 "-" "curl/8.18.0" "GET /php/subscribe.php HTTP/1.1" 405 19 "-" "curl/8.18.0"
What each server and framework does
We sent different methods to Nginx, Apache, PHP and two frameworks on a test server. This is what came back:
Nginx
- POST, PUT, DELETE and OPTIONS to a static file (
.html, or/when the index isindex.html) return405 Not Allowed. GET and HEAD work. Nginx's error page has noAllowheader (lab output, shortened):HTTP/1.1 405 Not Allowed Server: nginx/1.28.3 (Ubuntu) Content-Type: text/html <head><title>405 Not Allowed</title></head>
- A POST to a
.phpfile in a location without a PHP handler also returned 405, because Nginx served the file as a static file. The same request to a location withfastcgi_passto PHP-FPM ran the script. limit_except GET { deny all; }answers other methods with403, not 405.
Apache
- A POST to a static file returned
200, but PUT and DELETE returned405 Method Not AllowedwithAllow: GET,POST,OPTIONS,HEADand the textThe requested method PUT is not allowed for this URL. - TRACE returned 405 because Ubuntu's
security.confsetsTraceEnable Off; that is intended (see disable TRACE in Apache). AllowMethods GET OPTIONS(mod_allowmethods) answers other methods with 405 and logsAH01623: client method denied by server configuration.<LimitExcept GET>withRequire all deniedanswers 403 instead.
PHP, Laravel, Flask and WordPress
- Your own PHP script can send a correct 405 itself:
http_response_code(405); header('Allow: POST');before any output. - Laravel: a GET to a route defined with
Route::postreturned 405 withAllow: POSTand, withAPP_DEBUG=true,The GET method is not supported for route subscribe. Supported methods: POST.With debug off, visitors only see Method Not Allowed. A very common case is an HTML form for aRoute::putorRoute::deleteroute: forms can only send POST, so you getThe POST method is not supported for route profile. Supported methods: PUT.Add@method('PUT')inside the form; Laravel then reads the hidden_methodfield. If the error changes to 419, the CSRF token (@csrf) is missing. - Flask: a GET to a route with
methods=["POST"]returned405 METHOD NOT ALLOWED,Allow: OPTIONS, POSTandThe method is not allowed for the requested URL. - WordPress: opening
xmlrpc.phpin a browser gives 405 withXML-RPC server accepts POST requests only.That is how WordPress's XML-RPC server is written (we checked the 7.1.3 source); nothing is broken.
IIS on Windows Server
According to Microsoft, IIS returns HTTP Error 405.0 - Method not allowed when a POST goes to a page handled by the StaticFile handler, when the request uses a method that does not follow the HTTP specification, or when WebDAV Publishing interferes with PUT requests. For the last case, Microsoft's fix is to remove the WebDAV modules and handlers from web.config, or to remove the WebDAV Publishing feature if you do not use it.
The redirect trap: POST turned into GET
Browsers follow a 301 or 302 after a POST with a GET. In our test, a POST to an address that answered 301 was repeated as GET and ended in 405, while the same POST through a 308 redirect kept its method and got 200. Typical triggers are a form that posts to http:// while the site redirects to https://, a missing or extra trailing slash, or a moved page. Point forms and API clients at the final URL; for an endpoint that must receive POSTs at an old address, redirect with 307 or 308. See redirect HTTP to HTTPS and 301, 302, 307 and 308 explained.
Fix it
- Use the right method. Check the
Allowheader or the API documentation and send GET, POST, PUT or DELETE as listed. - Send forms to a script, not a page. A form's
actionmust point at something that processes it (a PHP file, an application route or a form service), not at an.htmlpage. - On Nginx, connect PHP. Make sure the
locationthat serves the file passes.phpto PHP-FPM, then runsudo nginx -t && sudo systemctl reload nginx. - On Apache, check the method rules. Look for
AllowMethodsin the virtual host or.htaccess; the error log names the denied method. - In your application, allow the method on the route if it should be accepted:
Route::match(['get', 'post'], ...)in Laravel,methods=["GET", "POST"]in Flask. - Remove redirects from the request path by calling the final
https://URL directly.
If you get 403 instead of 405, the method is blocked by an access rule such as limit_except, LimitExcept or a security filter, not by the page itself. Stuck with a custom application? Our engineers can look at it through Hire an Expert.
Official documentation: MDN: 405 Method Not Allowed and Microsoft: HTTP 405.0 errors in IIS.