YahnisElsts / plugin-update-checker

A custom update checker for WordPress plugins. Useful if you don't want to host your project in the official WP repository, but would still like it to support automatic updates. Despite the name, it also works with themes.
MIT License
2.22k stars 403 forks source link

Checker & Server on same WP site: Download failed (503 Service unavailable) #489

Closed ddur closed 2 years ago

ddur commented 2 years ago

Hi,

When update server and plugin (with update checker) are on same WP site, cannot get ?action=download working (503 Service unavailable) Any idea?

Thanks.

YahnisElsts commented 2 years ago

Here are some ideas:

YahnisElsts commented 2 years ago

Also - check if there's a firewall/IDS that might be blocking local requests.

ddur commented 2 years ago

Here are some ideas:

* Make sure that you're using the latest version of `plugin-update-checker`. There used to be a compatibility issue related to downloading updates from the same server, but it was fixed a while ago. Old versions might still be affected.

Yes, I'm using latest version. What was the issue then?

* Does the download link work fine if you open it in the browser?

Can't test download with browser because of required authorization, but it should work and did work without authorization because browser request is not from same WP site/IP. But ?action=get_metadata does work in browser and from update checker on same WP site. Action=download does work from another WP site, no "problemo".

* Does the webserver log  - e.g. the Apache error log - have any more details about this error?

Nothing in error logs, only 503 in access logs, same on Apache and Nginx. Based on earlier experience, tried to close PHP session, but no success.

YahnisElsts commented 2 years ago

If I remember correctly, the issue was that WordPress intentionally blocks local HTTP requests. Some discussion here: https://wordpress.stackexchange.com/questions/123307/how-do-i-use-the-http-request-host-is-external-filter

There's a filter that lets plugins override that restriction. plugin-update-checker uses that filter now. Since you can see the requests in the access log, this is probably not the problem.

Anything in wp-update-server logs? If not, it might be that the requests never reach the PHP script, which would suggest that it's an issue on the webserver level.

ddur commented 2 years ago

Anything in wp-update-server logs? If not, it might be that the requests never reach the PHP script, which would suggest that it's an issue on the webserver level.

No logs there

Maybe this has something to do with receiving and sending on same IP and/or latest WP? Long time a go I had similar issue and did some local-IP/127.. request by using Host: header, it worked, but original download request code is deep in WordPress core, hard to replace.

Yes I tried \add_filter( 'block_local_requests', '__return_false' ); No success.

Also - check if there's a firewall/IDS that might be blocking local requests.

AFAIK, that is not the case. Nothing stands between local/net request and localhost. I built both servers. One is in local network, another in cloud VPS.

Thanks. I will let you know if/when I find or fix the cause. :+1:

YahnisElsts commented 2 years ago

Just to note: If you can see the request in the access log, I think that proves that WordPress allowed the request to be sent. So you can at least rule out that particular problem.

ddur commented 2 years ago

Yeah. That also means that there is no blocking firewall rule from/to localhost.

Only difference between (working) get-metadata and (failed) download action is actually plugin.zip response, receive plugin.zip, download (save) and plugin upgrade which all together may require larger memory resources. Lack of the memory usually does not allow server to return detailed error code.

Fix: When request for get-metadata comes from same Site URL, instead of download URL, provide plugin absolute path to metadata->downloadUrl.

In derived generateDownloadUrl( $package ) do something like:

if ( $request->wpSiteUrl === home_url() ) {
    return $package->getFilename();
}
return parent::generateDownloadUrl( $package );