xmlrpc.php 403 Forbidden

The other day I encountered this error on one of my domains while working on a small project. The endpoint used to work, as I had used it for testing as recently as a month ago so when it stopped working I became annoyed.

There are a few reasons for this to happen and you have probably already tried them, though I will still enumerate them here:

  1. One of your plugins, in particular security plugins, is blocking access to the endpoint (you can check by looking at your .htaccess file or disabling the security plugins)
  2. The file permissions for xmlrpc.php are incorrect (they should be 644)
  3. The .htaccess file has become corrupt (you can check by renaming the current file to something like .htaccess.org then go to dashboard of the WP instance, click on settings, writing, permalinks and click on save. This will re-create the .htaccess file. If it works, then your .htaccess file was corrupt indeed, otherwise, just delete that newly created file and revert to the original)

Obviously, none of these were the issue for me. The problem turned out to be my hosting provider was filtering on xlmrpc.php and returning a 403.

You can confirm this by doing the following:

curl -v https://your-domain/xmlrpc.php

If access to the xmlrpc.php file is being blocked by your hosting provider the response will look like this:

*   Trying 198.54...
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
*  SSL certificate verify ok.
> GET /xmlrpc.php HTTP/1.1
> Host: <your domain>
> User-Agent: curl/7.54.0
> Accept: */*
* HTTP 1.0, assume close after body
< HTTP/1.0 403 Forbidden
< Cache-Control: no-cache
< Connection: close
< Content-Type: text/html
<html><body><h1>403 Forbidden</h1>
Request forbidden by administrative rules.
* TLSv1.2 (IN), TLS alert, Client hello (1):
* Closing connection 0
* TLSv1.2 (OUT), TLS alert, Client hello (1):

The giveaway is in the response headers.

< HTTP/1.0 403 Forbidden 
< Cache-Control: no-cache 
< Connection: close 
< Content-Type: text/html

If the issue is on your WP instance configuration, the response headers will include Apache as the server (like this):

< HTTP/2 405
< content-type: text/plain;charset=UTF-8
< date: Wed, 04 Apr 2018 07:37:10 GMT
< server: Apache
< x-powered-by: PHP/7.0.26
< allow: POST

I contacted my hosting provider and indeed they were filtering on xmlrpc.php. I am not recommending you use or not use xmlrpc, I am simply demonstrating the steps to troubleshoot the error.

How to fix Plex server external access

Recently after installing a new router, I ran into an issue where my Plex server was not accessible from the internet.

The way Plex is setup to work seems to be like: Internet --> External-IP:random-port --> Internal-IP-of-Plex-Server:32400

Originally, I had forgotten to enable port-forwarding on my router for port 32400. The solution seemed simple, enable that port (32400) to my Plex Server’s internal IP and while at it, also enable that random port (which didn’t seem so random at the time). That was a problem.

Enabling the both port causes a problem (not really sure why). So I looked at the option on Plex to set the external port to 32400 with no luck. The solution was the simplest one; only enable port forwarding for port 32400 at the internal network level. Meaning, just turn on port forwarding for port 32400 to the Internal-IP-of-Plex-Server. Leave the rest alone. Do not set an external port and do not enable port forwarding for the random port (even if it does not seem random).

Fixing double NAT on Jazztel DSL and Asus RT AC87U

Recently I purchased an Asus router. Our old Netgear router died and we needed a replacement. The installation was almost plug and play with the new Asus, almost.

After the setup was complete I ran into an issue where the router was reporting a double-NAT issue.

With our previous router I had setup port-forwarding at the DSL modem level. The port forwarding was setup to forward all traffic from ports 1:65000 to the IP address of the Netgear router, something like this: internet --> DSL modem --> port forwarding (1:65000) --> 192.168.1.nnn (local IP of the Netgear router)

That approach solved the double-NAT problem by having all traffic on those ports forwarded to the Netgear router.

However, for better or for worse, because the local IP for the Asus router changed (no longer 192.168.1.nnn, but now 192.168.1.xxx) this still didn’t work (and I didn’t immediately realize it). So as a result I began to dig deeper into the issue.

According to this post, there are three solutions:

  • Setup the DSL modem in bridge-mode (described here)
  • Forward traffic to the Asus router (partly what I had done, minus the oversight on the IP address)
  • Setup the Asus router as a DMZ (similar to forwarding the port traffic, but with less control)

To setup my DSL modem into bridge mode I did the following:

  • Edit the WAN service under: Advanced Setup --> WAN service --> ppp1.1 (that was the one that was enabled for me)
  • Get the password by “editing” the page using FF webtools
    • You will need it later
  • Enable fullcone NAT
  • Enable Bridge PPPoE frames between WAN and local ports
  • Click save and exit

Now you’ll need to update the Asus’s WAN setup to use PPPoE login like this:

  • Go to WAN
  • Under connection type choose PPPoE
  • For PPP user and pass, use those from the DSL modem
  • Under MAC address choose “MAC Clone” (it should pick the MAC of the DSL modem)
  • Click “Apply” and you are done

This solved my double-NAT problem. Now the router got the external IP the DSL modem was getting.

The reality, however, is that I could have just as easily fixed the issue through either port-forwarding and DMZ, but by the time I realized it I was too focused on solving it through the bridge approach.