Fast CGI and PHP on Windows

My investigations of problems with using PHP (in this thread) in Caddy on Windows have thrown up the fact the the implementation has problems which are not present in Linux. It is not clear whether these are anybody’s fault (though if anyone, I’d point at the PHP developers); but there seems to be a layer missing which is required.

Fast CGI differs from plain CGI in that instead of generating a new process for each call, it can reuse existing processes which keep running, waiting for new input. At some stage in the execution of a fastcgi call there needs to be some form of control to avoid reentrancy or calling for multithreading beyond what the called process can handle. It is not, however, clear where this should be applied.

Taking the example of PHP, which is the main one in most people’s minds I imagine, the binary availabel from PHP is php-cgi. Now php-cgi does not contain the necessary process management code, as is explicitly noted in the last comment here:

The executable php-cgi.exe that is bundled with the windows binaries is a FastCGI interface but it is not FPM (Fastcgi Process Manager). php-cgi.exe does not have multi-threading or concurrent request support, nor support for any of the FPM configuration options.

Elsewhere I have seen comments that such code is in the source of php-cgi, but is disabled in the Windows compilation. It also appears that php-cgi will only accept a certain (configurable) number of calls before dying (to clear possible memory leaks, they say); a process manager would need to handle that eventuality as well.

For these reasons, PHP supply an additional program php-fpm which implements this management layer before passing requests on to php-cgi. In Linux, fastcgi calls to PHP are always written using php-fpm (I guess the implementation of process management in php-fpm is an improvement in same respect on that in the Linux version of php-cgi).

However, php-fpm is not available for Windows. I believe that this is because it uses Linux mechanisms which have no direct parallel in the Windows environment, and so it would need to be rewritten. For this reason, a web server has to be able to provide this function instead to make fastcgi to PHP reliable. Apache has two alternative layers which provide the requirements: mod_fcgid and mod_proxy_fcgi (the first is far easier to use). IIS has the necessary built in to its fastcgi implementation, and I think Lighttpd does as well.

Now I may have got this quite wrong, and Caddy may have the necessary code. But if that is so it has problems - firstly because of the behaviour discussed in the thread I linked at the start (not being able to handle arbitrary overlapping parallel calls), and secondly (something I have not mentioned before) because there appears to be a huge latency (something like 1 second) in PHP calls through Caddy on my system. Neither of these effects is present when using Apache calling the same php-cgi file through mod_fcgid on the same system, which is why I am currently proxying my PHP subsystems from Caddy to Apache.

3 Likes

Interesting! You have done a good job narrowing it down so far. So, thanks for that, Paul. It’s really helpful!

I admit I haven’t used PHP for a while, and working on it in Caddy isn’t personally a priority for me, however I would happily accept contributions to improve Caddy’s fastcgi handling. If someone is willing to help debug it and submit a fix if it does expose a bug in Caddy. Strange that only Windows shows it. (I don’t usually recommend using Windows for servers though anyway… Or at all, really, haha.)

1 Like

I may start looking at it myself - but my serious full-time coding days ended twenty years ago so I am inevitably (a) out of practice and (b) not well up with current standards, techniques, and even terminology. But if I see anything helpful, I’ll note it in here.

And as for Windows servers, I take your point - but they are actually quite a substantial minority; it’s because they are more often corporate that working with them gets less exposure on the web than would be proportionate. I came from a life of independent programming (pre-Windows), then corporate system management, so they feel very natural to me.

2 Likes

Awesome writeup, mate! Thanks doing the research and giving us a clear understanding of the issue.

I haven’t seen any sign of FPM-like functionality in Caddy at all; from what I can tell, it’s built with the assumption that process management is all handled upstream by the nominated FastCGI listener, and requests are handed off as soon as they’re received and translated.

It’s pretty unfortunate that at the moment, those familiar with Caddy’s code aren’t familiar with PHP on Windows, and visa versa. I guess this thread is a call-to-arms to anyone with a stake in both and time/expertise to volunteer.

In case of FastCGI, web server is not responsible for multi-processing. FCGI specification says the communication is supposed to happen over socket, implying that the upstream process may or may not be controlled by the web server directly.

mod_fcgid is similar to php-fpm. It creates a bunch of php-cgi processes and keeps them alive, if a process dies it creates a new one.
mod_proxy_fcgi is similar to what Caddy has. It only translates between HTTP and FCGI and requires an upstream FastCGI handler which can handle network requests.

In Apache configuration, If you use mod_proxy_fcgi, you can host a FastCGI server over the network and proxy requests to that. This way you can scale your webserver and the application independently.
If you choose mod_fcgid then you must host the webserver and the CGI handler on same machine.

Generally it is considered to be a good strategy to keep your web server and application tier separate. However, such a deployment configuration may not always be desirable. In that case I suggest that you keep using Apache, simply because the FCGI and FCGI proxy implementation in Apache is far more robust and reliable than it would be in Caddy should someone implement a process manager in Caddy.
Process managers are complicated to implement correctly and bring different class of problems than what Caddy community may want to have.

If you are feeling adventurous then sacrifice a goat and do something like this:

  • Create a pool of php-cgi processes running as Windows service. Start them on consecutive ports. Set the service to always restart.
  • specify all services as upstream in fastcgi block in Caddy configuration file.
  • Pray

This should give you moderately stable HTTP ↔ FastCGI setup. I believe the only problem should be gracefully handling shutdown and retrying the same request with another FCGI handler if the chosen handler refuse to service the request.
I wouldn’t recommend that you run this configuration in production, but if you end up doing that I’d be very interested in any metrics you can share with us.

However, in the long run those in charge of developing the market for Caddy might not wish to keep such a limitation which competitive web servers do not share.

I did this in the thread referenced at the start of this one - it made things far worse in my situation, because:

The Caddy FCGI code is getting back a 502, and therefore will not retry; retries might well have done enough in my case to have prevented me from needing to look into this at all.

What OS are you using @pwhodges?

This could possibly be tested to see if it helps:
https://github.com/mholt/caddy/pull/2061

And:

Could you compile on Windows with this plugin?

Windows Server 2012 DC, in a Hyper-V VM.

I can’t see how caddy-run bears on this problem. It runs a single process, which I can already do with “on startup” or as a Windows service. The problem that needs resolving is that of how multiple overlapping calls to that one process are handled to ensure they are all completed rather than rejected.

https://caddy.community/t/caddy-unable-to-start-as-a-service-on-window-server-2008-r2/3646/26?u=xincun

Do you have the problem? Since caddy version 10.10, caddy can not wake up php-cgi at startup.
Test environment: win7_x64.

I do not use Caddy to start PHP, so I wouldn’t know if there is currently a problem. I start it as a Windows service (using nssm) because that provides more control.

(Another reason is that the way that Caddy requires that a global action - starting a process - be set up within a site offends my sense of order!)

I wrote this earlier today to address the performance of php-cgi.exe: https://github.com/andkrau/WIN-FPM/releases

It still needs a lot of work but is ready enough for testing. While we don’t use Windows in production, I always test everything locally with Caddy. Having something FPM-ish makes things a little easier.

Huge thanks for taking this on! I shall try it out in the next day or so.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.