1

Pretty straightforward:

I want to only expose routes with the /wp-json prefix so that I can use headless WordPress without exposing the rest of my WordPress site to the internet.

I'm running this on Apache, but haven't yet figured out the proper syntax for .htaccess.

So far I have tried:

<Directory />
    AllowOverride None
</Directory>
<Directory /wp-json*>
    AllowOverride All
</Directory>
<Directory /wp-json*/*>
    AllowOverride None
</Directory>

and

<Directory "/wp-json/">
    Options Indexes MultiViews FollowSymLinks
    AllowOverride None
    Order deny,allow
    Deny from all
    Allow from all
</Directory>

My .htaccess is located inside of the public_html root directory. I'm not sure if I've got the .htaccess in the wrong directory or, if the syntax I'm using just isn't working. Any tips?

EDIT: MrWhite's example worked. I ultimately added another rewrite rule for /wp-admin and my final .htaccess is as follows (note the [F] changes to a [C] on the wp-json RewriteRule):

RewriteEngine on

# Reject any user requests that are not prefixed "/wp-json"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule !wp-json($|/) - [C]
RewriteRule !wp-admin($|/) - [F]

# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

1 Answer 1

2

Try the following mod_rewrite directives instead at the top of your root .htaccess file (before the # BEGIN WordPress section):

# Reject any user requests that are not prefixed "/wp-json"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule !wp-json($|/) - [F]

Requested URLs that are not prefixed /wp-json (or /wp-json/) are rejected with a 403 Forbidden.

The RewriteCond directive that checks against the REDIRECT_STATUS environment variable is to ensure that only requests from the client are blocked and not internally rewritten requests to index.php (the WordPress front-controller). REDIRECT_STATUS is empty on the initial request and set to "200" (as in 200 OK status) after the first successful rewrite.

<Directory />
    AllowOverride None
</Directory>
<Directory /wp-json*>
    AllowOverride All
</Directory>
<Directory /wp-json*/*>
    AllowOverride None
</Directory>

<Directory> and AllowOverride are server-only directives and will trigger a 500 Internal Server Error if used in .htaccess. However, AllowOverride enables/disables .htaccess overrides (it doesn't block access) - which is not what you want to do here (.htaccess overrides are probably already enabled). And /wp-json is not a physical "directory" on the filesystem, so the <Directory> directive does not apply here.

Order deny,allow
Deny from all
Allow from all

Having Deny from all and Allow from all in the same context doesn't really make sense. (You would need to disable access for the root and enable access for the specific URL-path prefix.) However, Order, Deny and Allow are Apache 2.2 directives and you are more likely to be on an Apache 2.4 server. These directives are now deprecated in favour of the Apache 2.4 Require group of directives.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.