BreadcrumbHomeResourcesBlog How To Configure Nginx For Drupal 10 and PHP-FPM June 27, 2024 How to Configure Nginx for Drupal 10 and PHP-FPMDevOpsPHP DevelopmentBy Doug BiererNginx is a popular open-source web server software. Paired with Drupal 10 and PHP-FPM, nginx provides powerful performance and stability for load balancing, caching, and more. However, configuring nginx for Drupal 10 is not without its challenges.In this blog, I explore what happens if you encounter problems with the nginx configuration when installing Drupal 10 while using PHP-FPM. I walk you through solutions and offer insight to ensure you have the necessary knowledge for establishing a robust configuration that works well in a production environment.Table of ContentsGetting Started With the Drupal Nginx Configuration ProcessNginx for Drupal 10 SetupTroubleshooting Nginx for Drupal 10 and PHP-FPM Configuration IssuesFinal ThoughtsAdditional ResourcesTable of Contents1 - Getting Started With the Drupal Nginx Configuration Process2 - Nginx for Drupal 10 Setup3 - Troubleshooting Nginx for Drupal 10 and PHP-FPM Configuration Issues4 - Final Thoughts5 - Additional ResourcesBack to topGetting Started With the Drupal Nginx Configuration ProcessThe subject of this article, configuring nginx for Drupal and PHP-FPM, evolved out of my efforts at building a lab environment for an upcoming course on Drupal module development. My goal was to create a reproducible set of instructions that could build either a Docker container (e.g., a Dockerfile ), or a VirtualBox VM (e.g., a Vagrantfile ), usable for the course.I won’t bore you with the details of how I ran build after build until I latched into just the right set of instructions to produce a base environment for Drupal 10. The Dockerfile instructions will later be used to create a Vagrantfile. And yes, before you get started, I know that I’m doing things a little backwards. I should’ve started with a Terraform template, and then I’d already be done! But being the impatient type, and unable to resist the Urge To Code, I barreled on ahead and banged out a suitable Dockerfile. It’s based upon the template available as a download from the ZendPHP group. Configuration files for this setup are available on GitHub.Back to topNginx for Drupal 10 SetupBefore diving into the main problem I ran into pertaining to the Drupal 10 nginx using PHP-FPM configuration, let me give you an overview of the container setup.ZendPHPUsing ZendPHP was a no-brainer. The pre-defined Dockerfile served as the basis for the one I ended up using. All I needed were a few additional installation instructions, and I had a container already configured for ZendPHP and PHP-FPM. All management for PHP can now be accomplished using the fabulous zendphpctl script.NginxAlthough I have a long and fondly remembered history with Apache, I began toying around with nginx some years ago and got hooked. Accordingly, the setup I’m describing here uses nginx as its web server.PHP-FPMPHP-FPM (PHP FastCGI Process Manager) is a highly efficient alternative PHP FastCGI implementation with features for managing and processing PHP requests. It works by receiving and processing PHP requests from nginx. It can handle high loads and maximize performance by via multiple pools of PHP processes. MariaDBAny intermediate-level PHP developer should be familiar with MariaDB, a powerful open-source MySQL alternative database. In the Drupal installation script I use Drush to do the actual database setup for the new Drupal website.So now, at long last, we arrive at the entire point of this article: how to properly configure nginx for Drupal 10 and PHP-FPM.Back to topTroubleshooting Nginx for Drupal 10 and PHP-FPM Configuration IssuesThere are a number of configuration issues you might encounter when configuring nginx for Drupal 10 and PHP-FPM. The configuration problems will be starkly evident the first time you fire up your newly created Drupal 10 installation. Let’s tackle the potential issues one at a time and see how to configure nginx for Drupal to avoid problems.Always Getting the Website Home PageYou check and double-check your configuration. You verify that the Drupal source code has been installed. You check the database. But, no matter what you do, you always end up on the website’s main home page! The most likely culprit is that you didn’t make your new nginx-Drupal configuration available to nginx.From a Linux command prompt, here’s what you might see:root@drupal:/home/training# ls -l /etc/nginx/sites-available/ total 12 -rwxrwxr-x 1 root root 468 Apr 24 09:25 default -rw-r--r-- 1 root root 2412 May 30 2023 default.old -rw-r--r-- 1 root root 955 Apr 26 02:02 drupal.conf root@drupal:/home/training# ls -l /etc/nginx/sites-enabled/ total 0 lrwxrwxrwx 1 root root 34 Apr 24 09:29 default → /etc/nginx/sites-available/default To fix the problem, create a symbolic link between the available and enabled directories: root@drupal:/home/training# ln -s \ /etc/nginx/sites-available/drupal.conf \ /etc/nginx/sites-enabled/drupal.conf root@drupal:/home/training# ls -l /etc/nginx/sites-enabled/ total 0 lrwxrwxrwx 1 root root 34 Apr 24 09:29 default → /etc/nginx/sites-available/default lrwxrwxrwx 1 root root 38 Apr 26 02:11 drupal.conf -> /etc/nginx/sites-available/drupal.confThe directory defined by the root directive must exist and must be accessible to nginx. Don’t forget to restart nginx! root@drupal:/home/training# /etc/init.d/nginx restart * Restarting nginx nginx [ OK ] 502 Bad GatewayIf you’re like me, you look for the “official” sources when dealing with configuration. In this case it’s natural to look at the nginx website. Search revealed a community-supplied configuration: the Lando nginx - Drupal configuration. It even addresses PHP-FPM. Hooray! Copy and paste the configuration into /etc/nginx/sites-available/drupal.conf.But then you get the output shown in the image below.The most likely cause is that PHP-FPM is running on a socket or TCP/IP port that’s different from the one in the nginx documentation. Before you change your nginx configuration, you’ll first need to find how your PHP-FPM installation is configured to “listen.” The listen directive is usually found in the PHP-FPM “pool” configuration. In the case of ZendPHP, this is located in this directory structure (where “X.Y” is your version of PHP):root@drupal:/home/training# cat \ /etc/php/X.Y-zend/fpm/pool.d/www.conf |grep listen listen = 0.0.0.0:9000In your presumed drupal.conf file, look for the fastcgi_pass directive:root@drupal:/home/training# cat \ /etc/nginx/sites-available/drupal.conf |grep fastcgi_pass fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; Oops! This doesn’t match. In the demo installation, PHP-FPM is programmed to listen via TCP/IP port 9000 on any IP address whereas nginx thinks that PHP-FPM will respond via a socket unix:/var/run/php/php7.0-fpm.sock. This will not do at all! The solution is to rewrite the fastcgi_pass directive to listen on the localhost loopback network 127.0.0.1: fastcgi_pass 127.0.0.1:9000; And, of course, don’t forget to restart nginx!404 Not FoundAt first glance you might believe this is a result of an nginx misconfiguration, in my experience, however, this message, especially when you’re just trying to get to the home page, is due to a file system permissions problem. To start, check the permissions of your Drupal installation:root@drupal:/home/training# ls -l /var/www total 12 drw-r----- 4 root root 4096 Apr 24 04:57 drupal drwxrwxr-x 1 www-data zendphp 4096 Apr 24 09:32 htmlAs you can see, the permissions are set for the root user, and “world” access is disabled. Before changing the permissions, you’ll need to find the users and groups for PHP-FPM and nginx. For PHP-FPM look in the “pool” configurations:root@drupal:/home/training# cat \ /etc/php/8.2-zend/fpm/pool.d/www.conf \ | grep -e "user" -e "group" user = zendphp group = zendphpFor nginx look in the primary nginx configuration file:root@drupal:/home/training# cat \ /etc/nginx/nginx.conf \ |grep -e "user" user www-data;One approach to reset the appropriate permissions would be to add the user “www-data” to the group “zendphp,” and make an assignment to the group “zendphp.” Alternatively, nginx creates a group of the same name, so you could add the user “zendphp” to the group “www-data,” and assign permissions to the group “www-data.” Either way works fine.In my example I’ll use a simpler approach which is to assign both user and group, which covers the needs of nginx and PHP:root@drupal:/home/training# chown -R www-data:zendphp /var/www/drupal root@drupal:/home/training# chmod -R 775 /var/www/drupal root@drupal:/home/training# find /var/www/drupal \ -type d -exec chmod 775 {} \; root@drupal:/home/training# find /var/www/drupal \ -type f -exec chmod 664 {} \; root@drupal:/home/training# chmod +x /var/www/drupal/vendor/bin/* root@drupal:/home/training# ls -l /var/www/drupal total 3156 -rw-rw-r-- 1 www-data zendphp 3553 Apr 24 04:58 composer.json -rw-rw-r-- 1 www-data zendphp 229522 Apr 24 04:58 composer.lock -rw-rw-r-- 1 www-data zendphp 2985953 Apr 24 04:57 composer.phar drwxrwxr-x 28 www-data zendphp 4096 Apr 24 04:58 vendor drwxrwxr-x 7 www-data zendphp 4096 Apr 24 04:57 webYou’ll note that I needed to add execute permissions to the drupal/vendor/bin folder as I’m using Drush for certain operations.403 ForbiddenA 403 Forbidden error is returned if you have made a valid request, but the request hasn’t been authorized in the nginx configuration. This means that your Drupal virtual host definition file has identified your Drupal URL (“drupal.local” in this example), and that it’s been properly linked as described in the earlier section.In your nginx-Drupal configuration file, look for the primary location block:location / { # some configuration }What’s needed is a try_files directive. You can use the $uri variable to represent the original URI requested:location / { try_files $uri; }However, the problem with this configuration is that only exact matches will be found. So if you enter http://drupal.local/index.php you’ll see your Drupal website. However, if you only enter http://drupal.local you’ll still get the 403 error.To fix the problem just add another entry, separated with a space, to reference index.php. Append the $query_string variable so that any rejected $uri requests are funneled through index.php, and all original request information will be dragged along:location / { try_files $uri /index.php?$query_string; }CSS and JavaScript Files Not LoadingIf you able to access your Drupal site, but aren’t seeing graphics, backgrounds, and styling, it could be a permissions issue, or something as simple has not having enabled a theme. On the other hand, the smart people at nginx added a few extra location blocks you can add to your nginx - Drupal configuration to prevent problems with web assets such as graphics, stylesheets, and JavaScript files.This snippet does the actual URL rewrite: location @rewrite { rewrite ^ /index.php; # For Drupal >= 7 }These snippets handle specific file types: location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { try_files $uri @rewrite; expires max; log_not_found off; } location ~ ^/sites/.*/files/styles/ { try_files $uri @rewrite; }Security ConfigurationSome of the other features of the Drupal configuration developed by nginx includes a number of security settings. These are needed because in Drupal the document root points to a directory that allows access to the Drupal source code. Accordingly, you can use these nginx settings to prevent accidentally exposing your source code or other sensitive files to the world.This prevents users from attempting to access PHP code from higher level directories: location ~ \..*/.*\.php$ { return 403; } This configuration snippet prevents direct access to files in the /sites directory structure: location ~ ^/sites/[^/]+/files/.*\.php$ { deny all; } This snippet blocks access to the /vendor folder (used by Composer): location ~ /vendor/.*\.php$ { deny all; return 404; } There are other security settings, however the three mentioned should give you the general idea of what’s available.Back to topFinal ThoughtsFor the most part I’ve found that the Lando nginx - Drupal - PHP-FPM configuration is pretty robust and should work well in a production environment. There are plenty of extra security measures, and it’s flexible enough to serve most purposes. The main things to watch out for are file system permissions issues, misconfigured nginx and PHP-FPM users and groups, webserver permission settings, and configuring the correct listener for PHP-FPM.Additionally, there are a number of configuration differences between Drupal 10 and earlier versions. There was a major change starting with Drupal 7. The official nginx – Drupal configuration is good at pointing out the differences between Drupal 7+ and earlier versions in its comments.As you continue to modernize and optimize your Drupal PHP applications, make sure to check back here. Zend continuously offers new training courses, how-to guides, and expert insights for developers, and we are ready to support your team as you tackle tough PHP challenges.Ready to Expand Your PHP Knowledge?Whether you're new to PHP or are an advanced developer, Zend PHP training courses are designed to enhance your skills. Learn your way through our instructor-led, on-demand, or free training options.Find Your Best CourseBack to topAdditional ResourcesOn-Demand Webinar - Are CMS Ecosystems Keeping Pace With PHP?On-Demand Webinar - The State of Open Source Web App DevelopmentBlog - Unpacking the Drupal PHP Support LifecycleBlog - Using ZendPHP, PHP-FPM, and Nginx on IBM iBlog - How To Install (and Configure) Ansible to Deploy a PHP ApplicationBlog - How To Use PHP and ReactJS To Build Modern Web AppsBack to top
Doug Bierer Senior Technical Trainer, Zend by Perforce Doug Bierer has been hooked on computers since his first program, written on a DEC PDP-8 in 1971. In his wide-ranging career, Doug has been a professional contract programmer since 1978, having built applications in BASIC, PL/I, assembler, FORTH, C, C++, dBase/FoxBase/Clipper, Pascal, Prolog, Perl, Java, Python, and PHP. He deployed his first website in 1993 while living in San Francisco. Doug has been doing technical PHP training since 2009 and has written a number of technical books including PHP 8 Programming Tips, Tricks and Best Practices and the PHP 7 Programming Cookbook (Packt Publishing Ltd). He is fluent in three languages, has traveled extensively, and now resides in Thailand.