NGINX Wordpress REST API not working with allow/deny in location block

6,451

as you requested, I'm posting my comments as an answer:

Instead of using regex (which could be a little slower) you could use a simple location. Also, since the logic to redirect the "pretty" permalinks to the correct PHP file is inside another location directive, you need to copy it to your new custom location:

location /wp-json/ {
    allow x.x.x.x;
    deny all;
    try_files $uri $uri/ /index.php?$args;
}

NOTE: you might need to adjust the actual try_files location

Share:
6,451
manifestor
Author by

manifestor

Updated on September 18, 2022

Comments

  • manifestor
    manifestor almost 2 years

    I'm trying to restrict access to a WordPress REST API with NGINX (it's the main backend server {} block, no proxy):

    location ~ ^/wp-json/ {
        allow x.x.x.x;
        deny all;
    }
    

    The problem is, that WordPress always returns a 404 when trying to access an API endpoint (www.example.com/wp-json/wp/v2/pages e.g.) with that configuration (no matter if it is the browser, which is passing all Cookies and Authorization stuff, or cURL):

    curl -X GET -Ik https://www.example.com/wp-json/wp/v2/taxonomies
    HTTP/2 404
    date: Thu, 17 Jan 2019 12:40:12 GMT
    content-type: application/json; charset=UTF-8
    x-robots-tag: noindex
    x-content-type-options: nosniff
    access-control-expose-headers: X-WP-Total, X-WP-TotalPages
    access-control-allow-headers: Authorization, Content-Type
    

    But once I comment out the location block, I get no errors when I access the site with a browser.

    I'm afraid that happens because I need to pass some HTTP headers for authorization purposes, as I have these HTTP headers in my REQUEST (checked with chrome devtools):

    :authority: www.example.com
    :method: GET
    :path: /wp-json/wp/v2/taxonomies?context=edit&lang=en&_locale=user
    :scheme: https
    accept: application/json, */*;q=0.1
    accept-encoding: gzip, deflate, br
    accept-language: en-US,en;q=0.9
    (!) ---> authorization: Basic crf344...fdfs334
    cache-control: no-cache
    (!) ---> cookie: wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_282...7da; wp-settings-1=mfo...off; wp-settings-time-1=1547726728
    pragma: no-cache
    referer: https://www.example.com/wp-admin/post.php?post=193&action=edit
    (!) ---> x-wp-nonce: df238g3ds2
    

    Could someone help me please in order to configure the location block properly for the WordPress REST API?

    EDIT:

    I managed to get a 200 with cURL if I add the corresponding HTTP headers:

    curl -X GET -H "authorization: Basic c2F...TVY" \
         -H "cookie: wordpress_test_cookie=WP+...7da; \
                     wp-settings-1=mfo...off; \
                     wp-settings-time-1=1547726728"
         -H "x-wp-nonce: df238g3ds2" \
         -H "referer: https://www.example.com/wp-admin/post.php?post=193&action=edit" \
         -I https://www.example.com/wp-json/wp/v2/pages
    

    How could I do the same with the NGINX location block?

    • NuTTyX
      NuTTyX over 5 years
      Why do you use location ~ ^/wp-json/ { instead of simply location /wp-json/ { ? No need to perform regex with that string (it is slower). Also, have you double checked in logs that the IP you are allowing is the same as the one you are using to reach the site?
    • manifestor
      manifestor over 5 years
      @NuTTyX yes I checked the IP. Even if I delete all allow and deny statements I get a 404, if the block is commented out, it works. Thanks for your hint regarding the regex :)
    • NuTTyX
      NuTTyX over 5 years
      Now that I think of it, you must have some directive to translate the short and readable uri into the proper php file in the wordpress. Check in other locations for parameters like try_files and try to replicate them inside your new location directive.
    • manifestor
      manifestor over 5 years
      @NuTTyX yes, thank you! I missed a try_files $uri $uri/ /index.php?$args;. Post it as an answer, I want to give you some points! :)