mod_rewrite causing extra slash - apache

I'm trying to simply remove .php from the filenames on URLs. I'm implementing the solution from this StackOverflow answer so my VirtualHost looks like this,
# domain: example.com
# public: /var/www/html/example.com/public_html/
<Directory /var/www/html/example.com/public_html>
Options +FollowSymLinks
AllowOverride All
DirectoryIndex index.html index.htm index.php
</Directory>
<VirtualHost *:80>
ServerName example.com
Redirect / https://example.com/
</VirtualHost>
<VirtualHost *:443>
# Admin details
ServerAdmin vanguard#example.com
ServerName example.com
ServerAlias www.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
#Index File
DirectoryIndex index.html index.php
DocumentRoot /var/www/html/example.com/public_html
#Log Details
LogLevel warn
ErrorLog /var/www/html/example.com/log/error.log
CustomLog /var/www/html/example.com/log/access.log combined
RewriteEngine On
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule !.*\.php$ %{REQUEST_FILENAME}.php [L]
</VirtualHost>
Going to https://example.com resolves just fine, but if I try to go to https://example.com/examplefile it rewrites it to https://example.com//examplefile/

RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule !.*\.php$ %{REQUEST_FILENAME}.php [L]
In a virtual host context this RewriteCond directive will never match because at the time the directive is processed the request has not yet been mapped to the file system, so REQUEST_FILENAME simply contains the URL-path (as opposed to the absolute filesystem path), which is the same as REQUEST_URI.
(This wouldn't work in .htaccess either, but for a different reason. In .htaccess you can't rewrite to an absolute filesystem path, so whilst the RewriteCond should match, the RewriteRule is likely to trigger a 403 Forbidden error.)
To fix this in a server/virtual host context, you can modify these directives to use a URL-based look-ahead:
RewriteCond %{LA-U:REQUEST_FILENAME}.php -f
RewriteRule !\.php$ %{LA-U:REQUEST_FILENAME}.php [L]
However, neither your original directives nor this correction explains the double slash you are seeing in your example. Either an erroneously cached response or your web application?

Related

virtual host force https and redirect www to non-www, but no other subdomains

This is essentially the same question as htaccess force https and redirect www to non-www, but no other subdomains (i.e., I want to configure Apache to redirect all non-HTTPS and/or "www" URLs to HTTPS non-www URLs), but I want to configure Apache via a Virtual Host rather than an .htaccess file (since I read that avoiding .htaccess has some benefits).
I was able to get the following answer to work when using an .htaccess file: https://stackoverflow.com/a/34333450/1468130 But it did not work when I tried transferring that answer's configuration to my Virtual Hosts configuration; "https://www.domain.com" never redirected to "https://domain.com".
I read up on the differences between .htaccess and Virtual Host .conf files, and found this http://tltech.com/info/rewriterule-in-htaccess-vs-httpd-conf/ and this: https://www.digitalocean.com/community/questions/can-you-use-virtual-host-config-conf-to-redirect-www-domain-to-non-www?answer=15129 which seemed to hint that I could just wrap the configuration in a <Directory> block and it would work. Unfortunately, it doesn't ("https://www.domain.com" is still never redirected to "https://domain.com"), so I'm wondering if the Internet knew what I was doing wrong:
<VirtualHost *:80>
ServerName domain.com
ServerAlias www.domain.com
ServerAdmin admin#domain.com
DocumentRoot /var/www/domain.com/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<Directory /var/www/domain.com/>
RewriteEngine On
# match any URL with www and rewrite it to https without the www
RewriteCond %{HTTP_HOST} ^(www\.)(.*) [NC]
RewriteRule (.*) https://%2%{REQUEST_URI} [L,R=301]
# match urls that are non https (without the www)
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} !^(www\.)(.*) [NC]
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</Directory>
</VirtualHost>
I've also tried configuring <VirtualHost *:443> as Dusan Bajic suggested in the comments, but that has no effect either; https://www.domain.com still won't redirect to https://domain.com:
<VirtualHost *:443>
ServerName domain.com
ServerAlias www.domain.com
ServerAdmin admin#domain.com
DocumentRoot /var/www/domain.com/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLCertificateFile /etc/letsencrypt/live/domain.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/domain.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateChainFile /etc/letsencrypt/live/domain.com/chain.pem
<Directory /var/www/domain.com/>
RewriteEngine On
# match any URL with www and rewrite it to https without the www
RewriteCond %{HTTP_HOST} ^(www\.)(.*) [NC]
RewriteRule (.*) https://%2%{REQUEST_URI} [L,R=301]
</Directory>
</VirtualHost>
Also per the comments, I have tried the above *:443 configuration paired with a *:80 configuration with the <Directory> block changed to only redirect HTTP to HTTPS. But when I do that, "www" never gets removed.
<Directory /var/www/paradoxmayhem.com/>
RewriteEngine On
RewriteCond %{SERVER_NAME} =www.paradoxmayhem.com [OR]
RewriteCond %{SERVER_NAME} =paradoxmayhem.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]
</Directory>
Got it! Apparently, when I used letsencrypt (certbot) to configure SSL, it automatically created another virtual host file (at /etc/apache2/sites-enabled/domain.com-le-ssl.conf), which has its own definition for the domain.com *:443 Virtual Host, and seems to have taken precedence over any of the *:443 configuration I tried to set up before. I added the following code to the -le-ssl.conf file, and now my redirects finally work in all the cases I desired, using 100% Apache Virtual Host configuration:
<Directory /var/www/domain.com/>
RewriteEngine On
# match any URL with www and rewrite it to https without the www
RewriteCond %{HTTP_HOST} ^(www\.)(.*) [NC]
RewriteRule (.*) https://%2%{REQUEST_URI} [L,R=301]
</Directory>

vHost redirect not working at all

Goal: Redirecting every request to index.php except the files and folders (and their content) listed in the RewriteCond.
A friend did set up the server with me, but hadn't any time to fix this bug yet. The page automatically ends up at HTTPS.
When using this as 000-default.conf (/etc/apache2/sites-enabled/000-default.conf), the page just doesn't redirect to index.php. For example: Accessing www.page.com/uploads/38 works, although it should redirect to www.page.com/index.php. That's quite annoying as I'm emulating a filesystem and don't want to allow access to the files, at least not that way.
a2ensite 000-default.conf: Site 000-default.conf is already enabled
a2enmod rewrite: Module rewrite already enabled
This is my 000-default.conf:
<VirtualHost *:80>
ServerAdmin root#page.com
DocumentRoot /var/www/default
ServerName www.page.com
ServerAlias page.com
RewriteEngine On
<Location />
RewriteBase /
Options -Indexes
Options +FollowSymlinks
RewriteEngine On
RewriteCond %{REQUEST_URI} !^(index\.php|css|fonts|gfx|js|favicon\.ico)
RewriteRule ^(.*)$ index.php [L,QSA]
</Location>
LogLevel warn
ErrorLog ${APACHE_LOG_DIR}/default_error.log
CustomLog ${APACHE_LOG_DIR}/default_access.log combined
</VirtualHost>
<VirtualHost *:443>
ServerAdmin root#page.com
DocumentRoot /var/www/default
ServerName www.page.com
ServerAlias page.com
RewriteEngine On
<Location />
RewriteBase /
Options -Indexes
Options +FollowSymlinks
RewriteCond %{REQUEST_URI} !^(index\.php|css|fonts|gfx|js|favicon\.ico)
RewriteRule ^(.*)$ index.php [L,QSA]
</Location>
LogLevel warn
ErrorLog ${APACHE_LOG_DIR}/default_error.log
CustomLog ${APACHE_LOG_DIR}/default_access.log combined
SSLEngine on
SSLCertificateFile /etc/ssl/page.com.crt
SSLCertificateKeyFile /etc/ssl/page.com.key
SSLCertificateChainFile /etc/ssl/comodo-ca.crt
</VirtualHost>
When looking at default_error.log, I often find stuff like this:
Request exceeded the limit of 10 internal redirects due to probable configuration error.
And also:
RSA server certificate CommonName (CN) `page.com' does NOT match server name!?
Thanks in advance.
The %{REQUEST_URI} variable starts with a /, your regex doesn't so that condition will always be true, including when the URI gets rewritten to /index.php, this is causing the loop.
Replace the block with:
RewriteBase /
Options -Indexes
Options +FollowSymlinks
RewriteEngine On
RewriteCond $1 !^(index\.php|css|fonts|gfx|js|favicon\.ico)
RewriteRule ^(.*)$ index.php [L,QSA]
Additionally, I'm guessing you've bought a certificate for the name "page.com", not "www.page.com", which means when you go to "www.page.com" and the browser sees a certificate for "page.com", it'll throw an exception. You need a cert for "www.page.com" (and optionally with "page.com" as an alternate name)/.
EDIT
Hmm, this didn't work for me either inside the <Location /> container. But this worked outside of the container by itself:
RewriteEngine On
RewriteCond $1 !^(index\.php|css|fonts|gfx|js|favicon\.ico)
RewriteRule ^/(.*)$ /index.php [L,R]

.htaccess strange behaviour

If I put theese lines to .htaccess everything works well (when I'm going to http://www.example.ru I'm redirected to http://example.ru).
RewriteEngine On
# Installation directory
RewriteBase /
# Redirect all www to non-www
RewriteCond %{HTTP_HOST} ^www.example.ru [NC]
RewriteRule ^(.*)$ http://example.ru/$1 [L,R]
But If I put exactly same lines to <VirtualHost> -> <Directory> section trying to go to http://www.example.ru redirects me to http://example.ru/www.
Anybody knows why?
UPD
New VirtualHost:
<VirtualHost *:80>
ServerName example.ru
ServerAlias www.example.ru
ServerAdmin webmaster#localhost
DocumentRoot /home/example/www/example.ru/www
RewriteEngine On
<Directory /home/example/www/example.ru>
Options FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
</Directory>
ErrorLog /home/example/www/example.ru/log/error.log
LogLevel warn
SetEnvIf Remote_Addr 127.0.0.1 loopback
CustomLog /home/example/www/example.ru/log/access.log combined env=!loopback
# Redirect all www to non-www
RewriteCond %{HTTP_HOST} ^www.example.ru [NC]
RewriteRule ^(.*)$ http://example.ru$1 [L,R]
</VirtualHost>
Spent some time I've figured out, that in VirtualHost section, pattern will match against the part of the URL after the hostname and port, and before the query string (in my case "/").
In Directory section, pattern will match against the filesystem path.

htaccess moved to vhost not playing nice

I wanted to move my .htaccess file - redirects into my vhost conf file...
This was working - but the htaccess redirects were not...
<VirtualHost *:80>
ServerName dev.x.com
ServerAlias dev.x.com
DocumentRoot "C:/wwwroot/x"
Alias /modules/ "C:/wwwroot/x/_my_modules/"
ErrorLog "C:/wwwroot/x/_my_logs/error.log"
CustomLog "C:/wwwroot/x/_my_logs/access.log" combined
<Directory "C:/wwwroot/x/_my_logs/" >
Options FollowSymLinks
AllowOverride All
Order deny,allow
Deny from all
Satisfy all
</Directory>
</VirtualHost>
Then i did this -
<VirtualHost *:80>
ServerName dev.x.com
ServerAlias dev.x.com
DocumentRoot "C:/wwwroot/x"
Alias /modules/ "C:/wwwroot/x/_my_modules/"
ErrorLog "C:/wwwroot/x/_my_logs/error.log"
CustomLog "C:/wwwroot/x/_my_logs/access.log" combined
<Directory "C:/wwwroot/x/_my_logs/" >
Options FollowSymLinks
AllowOverride All
Order deny,allow
Deny from all
Satisfy all
</Directory>
RewriteEngine on
# if requested URI is not a file and not a directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# externally redirect to /newLocation/{URI}
# RewriteRule (.*) index.php?_req=$1 [L]
# could use a redirect to a new directory ---
RewriteRule ^ /_mf_modules%{REQUEST_URI} [L,R=301]
</VirtualHost>
My objective was this:
I wanted any "directory" request - that didn't exist - to be rerouted to a directory of that name in the _my_modules dir.
IF a file did not exist I wanted to redirect to the to a directory of that name in the _my_modules dir.
So if www.x.com/xxx was the url... and 'xxx' dir didn't exist, I'd redirect to www.x.com/_my_modules/xxx
and like wise if www.x.com/xxx.php was requested - but xxx.php DIDN'T exist, they wou be redirected to www.x.com/_my_modules/xxx
however (even though there is an index.php in each dir) these always results in th eURL redirecting to this...
The requested URL /modules/modules/modules/modules/modules/modules/modules/modules/modules/modules/modules/modules/modules/modules/modules/modules/modules/modules/modules/_my_modules/ was not found on this server.
So I got fed up and changed the vhost file back to what I had to begin with, restarted Apache, and it's still redirecting, I can't get rid of the behavior.
You can move the RewriteRules from a .htaccess to the VirtualHost environment by putting them in a <Directory> environment in your vhost configuration.
In your case, try to cut and paste your rewrite rules in <Directory "C:/wwwroot/x/_my_logs/" >
If you really want to put them in the VirtualHost environment, you have to modify the paths in them: RewriteRules in .htaccess or are relative to the directory, RewriteRules in the VirtualHost are absolute to the root of the filesystem or the DocumentRoot.
rewritecond example:
RewriteCond %{REQUEST_FILENAME} !-f
should be in vhost:
RewriteCond /your/documentroot/%{REQUEST_FILENAME} !-f
rewriterule example:
RewriteRule (.*) /your/documentroot/index.php?_req=$1 [L]
should be in vhost:
RewriteRule (.*) index.php?_req=$1 [L]

Per-server rewriterules not working

I've got a VirtualHost directive in /etc/apache2/openpanel.d/www.example.com.conf:
<VirtualHost *:80>
ServerAdmin "jon#example.com"
DocumentRoot /home/openpanel-admin/sites/www.example.com/public_html
ServerName www.example.com
ServerAlias example.com
<Directory /home/openpanel-admin/sites/www.example.com/public_html>
AllowOverride All
Allow from all
</Directory>
Include /etc/apache2/openpanel.d//www.example.com.inc/[^.#]*
Include /etc/apache2/openpanel.d//global.inc
</VirtualHost>
And I've the following in /etc/apache2/openpanel.d/www.example.com.inc/RewriteRules
<Directory /home/openpanel-admin/sites/www.stallfinder.com/public_html>
Options +FollowSymlinks
RewriteEngine On
RewriteRule agricultural-show-c780.html /search/event/agricultural-shows/1/ [R=301,L]
RewriteRule antique-fair-c596.html /search/event/antique-and-collectors-fairs/1/ [R=301,L]
RewriteRule baby-and-toddler-fairs-c896.html /search/event/baby-and-toddler-fairs/1/ [R=301,L]
RewriteRule book-fair-c631.html /search/event/book-fairs/1/ [R=301,L]
# etc... there are ~3000 of these
</Directory>
And I've got an .htaccess file in /home/openpanel-admin/sites/www.example.com/public_html:
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
# Search pages
RewriteRule ^search/(stallholder|event)/?$ /find-$1.php [L]
RewriteRule ^search/(stallholder|event)/([^/]+)/([0-9]+)/? /$1.php?name=$2&id=$3 [L]
But the RewriteRules in the include file (RewriteRules) don't appear to be parsed/used.
The file is being included because I can put non-allowed stuff in there and apache will fail to load the config file, but if I turn on Apache redirect logging, then I only see [perdir] lines as if all the RewriteRules I've got in the RewriteRules include aren't being processed.
The global.inc file is empty, and the RewriteRules in my .htaccess file work fine.
Any clue what I'm doing wrong?
Try adding RewriteOptions directive into your .htaccess to allow executing rewrite rules on parent (upper) level.
http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriteoptions