Configure Nginx to serve static HTML and dynamic PHP from multiple folders by defining separate location blocks within a single server block. Use specific root directives for each path and apply the fastcgi_pass handler only to the PHP directory. This approach ensures that static assets are served directly while PHP files are processed by the backend interpreter, maintaining high performance and clear separation of concerns.
Understanding the Server Block Structure
The core of this configuration lies in how Nginx routes requests based on the URI path. When you have multiple folders, such as
/var/www/html for static content and
/var/www/php-app for dynamic scripts, you must guide Nginx to treat them differently. The default behavior often assumes all content is either static or requires processing, which can lead to errors when mixing types in different directories.
To solve this, you do not need separate server blocks for each folder unless they use different ports or domains. A single server block listening on port 80 or 443 can handle multiple locations. The key is precision in your location definitions. You must explicitly tell Nginx where to look for files and which internal processor to invoke for specific file extensions.
Configuring Static HTML Directories
For folders containing only HTML, CSS, JavaScript, and images, you want Nginx to serve these files directly without involving PHP-FPM. This reduces overhead and speeds up load times significantly. Start by defining the general root for your site, but be careful if your paths diverge.
If your HTML files are in a subdirectory like
/public, you can create a dedicated location block. For example:
server {
listen 80;
server_name example.com;
# General fallback or default root
root /var/www/html;
index index.html;
location /static-html/ {
alias /var/www/static-content/;
try_files $uri $uri/ =404;
}
}
Using
alias instead of
root inside the location block is crucial here. It maps the URL path exactly to the filesystem path. If you used
root, Nginx might append the location prefix to the root path, resulting in a 404 error because the file structure would not match. The
try_files directive ensures that if a file does not exist, Nginx returns a proper 404 response rather than passing the request to a processor that doesn't need it.
Handling PHP Files in Separate Folders
When you have a folder dedicated to PHP applications, you must enable the FastCGI process. This allows Nginx to communicate with PHP-FPM. Suppose your PHP application resides in
/var/www/php-app. You need a location block that targets this specific path and passes matching files to the PHP processor.
location /php-app/ {
alias /var/www/php-app/;
# Pass PHP files to PHP-FPM
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
Notice the nested location block. The outer block sets the
alias for the directory. The inner block, using a regex
~ \.php$, specifically catches any request ending in
.php. Inside this inner block, we define how to talk to PHP-FPM. The
fastcgi_param SCRIPT_FILENAME variable is critical; it must point to the actual file on disk. Because we used
alias,
$request_filename/var/www/php-app/.
If you mix PHP and HTML in the same root directory, the logic changes slightly. You would typically keep the main
root directive at the server level and use a regex location for PHP that applies globally, while letting other files fall through to the default static handling. However, keeping them in separate physical folders simplifies permissions and security management.
Security and Permissions Considerations
Running PHP and static files from different folders offers security benefits. You can restrict execution permissions more tightly. Ensure that the web server user (usually
www-data) has read access to both directories. For the PHP folder, write permissions may be needed for uploads or cache directories, but never for the executable PHP scripts themselves.
It is also wise to prevent direct access to sensitive files. In your PHP location block, you can deny access to hidden files or backup files:
location ~* /\. {
deny all;
}
This small addition prevents users from accessing
.htaccess equivalents or version control directories like
.git that might reside within your public-facing folders.
Troubleshooting Common Issues
If you encounter 502 Bad Gateway errors, check if PHP-FPM is running and if the socket path in
fastcgi_pass matches your system's configuration. On many systems, the socket is located at
/run/php/php-fpm.sock, but it may vary depending on your PHP version and installation method. You can verify the correct path by checking your PHP-FPM pool configuration file.
Another common issue is the "No input file specified" error. This usually means the
SCRIPT_FILENAME parameter is incorrect. Double-check that your
alias directive ends with a slash and that the regex in the location block correctly identifies the PHP files. If you recently changed your directory structure, ensure that Nginx has reloaded its configuration using
sudo nginx -t followed by
sudo systemctl reload nginx.
For deeper insights into isolating PHP processes, consider reviewing guides on PHP-FPM security isolation. Understanding how Nginx proxies requests helps clarify why misconfigurations in one block affect the entire server. Additionally, if you are managing multiple environments, similar principles apply to Docker setups where proxying can sometimes lead to timeouts if not configured correctly.
Frequently Asked Questions
Can I use the same root directory for both HTML and PHP?
Yes, you can serve both from the same root by using a regex location block for PHP files. This method relies on the file extension to trigger the FastCGI pass, while other files are served statically via the default location. It is simpler to manage but offers less granular security isolation than separate folders.
Why did I get a 404 error after adding the alias directive?
A 404 error often occurs if the alias path does not end with a trailing slash or if the try_files directive does not account for the aliased path correctly. Always ensure the alias points to an existing directory and that the URI structure matches the filesystem layout exactly.
How do I test my Nginx configuration before reloading?
You should always run
sudo nginx -t to syntax-check your configuration file. This command validates the directives and reports any errors in line numbers. Only proceed with
systemctl reload nginx if the test returns success, preventing service downtime due to bad configurations.
What is the difference between root and alias directives?
The
root directive appends the full URI to the specified path, while
alias replaces the URI prefix with the specified path. Use
root for standard sites and
alias when mapping a URL path to a completely different directory structure, especially in nested location blocks.
Is it safe to run PHP-FPM and static files on the same server?
Yes, it is standard practice and highly efficient. Nginx handles static files natively, which is much faster than passing them through PHP. Running them together saves resources compared to separate servers, provided you configure permissions correctly to prevent unauthorized script execution.