How do I limit Nginx/PHP-FPM to 1 client connection only?

What I’m trying to do:

Hello, I am seeking for Your suggestion on how to allow running a PHP script only once at a time, not for more than 1 persons/clients. Because the PHP script is made to run a python command which fails if attempted to run more than 1 time:

exec("$*** siteSign $site $privatekey --publish 2>&1", $out);

Also it is modifying a .json file (which may also be the problem if done concurrently?):

$f = fopen($users_json, "w");
fwrite($f, $json_out);
fclose($f);

What I’ve already tried:

Not being a PHP developer I spent like one hour trying to talk to AI and figure out how to limit Nginx to only one client.

nginx -v; php -v; lsb_release -d

nginx version: nginx/1.22.1
PHP 8.2.28 (cli) (built: Mar 13 2025 18:21:38) (NTS)
Description:    Debian GNU/Linux 12 (bookworm)

Result:

https://nginx.org/en/docs/ngx_core_module.html#worker_processes set to 1
https://nginx.org/en/docs/ngx_core_module.html#multi_accept set to off
https://nginx.org/en/docs/ngx_core_module.html#worker_connections set to 1

edited in my /etc/nginx/nginx.conf After saving, I have ran “nginx -t”. It may complain that “1 worker_connections are not enough for 4 listening sockets”.
It means that I may have open 4 HTTP/s ports (443 ipv4, ipv6; 80 ipv4, ipv6).
I have also adjust PHP FPM settings in /etc/php/*/fpm/pool.d/www.conf

pm = ondemand
pm.max_children = 1
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 1
pm.max_requests = 1

In my case the error log still shown sockets errors when visiting all 2 .php files, until I have raised worker_connections to 7 (6 not worked - Error 500).
So it looks to me like I have managed to limit clients to 1 or no?

Or please can you suggests more simple and better way to handle this, considering i am total newbie to Nginx and not a PHP developer?

The most direct solution is to implement file locking in your PHP script:

// Define a lock file
$lock_file = "/tmp/my_script.lock";

// Try to get an exclusive lock
$lock = fopen($lock_file, "w");
if (!flock($lock, LOCK_EX | LOCK_NB)) {
    // Could not get lock - script is already running
    echo "Script is already running. Please try again later.";
    exit(1);
}

// Now we have the lock, run your code
try {
    // Your existing code here
    exec("$*** siteSign $site $privatekey --publish 2>&1", $out);
    
    // JSON file operations with proper locking
    $f = fopen($users_json, "w");
    fwrite($f, $json_out);
    fclose($f);
} finally {
    // Release the lock
    flock($lock, LOCK_UN);
    fclose($lock);
    @unlink($lock_file); // Optional: remove the lock file
}
1 Like

Thank You, I was taking a look on the code and asked AI some additional questions. The HuggingChat AI suggested following. Do you think that its suggestions are good?

To prevent the lock from not being released when the PHP script is terminated, you can use the register_shutdown_function to ensure the lock is released even if the script is terminated unexpectedly.

Replace:

finally {
    // Release the lock
    flock($lock, LOCK_UN);
    fclose($lock);
    @unlink($lock_file); // Optional: remove the lock file
}

with:

register_shutdown_function(function() use ($lock, $lock_file) {
    flock($lock, LOCK_UN);
    fclose($lock);
    @unlink($lock_file); // Optional: remove the lock file
});

This will ensure that the lock is released when the script terminates, regardless of whether it’s due to an exception or a normal exit.

To make the user wait for the lock to be released instead of exiting, you can use a loop to continuously try to acquire the lock until it is available.

Replace:

if (!flock($lock, LOCK_EX | LOCK_NB)) {
    // Could not get lock - script is already running
    echo "Script is already running. Please try again later.";
    exit(1);
}

with:

while (!flock($lock, LOCK_EX | LOCK_NB)) {
    // Could not get lock - wait and try again
    sleep(5); // wait for 5 seconds
}

This will cause the script to wait for 5 seconds and then try to acquire the lock again, repeating this process until the lock is available.