Nginx – Reverse Proxy for PHP: Best practice

nginxPHPreverse-proxy

I'm setting up NGINX as a SSL reverse proxy for three small web apps with dynamic (PHP) and static content.

What would be considered best practice security-wise and performance-wise when it comes to passing PHP requests?

Should they be passed to the requested web server (NGINX – which would then pass it to PHP-FPM via socket or TCP on the same host) or should they directly be passed to the PHP-FPM server?

All my web apps and the reverse-proxy are in separate Jails on FreeBSD. Each Jail has it's own NGINX web server and PHP-FPM (or uWSGI and Python).

Best Answer

Your main Nginx should act as a reverse-proxy and forward HTTP requests to the respective web server of each app. If the main reverse-proxy has file-level access to the app's jails, you better use UNIX sockets to communicate with its web server, but in your case you have no choice but to use TCP.

When using TCP, make sure to set the keepalive parameter to maintain a number of open connections at all times, so that you don't have to open and close a connection on each request for better performance. The parameter's argument is the number of connections to keep open, something like 10 seems enough.

In your jails, the web server in there should use UNIX sockets to communicate with its PHP-FPM for better performance (TCP has more overhead than an UNIX socket, so use the latter wherever possible).

Finally I see no major security issues in having the main reverse-proxy communicating directly with the in-jail PHP-FPMs, but that would mean you should also configure the main reverse-proxy according to the in-jail PHP-FPM. That's something I'd rather avoid, I would prefer the jails to be self-contained and expose a single HTTP endpoint on a default port, and have the in-jail Nginx handle all the PHP-FPM stuff. If there's something you need to change in regards to PHP-FPM, you just do it in the jail without touching your main Nginx reverse proxy.

Also I suggest you try an even lighter web server for the jails like Lighttpd since you really don't need much features in there and even though Lighty's configuration syntax is absolutely horrible it shouldn't be a problem.

About your last comment

Now I only need to find out which settings to set in the backend and which in the proxy (cache-control, keepalive, error_page, etc…)

The keep-alive parameter I mentioned should be set in the upstream block of the main Nginx reverse proxy and only affects the reverse-proxy <-> in-jail server communication and has nothing to do with HTTP keep-alive between the clients and your server. For keepalive between browsers and servers, it should be done on the last endpoint on your side, which is the reverse-proxy. On the other hand, cache-control headers are app-dependent (as different apps may need different settings) and should be set individually in the app's jails. Try to put as much settings as possible in each app's jail, and only modify the reverse-proxy's configuration in extreme cases like connection-level settings (HTTP keepalive, TLS, etc).