Apache 2.4 + PHP-FPM, catching error pages - apache

Here is my vhost file:
<VirtualHost *:80>
ServerName awesome.dev
## Vhost docroot
DocumentRoot "/var/www/awesome"
## Directories, there should at least be a declaration for /var/www/awesome
<Directory "/var/www/awesome">
Options Indexes FollowSymLinks MultiViews
DirectoryIndex index.php
AllowOverride All
Require all granted
</Directory>
## Logging
ErrorLog "/var/log/apache2/w0JhArMoDehc_error.log"
ServerSignature Off
CustomLog "/var/log/apache2/w0JhArMoDehc_access.log" combined
## Server aliases
ServerAlias www.awesome.dev
## SetEnv/SetEnvIf for environment variables
SetEnv APP_ENV dev
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/awesome/$1
</VirtualHost>
I'm trying to catch all requests for non-existing *.php files.
For example, if /var/www/awesome/index.php exists and I go to http://foo.com/index.php I get the correct response, but if /var/www/awesome/foo.php does not exist and I go to http://foo.com/foo.php, I am simply getting a response of File not found..
The .htaccess file isn't being read because Apache hands everything off to PHP-FPM.
I need to catch all 404 requests and show a common error page, as you would normally see on any site.
However, since Apache hands everything off to php-fpm, it doesn't seem to be handling these errors properly.

For anyone reading today, HERE is the correct answer, thanks to Tito1337 for his answer.
ProxyErrorOverride may give you problems or break your application if you set 404's or handle some errors elsewhere in your code, and is more complicated to implement.
Instead, you should pass the request to php-fpm only if the file exists. If the file does not exist, Apache will direct to your defined ErrorDocument. You can add this check around your PHP handler in the Apache config.
Example for CentOS 8:
#
# Redirect to local php-fpm (no mod_php in default configuration)
#
<IfModule !mod_php5.c>
<IfModule !mod_php7.c>
# Enable http authorization headers
SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
<FilesMatch \.(php|phar)$>
# NEW ADDITION - CHECK IF FILE EXISTS FIRST
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"
</If>
</FilesMatch>
</IfModule>
</IfModule>

I used to have the same problem and finally I fixed it.
Try add this after ProxyPassMatch setting:
ProxyErrorOverride on
BTW, do not forget your
ErrorDocument 404 /path/to/file
setting.

As many problems can occur during apache / php-fpm process, many errors can lead to the response
"File not found" and in logs "AH01071: Got error 'Primary script unknown\n'": (double slashes in paths, permissions,...)
To track them you can:
Put in your apache configuration "LogLevel debug" and check error log.
And/Or revert temporary your configuration to "simple apache only try", in my case it lead me to permissions problems (www 0751 needed to be 0755) error wich was invisible before.
Ps: Take care on a other thread, people says that using ProxyErrorOverride for that is "really a bad idea": Server Fault | Apache 2.4 + PHP-FPM + ProxyPassMatch

Related

How to activate rewrite URL from apache2 with Linux

I recently transfered all my websites from Windows to KUbuntu via virtual machine. And now I can't access a part of my website that is using rewrite URL...
I've already activated rewrite module with sudo a2enmod rewrite and AllowOverride in apache2 conf and restarted apache but that still does not work...
At the start, I got 404 errors (without default.conf AllowOverride things)
And now I've got a 500 internal error. How don't know how to proceed next, I Googled that problem, but nothing helped me.
EDIT: The 500 internal error happened from my .htaccess:
Header add Access-Control-Allow-Origin "*"
My default.conf:
<VirtualHost *:80>
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<Directory /var/www/html>
Options Indexes FollowSymLinks MultiViews
AllowOverride all
Order allow,deny
allow from all
RewriteEngine on
</Directory>
</VirtualHost>
My .htaccess
Options -Indexes
RewriteEngine on
# RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
# %{HTTP_HOST} = domain
# %{REQUEST_URI} = /vl_web/...
# rewrite pages
RewriteRule ^login$ ./login.php [L]
RewriteRule ^reglement$ ./rules.php [L]
RewriteRule ^changelog$ ./changelog.php [L]
RewriteRule ^government/lspd/$ ./government/panel/?team=LSPD [L]
RewriteRule ^government/bcso/$ ./government/panel/?team=BCSO [L]
# 404 image
# RewriteRule \.(gif|jpe?g|png|bmp) ./assets/img/misc/404.png [NC,L]
# Ht Errors
ErrorDocument 404 /vl_web/assets/resources/hterr/index.php?error=404
ErrorDocument 403 /vl_web/assets/resources/hterr/index.php?error=403
ErrorDocument 500 /vl_web/assets/resources/hterr/index.php?error=500
ErrorDocument 503 /vl_web/assets/resources/hterr/index.php?error=503
Any idea ?
error in my .htaccess /var/www/html/vl_web/.htaccess: Invalid command 'Header', perhaps misspelled or defined by a module not included in the server configuration
Header is part of mod_headers, which needs to be _enabled. mod_headers is considered an "Extension", in other words:
A module with "Extension" status is not normally compiled and loaded into the server. To enable the module and its functionality, you may need to change the server build configuration files and re-compile Apache. (Source: https://httpd.apache.org/docs/current/mod/module-dict.html#Status)
Although, this will often just need "enabling" in the server config. (Requiring a webserver restart.)
php errors (that do not happen on windows so that's pretty weird): Undefined index: nom in /var/www/html/vl_web/government/panel/files/index/row2.php on line 35, referer: http://192.168.1.29/vl_web/government/
Differences in PHP versions and/or different (default) error_reporting levels could account for the differences in behaviour here. Notably, "Undefined index" messages became an E_WARNING in PHP 7 - previously this was an E_NOTICE.
'LimitInternalRecursion' errors: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace., referer: http://192.168.1.29/vl_web/
This is most probably caused by rewrites in your .htaccess file.
Please add the contents of your .htaccess file to you question.
Of note here is that Windows is a case-insenstive filesystem and Linux is not. The same directive might not match on Linux.
Aside:
<Directory /var/www/html>
Options Indexes FollowSymLinks MultiViews
AllowOverride all
Order allow,deny
allow from all
RewriteEngine on
</Directory>
You probably want to disable MultiViews (you are explicitly enabling it above). If you are doing much with mod_rewrite (in .htaccess) then MultiViews can often result in conflicts (depends what you are doing).
Do you really want to enable directory Indexes?
Order and Allow are Apache 2.2 directives. You are evidentally on Apache 2.4 so should be using the Require directive instead.
You do not need to enable the RewriteEngine here unless you are using it in this scope (you are not). If you are using .htaccess then this will most probably override this anyway.
In other words, this should probably be written:
<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>

Ratchet websocket SSL

I use Ratchet websocket on my server. It is working well without SSL but i need to make it work with SSL.
I've read this stackoverflow post. Unfortunately the support of my PAAS don't use httpd.conf. They advised me to add the ProxyPass straight in the .htaccess.
Regarding adding the following line in httpd.conf file then here I
would like to inform that we are not using httpd on the server as
server is Debian based and we are using Apache web server. I believe
you can use the same line in htaccess file or it would be better if
you can consult with the developer regarding this.
# ProxyPass for Ratchet with SSL
ProxyPass /wss2/ ws://127.198.132.141:8000/
# Preventing the app from being indexed
Header set X-Robots-Tag "noindex, nofollow"
# Use the front controller as index file. It serves as a fallback solution when
# every other rewrite/redirect fails (e.g. in an aliased environment without
# mod_rewrite). Additionally, this reduces the matching process for the
# start page (path "/") because otherwise Apache will apply the rewriting rules
# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
DirectoryIndex app.php
# By default, Apache does not evaluate symbolic links if you did not enable this
# feature in your server configuration. Uncomment the following line if you
# install assets as symlinks or if you experience problems related to symlinks
# when compiling LESS/Sass/CoffeScript assets.
# Options FollowSymlinks
# Disabling MultiViews prevents unwanted negotiation, e.g. "/app" should not resolve
# to the front controller "/app.php" but be rewritten to "/app.php/app".
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
[...]
Unfortunately Adding ProxyPass /wss2/ ws://127.198.132.141:8000/ is crashing the server as if the .htaccess was incorrect.
Do you have any solutions or hints?
UPDATE :
From what i understand we can't use ProxyPass in .htaccess it should be only used in the server configuration or virtual host configuration.
I tried to explain it to the support but they do not seem to understand.
So apparently it is forbidden to use ProxyPass in .htaccess.
"ProxyPass and ProxyPassReverse are available only in the server
config and virtual host contexts."
Therefore if you can't add this line in the server config, could it be
added in the virtual host contexts?
Their answer :
As I have again reviewed all the settings on the server level which
includes the Apache modules and Firewall rules to make the Ratchet
websockets able to run on the server also the rules which we have
added in Firewall indicates that all the traffic from outside is
allowed on the port 8000 and I believe which should be sufficient to
allow outside connections for websocket.
As of now, it seems like you are trying to make the connection using
the different port (in case of https). As we have reviewed the server
settings and configurations and all seems to be good.
It would be highly appreciated if you can involves the developer in
this process so he can guide you better as he know the code level
things much better.
Right now attempting to connect with wss will throw :
WebSocket connection to 'wss://127.198.132.141/wss2/' failed:
WebSocket opening handshake was canceled
While using http with ws is working well.
In your virtual host add :
ProxyPass /wss2/ ws://yourdomain.xxx:8888/
(try with port 8888)
do not forget to restart apache service
virtual host example:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
<Directory /var/www/html/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<IfModule mod_dir.c>
DirectoryIndex index.php index.pl index.cgi index.html index.xhtml index.htm
</IfModule>
SSLCertificateFile /etc/letsencrypt/live/yourdomain.xxx/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.xxx/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
ServerName yourdomain.xxx
ProxyPass /wss2/ ws://yourdomain.xxx:8888/
</VirtualHost>
</IfModule>
Here you can find a full working example
https://github.com/ratchetphp/Ratchet/issues/100

Set PHP to always redirect on error 500s

On my website I would like it to redirect all error 500 errors to /500.html. As of current some of the page displays with GET
http://localhost/ [HTTP/1.0 500 Internal Server Error 1ms] in the Developer Tools. I have tried implementing this by editing /etc/apache2/sites-enabled/000-default.conf. The file looks like this:
<VirtualHost *:80>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
ErrorDocument 500 /500.html
</VirtualHost>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
I have also tried editing apache2.conf and .htaccess but I get the same result.
P.S: I have tried restarting Apache every time!
If you are trying to intercept 500 errors from PHP in apache using mod_php with SetHandler (A very common way), then the answer is that you can't. To the best of my knowledge it's not a supported feature.
However there are ways such as using PHP via it's FastCGI interface (PHP-FPM) and the Apache proxy module to achieve what you require.
First, you may need to ensure that mod_proxy and proxy_fcgi_module are installed on your server and enabled in the Apache config like so:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
Also ensure that PHP-FPM is installed and running as a service, the default port it uses is 9000.
Then replace your apache PHP configuration (possibly in /etc/httpd/conf.d/php.conf) with the following.
ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1
DirectoryIndex /index.php index.php
This will mean that you are now using the Apache Proxy module to send traffic to PHP. It is possible to instruct Apache to intercept error responses from the proxy module and use custom error handlers with the following in your VirtualHost section.
ProxyErrorOverride On
ErrorDocument 500 /500.html
Custom error documents are configured using the ErrorDocument directive, which may be used in global, virtualhost, or directory context. It may be used in .htaccess files if AllowOverride is set to FileInfo.
ErrorDocument 500 "Sorry, our script crashed. Oh dear"
ErrorDocument 500 /errors/not_found.html
ErrorDocument 500 http://error.example.com/server_error.html
The syntax of the ErrorDocument directive is:
ErrorDocument <3-digit-code> <action>
where the action will be treated as:
A local URL to redirect to (if the action begins with a "/").
An external URL to redirect to (if the action is a valid URL).
Text to be displayed (if none of the above). The text must be wrapped in
quotes (") if it consists of more than one word. When redirecting to
a local URL, additional environment variables are set so that the
response can be further customized. They are not sent to external
URLs.
Apache documentation
Keep in mind that the Apache looks for the 404 page located within the
site's server root. Meaning that if you place the new error page in a
deeper subdirectory, you need to include that in the line.
I found this code here:
<VirtualHost *:80>
ServerAdmin webmaster#localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
ErrorDocument 500 /custom_500.html
</VirtualHost>
then the custom pages go here: /var/www/html
and the file you need to edit is this or similar:
/etc/apache2/sites-enabled/000-default.conf
also enable these 2 mods, and then check for syntax errors and restart apache
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo apache2ctl configtest
sudo service apache2 restart
tell me if this works for your server, because on my server after some tries, it worked

URL rewriting for cakephp on local OSX apache

I have set up apache on OSX for local web dev use and made a dynamic vhost using dnsmasq such that visiting foo.dev will point to the /foo directory in my ~/Sites/sites folder.
This is what the vhost rule looks like:
<Virtualhost *:80>
VirtualDocumentRoot "/Users/harryg/Sites/sites/%1"
<Directory "/Users/harryg/Sites/sites">
Order allow,deny
Allow from all
Options Indexes FollowSymLinks Includes ExecCGI
# New directive needed in Apache 2.4.3:
Require all granted
AllowOverride All
Satisfy Any
</Directory>
ErrorLog "/Users/harryg/Sites/logs/sites/error.log"
CustomLog "/Users/harryg/Sites/logs/sites/access.log" common
ServerName sites.dev
ServerAlias *.dev
UseCanonicalName Off
</Virtualhost>
This all works great but I donwloaded a copy of cakephp and put it in a directory ~/Sites/sites/cake. When I visit http://cake.dev I get taken to the cakephp default app page which is expected but there is a warning about url rewriting not being properly configured and stylesheets etc do not load. I followed the guide and tried placing the following in the .htaccess for the cake directory:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
</IfModule>
But I then get a 500 Internal Server Error. Error log says:
Request exceeded the limit of 10 internal redirects due to probable
configuration error. Use 'LimitInternalRecursion' to increase the
limit if necessary. Use 'LogLevel debug' to get a backtrace.
Suggesting the rewriting rules are conflicting somehow. Any idea how to solve this?
Solved. The answer was to simply add the following line to my .htaccess files:
RewriteBase /
Not sure why it's necessary but it worked!

How to disable 301 redirect that adds trailing slash to directory name in Apache

The Apache 2.2.20 automaticaly redirects all requests which are points to directories and has no trailing slash to the same URL with trailing slash, like shown below:
GET /some/path/to/dir HTTP/1.1
Host: www.some.org
...
301 Moved permanently
Location: http://www.some.org/some/path/to/dir/
In all cases it is a fine behavior, but I need to turn off this feature for one special folder (not for all), and can't find were I can do it.
Searching for 'Rewrite' rules tells founds nothing - only directive LoadModule mod_rewrite.so. Also, there is no .htaccess files in directories server in directory tree.
Is there any other directives that make thing?
UPD1 I try to set up SVN trough HTTP with next config:
LoadModule dav_svn_module /opt/libexec/mod_dav_svn.so
LoadModule authz_svn_module /opt/libexec/mod_authz_svn.so
NameVirtualHost *:8000
<VirtualHost *:8000>
ServerAdmin admin#some.host.org
ServerName some.host.org
DocumentRoot /path/to/wwwroot
DAVLockDB /opt/var/lock/davlock/svndavlockdb
<Directory /path/to/wwwroot>
Options FollowSymLinks Indexes
# #AllowOverride None
Order allow,deny
Allow from all
</Directory>
<Directory /path/to/wwwroot/svn>
Options FollowSymLinks Indexes
AllowOverride None
Order allow,deny
Allow from all
</Directory>
CustomLog /path/to/wwwroot/log/access_log.txt combined
ErrorLog /path/to/wwwroot/log/error_log.txt
<Location /svn>
#AllowOverride None
#RewriteEngine Off
#RewriteOptions AllowNoSlash
DirectorySlash Off
DAV svn
SVNParentPath /path/to/wwwroot/svn
# SVNListParentPath on
AuthType Basic
AuthName "Subversion Repository"
AuthBasicAuthoritative Off
AuthUserFile /path/to/wwwroot/svn/.htauthfile
<Limit GET OPTIONS REPORT PUT POST DELETE PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK>
Require valid-user
</Limit>
</Location>
</VirtualHost>
UPD2 It seems that the "DirectorySlash Off" directive works only for "some.host.org/svn" and not works for "some.host.org/svn/repo1", "some.host.org/svn/repo2" etc - child directories not inherit this option.
UPD3 I try to add the following lines into config, but result is same - "DirectorySlash Off" work only for "/svn" and not for childs.
<LocationMatch "/svn/.*">
DirectorySlash Off
</LocationMatch>
SOLVED
Problem solved. This is a my mistake - I placed SVN repository root under DocumentRoot folder, so apache and web_dav can't understand, who must handle request. This applies to TortoiseSVN client at least.
Comments from SVN developers:
It means your httpd.conf is misconfigured. Usually this error happens when you've defined the Subversion virtual "location" to exist within two different scopes at the same time.
For example, if you've exported a repository as , but you've also set your DocumentRoot to be /www, then you're in trouble. When the request comes in for /www/foo/bar, apache doesn't know whether to find a real file named /foo/bar within your DocumentRoot, or whether to ask mod_dav_svn to fetch a file /bar from the /www/foo repository. Usually the former case wins, and hence the "Moved Permanently" error.
The solution is to make sure your repository does not overlap or live within any areas already exported as normal web shares.
It's also possible that you have an object in the web root which has the same name as your repository URL. For example, imagine your web server's document root is /var/www and your Subversion repository is located at /home/svn/repo. You then configure Apache to serve the repository at http://local.host/myrepo. If you then create the directory /var/www/myrepo/ this will cause a 301 error to occur.
Use mod_dir's DirectorySlash directive. Example from docs:
# see security warning in docs
<Location /some/path>
DirectorySlash Off
SetHandler some-handler
</Location>
Adding
DirectorySlash Off
to .htaccess worked fine for me.