Recommended Free Tools
If an Apache site executes index.php but returns errors for CSS, JavaScript, images, or the site root, PHP is rarely the real problem. Apache is usually selecting the wrong virtual host, mapping URLs to the wrong DocumentRoot, denying static files, or failing to resolve the directory index. A PHP-FPM rule can also be pointing at a filesystem path that does not exist from FPM’s point of view.
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
Work through the checks in this order: identify the virtual host that receives the request, verify its public directory, confirm static-file access, set the directory index, then validate the PHP handler and its filesystem path. This isolates the failing layer without weakening the PHP proxy rule or granting access to the wrong directory.
As an Amazon Associate I earn from qualifying purchases.
What “Apache only serves PHP files” usually means
Apache treats a request for /style.css, /app.js, or /images/logo.svg as a normal file lookup. A request for /index.php is different: after Apache maps the URL to a file, a PHP handler such as mod_php or PHP-FPM processes the script. Seeing PHP output proves only that one request found a script and a working handler. It does not prove that the same virtual host, directory, permissions, or URL paths are correct for static assets.
The root URL, /, is a directory request rather than a direct request for index.php. Apache’s mod_dir module checks the resources named by DirectoryIndex. Its documented default is index.html, so a PHP application normally needs DirectoryIndex index.php (often followed by index.html as a fallback).
#1 Best Overall
Separate the symptom into one of five layers:
- Virtual-host selection: the request reaches another host or the default host.
- Filesystem mapping: the selected host’s
DocumentRootis not the directory containing the complete public site. - Directory-index resolution:
/does not look for the PHP entry point. - Static-file authorization or lookup: Apache cannot read the CSS, JavaScript, or image path.
- PHP execution: the PHP module or FPM connection is missing or misconfigured.
Fix the earliest failing layer. Changing PHP rules cannot repair a wrong DocumentRoot or a 403 caused by directory authorization.
1. Confirm which virtual host handles the request
Apache chooses a virtual host using the request address, port, and Host header. A request can therefore be handled by a different configuration from the file you are editing. If no matching ServerName or ServerAlias is found, the first listed matching virtual host can become the default.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Check the names and port
Make the hostname in your browser, DNS, and test command match the vhost. For example, a host configured as example.test will not necessarily answer requests sent to an unrelated name. Verify all of these values in the active configuration:
ServerNameexactly matches the hostname you use.- Every required alternate name appears in
ServerAlias. - The vhost listens on the address and port being requested, such as
*:80for HTTP. - If HTTPS is involved, the TLS vhost and its certificate configuration are also the ones receiving the request.
When testing locally, send the intended host explicitly, for example with a request whose Host header is the configured name. A successful request to an IP address alone can select a different vhost.
Inspect Apache’s active vhost map
Use the platform’s vhost-dump command (commonly apachectl -S) and read which vhost is the default for the requested address and port. This output reflects loaded configuration, not merely files present in an editor. If the expected host is absent, the site configuration may not be enabled, may contain a syntax error, or may be loaded by a different Apache instance.
Do not proceed to PHP debugging until this mapping is correct. Otherwise every later test may be examining the wrong site.
2. Make the DocumentRoot the complete public tree
Once the right vhost is selected, Apache maps a URL beneath that vhost’s DocumentRoot. The directory must contain the complete public tree: the PHP entry point, stylesheets, scripts, images, fonts, and any other files the browser requests.
Rank #2
- Used Book in Good Condition
Use one coherent public directory
A typical layout separates private application code from files intended for direct web access:
/srv/www/example/
├── app/ (private application code)
├── config/ (private configuration)
└── public/
├── index.php
├── css/
│ └── site.css
├── js/
│ └── app.js
└── images/
└── logo.svg
In this layout, the vhost should use /srv/www/example/public, not the project parent and not a directory containing only PHP scripts. A browser request for /css/site.css must therefore resolve to /srv/www/example/public/css/site.css.
Keep the Directory block aligned
The authorization block should refer to the same directory as DocumentRoot. A minimal HTTP vhost shape is:
<VirtualHost *:80>
ServerName example.test
ServerAlias www.example.test
DocumentRoot /srv/www/example/public
<Directory /srv/www/example/public>
Require all granted
DirectoryIndex index.php index.html
</Directory>
</VirtualHost>
If DocumentRoot points to one directory while <Directory> grants access to another, Apache can map a file correctly but still return 403, or deny the whole tree. Keep the paths identical unless you have a deliberate, documented alias design.
Check the actual files and URL case
On case-sensitive filesystems, /CSS/site.css and /css/site.css are different paths. Compare the browser’s failed request with the real filename, including capitalization, hyphens, and file extensions. Check generated HTML and CSS for stale relative paths, a wrong base URL, or an asset directory that was never copied into the public tree.
A 404 for a static asset generally means the mapped path does not exist. Confirm the file from the server’s filesystem and then calculate the path Apache should use by appending the URL path to DocumentRoot.
3. Configure directory-index resolution
When a client requests /, Apache searches the configured index resources in order. For a PHP application, declare the PHP entry point explicitly:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →<Directory /srv/www/example/public>
Require all granted
DirectoryIndex index.php index.html
</Directory>
With this order, Apache tries index.php first and uses index.html only if the PHP file is absent. Put the directive in the vhost or an allowed directory-level configuration, then verify that mod_dir is loaded by the distribution’s normal module mechanism.
Why you may see a directory listing
If no configured index file exists and directory listing is enabled, Apache may display the directory contents. That does not indicate that PHP is broken; it means the directory-index search did not find a usable resource. If listing is not intended, disable it with the site’s normal options policy and fix the missing index rather than relying on a hidden filename.
4. Verify static-file authorization and permissions
Require all granted permits requests at the Apache authorization layer, but the operating-system account running Apache must still be able to traverse every parent directory and read the files. A missing execute permission on a parent directory can produce 403 even when the file itself is readable.
- Check read permission on CSS, JavaScript, image, font, and map files.
- Check traverse permission on each parent directory from the filesystem root to
DocumentRoot. - Ensure security policies used by the operating system or container do not block Apache’s account.
- Avoid making the entire project world-writable as a quick fix; grant the minimum access needed for the web process.
Use the response status to narrow the search. A 403 points toward authorization, filesystem permissions, or a policy denial. A 404 points toward URL mapping, a missing file, or a case mismatch.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
5. Understand what a PHP-only ProxyPassMatch rule does
A PHP-FPM configuration commonly routes only PHP-looking paths to FastCGI:
<VirtualHost *:80>
ServerName example.test
ServerAlias www.example.test
DocumentRoot /srv/www/example/public
<Directory /srv/www/example/public>
Require all granted
DirectoryIndex index.php index.html
</Directory>
ProxyPassMatch ^/(.*.php(/.*)?)$ fcgi://127.0.0.1:9000/srv/www/example/public/$1
</VirtualHost>
This pattern is supposed to match PHP requests. CSS, JavaScript, and image requests do not match it, so Apache serves those files as ordinary static resources from DocumentRoot. Do not broaden the pattern simply because an image fails. First inspect the static path, authorization, permissions, and requested URL.
The exact endpoint may be a Unix socket instead of TCP port 9000, and the module or package commands differ by operating system and PHP version. Use the endpoint supplied by your distribution and confirm that the corresponding FPM service is running.
Rank #4
6. Make the PHP-FPM filesystem path exact
PHP-FPM interprets the filesystem path Apache passes to it. FPM does not understand Apache aliases, virtual-host names, or the web server’s namespace. The path in the FastCGI mapping must be the real path to the script as visible to the FPM process.
Free tools Windows power users keep installed
One-click scans. No signup required.
Common path mismatches
- Wrong project root: Apache serves
/srv/www/example/public, but the proxy rule appends paths to/srv/www/example. - Alias confusion: a URL alias such as
/siteis mistaken for a filesystem directory. - Container boundaries: Apache and FPM run in separate containers with different mount points. A path valid in Apache’s container may not exist in FPM’s container.
- Case differences: the script path differs only by capitalization on a case-sensitive system.
Compare the path in the proxy rule with the path mounted and readable by FPM. If the application is containerized, make the shared volume and mount paths consistent, or configure the mapping for the path FPM actually sees. A successful connection to FPM does not compensate for a nonexistent script path.
7. Choose and validate the PHP handler
Apache can execute PHP through mod_php or hand scripts to PHP-FPM using mod_proxy and mod_proxy_fcgi. The selected model must be installed, loaded, and scoped to the intended vhost.
| Area | mod_php | PHP-FPM through mod_proxy_fcgi |
|---|---|---|
| Process model | PHP runs inside Apache worker processes. | Apache passes PHP requests to separate FPM worker processes. |
| Isolation | PHP shares Apache’s process boundary. | PHP workers are a separate service boundary, allowing independent process management. |
| Apache integration | Uses the PHP module loaded into Apache. | Requires mod_proxy, mod_proxy_fcgi, and a valid FPM socket or TCP endpoint. |
| Restart behavior | PHP changes generally involve the Apache process lifecycle. | Apache and FPM can be restarted or tuned as separate services. |
| Deployment status | Available on systems that provide the module, but tied to the Apache MPM and its compatibility. | The PHP manual recommends this model for modern Apache deployments. |
Do not configure both handlers for the same request pattern unless you understand which one wins. Duplicate or conflicting rules can produce downloads of PHP source, unexpected execution, or requests sent to an inactive endpoint.
Confirm the endpoint before testing the application
Check that the FPM service is running and listening on the socket or port named by the vhost. A 502 or 503 usually indicates that Apache cannot connect to FPM, while a PHP error after a successful handoff points to the runtime or application. A PHP file that works through one vhost but fails through another often indicates a scope or endpoint difference rather than a code change.
8. A complete troubleshooting sequence
Run these checks in order so each result narrows the next action.
- Validate syntax: run
apachectl configtestor the equivalent command for your platform. Fix every reported error before reloading. - Inspect active vhosts: use the platform’s active-vhost dump and confirm that the requested host, address, and port select the intended
ServerNameorServerAlias. - Read the effective root: verify that
DocumentRootnames the public directory containingindex.phpand all static assets. - Align authorization: ensure the
<Directory>block names that same directory and permits the site’s files. - Test one known asset: request a file whose exact location you can verify, such as
/css/site.css. Check URL case and filesystem case. - Set the index: add
DirectoryIndex index.php index.htmlwhere the application requires it, then test/separately from/index.php. - Identify the handler: decide whether the vhost uses mod_php or PHP-FPM. For FPM, confirm
mod_proxy_fcgi, the endpoint, and the running service. - Compare FPM paths: make the script path passed in the FastCGI rule exactly match the path visible to the FPM process, including container mounts.
- Reload safely: reload Apache only after the configuration test passes. Restart FPM separately if its service configuration changed.
- Read logs for the same request: correlate Apache access and error logs with the PHP-FPM log. Use the status code and timestamp, not a nearby unrelated error.
9. Use status codes and logs to choose the next branch
404 Not Found
Check vhost selection, DocumentRoot, the requested URL, file existence, and capitalization. For an asset, calculate the expected filesystem path and verify it directly. For /, verify the index file exists and is named in DirectoryIndex.
Best Value
- Used Book in Good Condition
403 Forbidden
Inspect the matching <Directory> authorization, parent-directory traversal permissions, file readability, and any operating-system security policy. Confirm that the request did not land in a vhost with a more restrictive directory block.
502 or 503
Check the PHP-FPM socket or TCP listener, service status, firewall or container networking, and the Apache proxy modules. A connection failure is different from an FPM process that receives the request but cannot open the script.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11PHP error after handoff
When Apache and FPM logs show that the request reached PHP, troubleshoot the application, PHP version, extensions, and script-level error. Do not alter static-file rules to address an error that occurs after execution begins.
PHP source downloads or is displayed
This indicates that the request was served as a static file instead of being sent to a PHP handler. Check that the intended vhost is active, the PHP handler is loaded, and the rule matches the requested path. Prevent public access while correcting the configuration if source exposure is possible.
10. Configuration patterns that prevent the symptom
Keep public and private files separate
Place only web-facing resources under DocumentRoot. Keep secrets, deployment files, and private libraries outside it. This makes URL-to-filesystem mapping predictable and reduces the chance that a broad root setting exposes files that were never meant to be downloaded.
Keep the PHP rule narrow
Match PHP scripts and let Apache’s normal file handling serve static resources. A narrow rule makes failures easier to classify: missing assets remain a mapping or authorization issue, while PHP failures remain an execution or FPM issue.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsUse explicit names and aliases
Declare the canonical hostname and required aliases in the vhost. If an application is mounted under a URL prefix, document both the URL prefix and the real filesystem path; do not assume FPM can infer one from the other.
11. What not to change as a first response
- Do not add a second PHP proxy rule for CSS or images.
- Do not point
DocumentRootat the project parent merely because PHP files are located there. - Do not enable broad filesystem access to bypass a 403.
- Do not assume a working
/index.phpproves that/has a correct directory index. - Do not copy an FPM path from another host or container without checking where the script exists in the current runtime.
- Do not reload an untested configuration; run the syntax check first.
12. A compact reference configuration
This example combines the essential pieces for a site whose public files live in /srv/www/example/public and whose FPM service listens on a local TCP endpoint. Replace the endpoint and paths with values that exist on your system.
<VirtualHost *:80>
ServerName example.test
ServerAlias www.example.test
DocumentRoot /srv/www/example/public
<Directory /srv/www/example/public>
Require all granted
DirectoryIndex index.php index.html
</Directory>
ProxyPassMatch ^/(.*.php(/.*)?)$ fcgi://127.0.0.1:9000/srv/www/example/public/$1
</VirtualHost>
After enabling the required Apache proxy modules and the FPM service supplied by your operating system, run the configuration test, reload Apache, request a known static asset, then request /. If the asset works but the root fails, focus on DirectoryIndex. If the root and PHP script work but assets fail, focus on the public tree, URL paths, authorization, and permissions. If PHP requests return 502 or 503, focus on the FPM endpoint and service.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




