How to Fix 405 Method Not Allowed Error for POST Requests in Nginx/PHP Applications


5 views

Every backend developer has encountered the frustrating 405 error at some point. What makes this particular case interesting is that:

GET /formcheck - Works perfectly
POST /formcheck - Returns 405 (Method Not Allowed)

The 405 status code indicates that while the server knows about the requested method (POST in this case), it's explicitly disabled for that particular resource. In our scenario with Winginx/Nginx, several potential causes emerge:

  • Nginx configuration blocking POST requests
  • PHP handler misconfiguration
  • Missing or incorrect location block directives
  • File permissions preventing write operations

First, let's check the relevant Nginx configuration section. A proper setup should include:

location ~ \.php$ {
    try_files $uri =404;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
    # Explicitly allow POST
    if ($request_method = POST ) {
        set $test P;
    }
    if ($test = P) {
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    }
}

Sometimes the issue lies with PHP-FPM. Verify your php-fpm.conf contains:

; Ensure these values are properly set
security.limit_extensions = .php
request_terminate_timeout = 300

Here's how to properly structure your jQuery POST request to avoid common pitfalls:

$.ajax({
    url: '/formcheck',
    type: 'POST',
    dataType: 'json',
    data: {
        username: 'testuser',
        email: 'test@example.com'
    },
    headers: {
        'X-Requested-With': 'XMLHttpRequest'
    },
    success: function(response) {
        console.log(response);
    },
    error: function(xhr) {
        console.log('Error:', xhr.statusText);
    }
});

Your formcheck.php should begin with proper headers and method verification:

<?php
header('Content-Type: application/json');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $input = json_decode(file_get_contents('php://input'), true);
    // Process data
    echo json_encode(['status' => 'success']);
} else {
    header('HTTP/1.1 405 Method Not Allowed');
    echo json_encode(['error' => 'Method not supported']);
}
?>

After implementing these changes, clear all caches and restart services:

# For Nginx
sudo nginx -t
sudo systemctl restart nginx

# For PHP-FPM
sudo systemctl restart php-fpm

The HTTP 405 "Method Not Allowed" error occurs when the server understands the request method (POST in this case) but has been configured to reject it for the specific resource. In your Nginx logs, we see repeated instances of:

127.0.0.1 - - [07/Jun/2017:15:14:06 +0300] "POST /formcheck HTTP/1.1" 405 575

In Winginx/Nginx environments, this typically happens because:

  • The location block doesn't explicitly allow POST methods
  • PHP-FPM isn't properly configured to handle POST requests
  • Missing try_files directive for front controller pattern
  • Rewrite rules interfering with request methods

Here's how to modify your Nginx configuration:

location /formcheck {
    try_files $uri $uri/ /formcheck.php?$query_string;
    allow GET;
    allow POST;  # Explicitly allow POST
    deny all;
    
    # PHP handler configuration
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass 127.0.0.1:9000;
}

Ensure your formcheck.php properly handles POST requests. Example structure:

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Process form data
    $data = $_POST['field_name'] ?? null;
    // Validation and processing logic
    header('Content-Type: application/json');
    echo json_encode(['status' => 'success']);
    exit;
}
?>

Here's a proper jQuery implementation that should work with the above setup:

$.ajax({
    url: '/formcheck',
    type: 'POST',
    data: {
        field_name: $('#inputField').val()
    },
    success: function(response) {
        console.log('Server response:', response);
    },
    error: function(xhr) {
        console.error('Error:', xhr.statusText);
    }
});

Use these curl commands to test your endpoint:

# Test GET (should work)
curl -i http://localhost/formcheck

# Test POST (should return 200 after fixes)
curl -i -X POST http://localhost/formcheck -d "test=data"
  • Verify file permissions on formcheck.php
  • Check Nginx error logs for more detailed messages
  • Ensure no security plugins/modules are blocking POST requests
  • Test with Postman or similar tools to isolate client-side issues