nginx / unit

NGINX Unit - universal web app server - a lightweight and versatile open source server that simplifies the application stack by natively executing application code across eight different programming language runtimes.
https://unit.nginx.org
Apache License 2.0
5.27k stars 324 forks source link

Wordpress is unable to perform loopback requests #1041

Closed lillian-b closed 6 months ago

lillian-b commented 6 months ago

I run a wordpress server under Unit, and the site health check does not seem to be able to connect back to itself.

When testing the REST API, an error was encountered:

REST API Endpoint: https://hacklab.to/wp-json/wp/v2/types/post?context=edit
REST API Response: (http_request_failed) cURL error 28: Operation timed out after 10001 milliseconds with 0 bytes received
image

However, if I su to the unit user and try to curl that same endpoint, it works:

[root@public ~]# su unit -s /bin/bash -c 'curl https://hacklab.to/wp-json/wp/v2/types/post?context=edit'
{"code":"rest_forbidden_context","message":"Sorry, you are not allowed to edit posts in this post type.","data":{"status":401}}

So there is something inside the Unit/PHP process that causes this issue. How can I debug this? I cannot find any logs related to this issue (I do see other logs from Unit and Wordpress).

callahad commented 6 months ago

@javorszky I know you've been poking at WordPress on Unit recently... in your test deployments do the health checks in the WordPress dashboard all work?

@lillian-b Are you able to share your Unit configuration, and how you're installing / running Unit?

lillian-b commented 6 months ago

config.json

I installed Unit via packages on Rocky Linux, and it's just running via systemd.

javorszky commented 6 months ago

Thanks for this @lillian-b! I can confirm that the some of the site health pingbacks do not work, while others do. I'm trying to figure out what the cause of them are. Also thanks for the config.json file. I'll let you know once I have a solid understanding of why those few are failing 🤔

javorszky commented 6 months ago

Hi @lillian-b ,

Good news! Figured out why that's happening and how to fix it!

Background: Unit out of the box with default configuration will have a single running process for php applications, which means it can only ever handle one request. In the loopback case there's one going to admin-ajax about kicking off the loopback test, and that loopback test sends another POST request to wp-cron, and waits for that to finish. The problem here is that the loopback POST request can't be handled because the single php process is already handling the one that initiated that one, so it arrives at a deadlock.

Other runtimes (apache, nginx (the proxy), php itself) have different number of default processes which prevents deadlocks like this.

Essentially this one check overloaded the configuration of a single process.

Fix it

Thankfully the fix only needs a change in your unit config file:

    "applications": {
        "wordpress": {
            "type": "php",
            "targets": {
                "direct": {
                    "root": "/app/wordpress/"
                },

                "index": {
                    "root": "/app/wordpress/",
                    "script": "index.php"
                }
            },
            "processes": {
                "idle_timeout": 30,
                "max": 50,
                "spare": 1
            }
        }
    }

Note: an earlier version of this had process instead of processes. The plural, current version is the correct one. Props @lillian-b

I've added the process configuration object to the application. That controls how many simultaneous processes can be run for that application (max), how many idle processess to keep around if they're not actively handling requests (spare), and how much time to wait until an idle proces is terminated if there are more than spare idle processes (idle_timeout). This is the dynamic way of letting Unit handle scaling processes.

You can also configure a set number of processes that would always be kept around. In that case the above configuration would look like this:

    "applications": {
        "wordpress": {
            "type": "php",
            "targets": {
                "direct": {
                    "root": "/app/wordpress/"
                },

                "index": {
                    "root": "/app/wordpress/",
                    "script": "index.php"
                }
            },
            "processes": 50
        }
    }

Note: an earlier version of this had process instead of processes. The plural, current version is the correct one. Props @lillian-b

You can read more about these here: https://unit.nginx.org/configuration/#application-processes.

Let me know how this goes!

lillian-b commented 6 months ago

That worked, thank you so much! I will note that at least my Unit version wanted processes rather than process for the config object key.

javorszky commented 6 months ago

I will note that at least my Unit version wanted processes rather than process for the config object key.

Oh, that was a typo on my end, so sorry about that! Glad it's working 🙂