Blog

How to bypass WordPress plugin repository from blocking your plugin updates

Without wading too much into the Automattic + WPEngine feud it has become evident that the availability of the WordPress plugin repository that allows and facilitates plugin updates across the entire WordPress ecosystem has become a vendetta tool.

Being blocked by WordPress likely means that their systems are checking the source IP address of a web request initiated by a WordPress website when checking for available plugin and core updates. In the case of WordPress blocking all WPEngine customers from updating their plugins, they would likely have included an entire IP address block in order to accomplish this.

There could be other things happening like host header validation and perhaps even environment checking that is happening but for the purposes of this post, I thought I’d outline a few workaround options that would help you bypass these sorts of blocks even as an interim short term solution, or perhaps part of a longer term strategy if confidence in the reliability and professionalism of the people making decisions for an open source project such as WordPress is shaken.

Option 1 : Use nginx as a transparent proxy

The idea with this option is that you are either managing the web hosting environment or have similar root level access in order to facilitate a DNS change to resolve api.wordpress.org to another IP address (the destination of the transparent proxy.)

Here’s how you can configure Nginx to act as a transparent proxy for routing requests from your web host to api.wordpress.org. The goal is to make all requests from your server destined for api.wordpress.org pass through the Nginx proxy before reaching their final destination.

Steps to Set Up a Transparent Proxy to Route Requests to api.wordpress.org

Prerequisites

  • A Linux server with Nginx installed.
  • Root or sudo access to configure Nginx.
  • Your server should be set up to handle outbound requests to api.wordpress.org.
  • Ensure api.wordpress.org is not directly accessible from your server to verify the effectiveness of the proxy (e.g., via firewalls or DNS adjustments).

Step 1: Install Nginx

If Nginx is not installed on your server, you can install it using the package manager for your Linux distribution.

For Debian/Ubuntu:

sudo apt update
sudo apt install nginx

For CentOS/RHEL:

sudo yum install nginx

Step 2: Edit Nginx Configuration

We will configure Nginx to intercept requests to api.wordpress.org and proxy them to the actual destination.

  1. Navigate to the Nginx configuration directory:bashCopy codecd /etc/nginx/sites-available/
  2. Create a new Nginx configuration file specifically for this proxy: For example, you can create a new file called wordpress_proxy.conf.bashCopy codesudo nano /etc/nginx/sites-available/wordpress_proxy.conf
  3. Configure the server block to intercept and forward requests to api.wordpress.org:In this configuration, any request that comes to this server for api.wordpress.org will be forwarded transparently to the real api.wordpress.org endpoint.Example configuration:nginxCopy codeserver { listen 80; server_name api.wordpress.org; # Proxy settings location / { proxy_pass https://api.wordpress.org; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Additional headers can be added here if needed for SSL or other purposes } } Key points:
    • proxy_pass https://api.wordpress.org;: This directive tells Nginx to forward the requests to the actual api.wordpress.org domain over HTTPS.
    • proxy_set_header Host $host;: Passes the original host header so that api.wordpress.org knows it was the intended host.
    • proxy_set_header X-Real-IP $remote_addr;: Passes the original client’s IP address to api.wordpress.org.
    • proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;: Forwards the original client’s IP address through any proxies.
    • proxy_set_header X-Forwarded-Proto $scheme;: Passes the original protocol (HTTP/HTTPS).
  4. Save the file and exit (Ctrl+O, Enter, Ctrl+X in nano).

Step 3: Enable the Proxy Configuration

If you’re using the /sites-available and /sites-enabled structure, you need to enable this configuration by creating a symbolic link:

sudo ln -s /etc/nginx/sites-available/wordpress_proxy.conf /etc/nginx/sites-enabled/

Step 4: Test the Nginx Configuration

Before reloading or restarting Nginx, check if the configuration is valid:

sudo nginx -t

If the test is successful, you should see a message indicating that the configuration is valid.

Step 5: Restart Nginx

After configuring the proxy, restart Nginx to apply the changes:

sudo systemctl restart nginx

To ensure your server routes all requests for api.wordpress.org through the Nginx proxy (instead of directly reaching the destination), you can modify the /etc/hosts file to resolve api.wordpress.org to the local server’s IP.

Edit the /etc/hosts file:

sudo nano /etc/hosts

Add the following line, replacing YOUR_SERVER_IP with your actual server’s IP address where Nginx is running:

YOUR_SERVER_IP api.wordpress.org

This forces your server to resolve api.wordpress.org to the Nginx proxy server instead of directly reaching the real API endpoint.

Step 7: Verify the Proxy is Working

To verify the setup, try making requests to api.wordpress.org using curl or another HTTP client:

curl http://api.wordpress.org

You should see the response from api.wordpress.org, but it will have gone through your Nginx proxy first.

Optional: Set Up HTTPS for the Proxy

To make the proxy more secure, you may want to set up SSL on your Nginx proxy so that it accepts HTTPS requests. You can use Let’s Encrypt to obtain a free SSL certificate for api.wordpress.org on your proxy server:

  1. Install Certbot: sudo apt install certbot python3-certbot-nginx
  2. Obtain and install the SSL certificate: sudo certbot --nginx -d api.wordpress.org

Certbot will automatically configure your Nginx server to use HTTPS.

Conclusion

With this configuration, your Nginx server acts as a transparent proxy that intercepts all requests to api.wordpress.org and forwards them to the real api.wordpress.org server. This setup is useful in situations where you want to control or log the traffic going to specific external destinations, or route traffic through a specific gateway.

It should be worth noting that the nginx proxy can live on a cloud provider such as AWS. If this is the case then you can utilize VPC -> ELB routing of requests to truly have access to a vast array of IP addresses to avoid future blocks.

Option 2: Redirect WordPress Update Requests to Another Hostname with a custom WordPress plugin

In this approach, you modify WordPress’s core functionality by intercepting update requests that normally go to api.wordpress.org and redirecting them to another server that mirrors the same functionality. You can achieve this by creating a custom plugin.

Steps for Creating a Custom Plugin to Redirect Updates:

  1. Create a Custom Plugin: Inside your WordPress installation, create a new folder in wp-content/plugins/ called custom-update-redirect. Inside this folder, create a file called custom-update-redirect.php.
  2. Edit the Plugin File: Add the following code to the file, which will intercept and modify the API request for plugin updates:

    <?php
    /*
    Plugin Name: Custom Update Redirect
    Description: Redirect WordPress plugin updates to a custom update server.
    Version: 1.0
    Author: Your Name
    */

    // Hook into the update request filter to modify the update API endpoint
    add_filter('pre_http_request', 'redirect_plugin_updates', 10, 3);

    function redirect_plugin_updates($pre, $parsed_args, $url) {
    // Check if the request is going to the WordPress plugin update API
    if (strpos($url, 'https://api.wordpress.org/plugins/update-check/1.1/') !== false) {
    // Redirect the update request to your custom update server
    $custom_update_url = 'https://your-custom-update-server.com/plugins/update-check/1.1/';
    $url = $custom_update_url;
    }

    // Allow the request to proceed with the modified URL
    return array(
    'url' => $url,
    'method' => $parsed_args['method'],
    'body' => $parsed_args['body'],
    'headers' => $parsed_args['headers'],
    'timeout' => $parsed_args['timeout'],
    'redirection' => $parsed_args['redirection'],
    'httpversion' => $parsed_args['httpversion'],
    'user-agent' => $parsed_args['user-agent'],
    );
    }


  3. Explanation of the Code:
    • The add_filter('pre_http_request', ...) hook intercepts outgoing HTTP requests before they are sent.
    • The strpos($url, 'https://api.wordpress.org/plugins/update-check/1.1/') checks if the request is destined for the WordPress plugin update API.
    • If the update URL is detected, the request is redirected to a custom update server (in this case, https://your-custom-update-server.com/).
    • This will only work if the custom server is capable of responding with update information in the expected format.
  4. Activate the Plugin: After saving the file, go to your WordPress admin dashboard, navigate to Plugins, and activate the Custom Update Redirect plugin.
  5. Custom Update Server Requirements:
    • The custom server that you point the update requests to must replicate the functionality of api.wordpress.org for plugin updates.
    • This server must return valid responses to plugin update requests in a format that WordPress expects, including plugin version information and download URLs.

Drawbacks:

  • Setting up a custom server to mimic api.wordpress.org is a complex task, as WordPress requires specific responses in terms of plugin updates.
  • You will have to regularly update the server with new plugin versions manually or set up automation to pull updates from another source.

Option 3: Use a Private Plugin Repository

An alternative method is to set up a private plugin repository, which you control. You can host your plugins in this repository and have WordPress retrieve updates from this custom repository instead of api.wordpress.org.

Steps for Creating a Private Plugin Repository:

  1. Set Up a Private Plugin Repository:
    • Create a private repository for your plugins on a web server you control. The repository should host .zip files for each plugin version and provide metadata (such as the plugin version and description).
  2. Modify the WordPress Plugin Update Check:
    • You can hook into WordPress’s plugin update check process and point it to your private repository instead of api.wordpress.org. This is done by using the site_transient_update_plugins filter to modify the update response for specific plugins.
  3. Example Plugin for Private Repository: Create a new plugin that modifies the update endpoint for your private plugins:

    <?php
    /*
    Plugin Name: Private Plugin Updates
    Description: Use a custom plugin repository for updates.
    Version: 1.0
    Author: Your Name
    */
    // Hook into plugin update check
    add_filter('pre_set_site_transient_update_plugins', 'check_for_private_plugin_update');
    function check_for_private_plugin_update($transient) {
    if (empty($transient->checked)) {
    return $transient;
    }
    // Define your private plugin details $plugin_slug = 'your-plugin-slug/your-plugin-file.php'; $repository_url = 'https://your-private-repo.com/plugin-info.json'; // Fetch update information from your private repository $response = wp_remote_get($repository_url); if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) == 200) { $plugin_info = json_decode(wp_remote_retrieve_body($response)); // Check if a new version is available if (version_compare($plugin_info->version, $transient->checked[$plugin_slug], '>')) { $transient->response[$plugin_slug] = (object) array( 'slug' => $plugin_slug, 'new_version' => $plugin_info->version, 'url' => $plugin_info->homepage, 'package' => $plugin_info->download_link, ); } } return $transient;
    }

  4. Explanation of the Code:
    • The pre_set_site_transient_update_plugins hook modifies the update check process for plugins.
    • It fetches update information from your private repository ($repository_url).
    • If a new version is available, it tells WordPress to display the update.
  5. Plugin Info File (plugin-info.json): You need to host a plugin-info.json file in your private repository, containing information about your plugin updates:

    {
    "version": "1.2.0",
    "homepage": "https://your-private-repo.com",
    "download_link": "https://your-private-repo.com/plugins/your-plugin.zip"
    }

  6. Activate the Custom Plugin: After saving and activating the custom plugin in WordPress, your private plugins will receive updates from your private repository instead of api.wordpress.org.

Conclusion:

This approach works well if you control or have access to the plugin repository, and it allows you to bypass the api.wordpress.org server by routing updates through a private or alternative repository.

All of these options offer potential solutions to api.wordpress.org blocking your hosting provider, though the third option (private plugin repository) is generally more sustainable and avoids the complexity of mimicking the WordPress API.