VirtualDocumentRoot handling non-existent folders - apache

Using Apache, I have set up the VirtualDocumentRoot and it works this way:
<VirtualHost *:80>
UseCanonicalName Off
ServerName app.example.com
ServerAlias *.example.com
VirtualDocumentRoot "/home/domains/example.com/%1"
<Directory "/home/domains/example.com/*">
Options Indexes FollowSymLinks
AllowOverride All
Order Allow,Deny
Allow from all
</Directory>
</VirtualHost>
If I put the URL of http://mail.example.com, the DocRoot becomes /home/domains/example.com/mail, if it is http://www.example.com, the DocRoot becomes /home/domains/example.com/www, and so on.
Now I would like to check for the folder if it exists, like when the user requests a domain like http://myusername.example.com, the DocRoot checks /home/domains/example.com/myusername and it doesn't exist, so it should refer to /home/domains/example.com/404. Is this possible?
I have referred the following questions but no good:
VirtualDocumentRoot Domains and Subdomains
Apache VirtualDocumentRoot redirect non-existing domains

If you have virtual subdomains that are mapped to folders then couldn't you just check for the existance of the document root? If not exists redirect to the 404 subdomain which in turn should use /home/domains/example.com/404 perhaps like this.
<VirtualHost *:80>
UseCanonicalName Off
ServerName app.example.com
ServerAlias *.example.com
VirtualDocumentRoot "/home/domains/example.com/%1"
<Directory "/home/domains/example.com/*">
Options Indexes FollowSymLinks
AllowOverride All
Order Allow,Deny
Allow from all
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT} !-d
RewriteRule ^(.*) http://404.example.com/ [R=301,L]
</Directory>
</VirtualHost>
Or if the full virtualdocumentroot path is not being picked up by %{DOCUMENT_ROOT} variable because of the dynamic assignment, maybe try it this way by assiging subdomain to a env variable then use it to check the path.
<VirtualHost *:80>
UseCanonicalName Off
ServerName app.example.com
ServerAlias *.example.com
VirtualDocumentRoot "/home/domains/example.com/%1"
<Directory "/home/domains/example.com/*">
Options Indexes FollowSymLinks
AllowOverride All
Order Allow,Deny
Allow from all
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(.+)\.example\.com [NC]
RewriteRule ^(.*)$ - [E=virt_path:%1,N,NS]
RewriteCond %{DOCUMENT_ROOT}/%{ENV:virt_path} !-d
RewriteRule ^(.*) http://404.example.com/ [R=301,L]
</Directory>
</VirtualHost>

Interesting problem indeed. You need to handle it by placing a custom 404 handler in <VirtualHost> section.
Add this line just below <VirtualHost *:80>:
ErrorDocument 404 http://www.example.com/404.html
This will try to open /home/domains/example.com/www/404.html when you visit:
http://myusername.example.com
And corresponding folder doesn't exist in your filesystem.

Related

Server not reading htaccess file and redirect not working

My site is not reading the htaccess file. Even if I add Deny from all at the top, the site loads fine.
Permission is 644. I have a number of sites running on the server so Apache is set up correctly.
This is my virtualhost config:
<VirtualHost 12.34.56.78:80>
ServerAdmin webmaster#example.com
ServerName example.com
ServerAlias www.example.com
DocumentRoot /srv/www/example.com/public_html/
<Directory /srv/www/example.com/public_html/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog /srv/www/example.com/logs/error.log
CustomLog /srv/www/example.com/logs/access.log combined
RewriteEngine on
RewriteCond %{SERVER_NAME} =www.example.com [OR]
RewriteCond %{SERVER_NAME} =example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
This is what I'd added to .htaccess file to redirect www to non-www:
RewriteCond %{HTTP_HOST} ^(www\.)(.*) [NC]
RewriteRule (.*) https://%2%{REQUEST_URI} [L,R=301]
I tried adding it to virtualhost as well but it's still not redirecting.
After issuing an SSL Certificate with Let's Encrypt I had noticed it had created a duplicate conf file for port 443:
/etc/apache2/sites-available/example.com.conf
/etc/apache2/sites-available/example.com-le-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost 12.34.56.78:443>
ServerAdmin webmaster#example.com
ServerName example.com
ServerAlias www.example.com
DocumentRoot /srv/www/example.com/public_html/
<Directory /srv/www/example.com/public_html/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog /srv/www/example.com/logs/error.log
CustomLog /srv/www/example.com/logs/access.log combined
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
Prior to the LE, the original example.com.conf didn't have the AllowOverride All directive. So I assume what has happened is the contents were duplicated and then I only changed the original one.

apache http 80 .htacess, https 443 .htaccess does not work

When I run api.troop37bsa.org/user, I am able to access the page but when I run https://api.troop37bsa.org/user, I get a 404 error. When I run api.troop37bsa.org/?url=user or the secure version I get the correct page.
I am using a .htaccess file to rewrite the url so that everything after the subdomain is considered a parameter string.
So my question is two fold. How can I get https://api.troop37bsa.org/user to work and also what can I do to reduce the size of my .conf file and reduce or merge my .htaccess file.
I have an Apache Server 2.4.18.
My .conf file is setup as follows:
<VirtualHost *:80>
ServerAdmin kreichner#troop37bsa.org
ServerName api.troop37bsa.org
ServerAlias api.troop37bsa.org
DocumentRoot /var/www/troop37bsa.org/api/public
<Directory /var/www/troop37bsa.org/api/public>
DirectoryIndex index.php index.html
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
# Uncomment this directive is you want to see apache2's
# default start page (in /apache2-default) when you go to /
#RedirectMatch ^/$ /apache2-default/
</Directory>
AccessFileName .htaccess
ErrorLog /var/www/troop37bsa.org/api/public/apache_error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
#RewriteEngine on
#RewriteCond %{SERVER_NAME} =api.troop37bsa.org
#RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]
</VirtualHost>
<VirtualHost *:443>
ServerAdmin kreichner#troop37bsa.org
ServerName api.troop37bsa.org
ServerAlias api.troop37bsa.org
DocumentRoot /var/www/troop37bsa.org/api/public
<Directory /var/www/troop37bsa.org/api/public>
DirectoryIndex index.php index.html
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
allow from all
# Uncomment this directive is you want to see apache2's
# default start page (in /apache2-default) when you go to /
#RedirectMatch ^/$ /apache2-default/
</Directory>
AccessFileName .htaccess
ErrorLog /var/www/troop37bsa.org/api/public/apache_https_error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
In my subdomain folder (ie /var/www/troop37bsa.org/api/public) I have an .htaccess file
ReWriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $0#%{REQUEST_URI} ([^#]*)#(.*)\1$
RewriteRule ^(.+)$ %2index.php?url=$1 [QSA,L]
I am also using a letsencrypt SSL certificate that otherwise seems to be working fine.
Thanks
As I said in the comment section, It turns out that there was a conf file generated by letsencrypt, but it was pointing to the wrong directory publicl instead of public. When I changed the directory name. the .htaccess file did its job. I also removed the second *.443 virtualHost from my orginal conf to avoid further conflicts.
So others may not fall into the same problem the name of the conf was api.troop37bsa.org-le-ssl.conf. This set up the look ups from the SSL certificate.
the api.troop37bsa.org-le-ssl.conf code is as follows:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin kreichner#troop37bsa.org
ServerName api.troop37bsa.org
ServerAlias api.troop37bsa.org
DocumentRoot /var/www/troop37bsa.org/api/public
<Directory /var/www/troop37bsa.org/api/public>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
# Uncomment this directive is you want to see apache2's
# default start page (in /apache2-default) when you go to /
#RedirectMatch ^/$ /apache2-default/
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLCertificateFile /etc/letsencrypt/live/troop37bsa.org/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/troop37bsa.org/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
Thank you everyone for your help.

localhost redirects to one of local websites

I added to C:/windows/system32/drivers/etc/hosts:
127.0.0.1 mywebiste
and in httpd-vhosts.conf added:
<VirtualHost *:80>
ServerAdmin webmaster#dummy-host2.example.com
DocumentRoot "C:/xampp/htdocs/mywebiste"
ServerName mywebsite
ErrorLog "logs/error.log"
CustomLog "logs/access.log" common
<Directory "C:/xampp/htdocs/mywebiste">
Options Indexes FollowSymLinks Multiviews
Options -Indexes
AllowOverride None
Order allow,deny
allow from all
#RedirectMatch ^/$ / index.php
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php
</Directory>
</VirtualHost>
And now when I want to add new website to hosts file and httpd-vhosts.conf it renders 'mywebsite' and I cant access that website, even if I delete my virtualhost in httpd-vhosts.conf and remove my entry from hosts file it still renders 'mywebsite'. What should I do to fix this, I have no clue?
I believe you need
NameVirtualHost *:80
Prior to any <VirtualHost...> lines
See here
Nevermind, you have to restart the apache to apply new settings :) sorry. Btw it doesnt work at all wit NamevirtualHost.

How to forward https with php POST to a different domain via DNS?

I'm in the middle of updating a domain name which is currently using HTTPS and has an API that many users are connecting to daily.
What I need to do, is basically reroute all that traffic via DNS/the new server to the new domain name.
EG
Currently users are hitting: https://olddomain.com/api and we are now using https://newdomain.com/api so I need all calls from https://olddomain.com/api to be redirect, with php POST data intact to https://newdomain.com/api
CNAME doesn't seem to redirect it with post data, and it fails the API call. The CNAME is for olddomain.com pointing to newdomain.com, with apache2 mod rewrites which should take care of the redirects, if you navigate to olddomain.com it does forward to newdomain.com but the POST data does not go with it for some reason. The new server has both the old and new domain SSL certs, so that should be valid.
This is what my 000-default looks like in /etc/apache2/sites-enabled/000-default
<VirtualHost *:80>
ServerAdmin webmaster#localhost
ServerName newdomain.com
ServerAlias newdomain.com
RewriteEngine on
RewriteCond %{HTTP_HOST} ^olddomain.com
RewriteRule ^/(.*)$ https://newdomain.com/$1 [L,R=301]
RewriteCond %{HTTP_HOST} ^www.olddomain.com
RewriteRule ^/(.*)$ https://newdomain.com/$1 [L,R=301]
DocumentRoot /var/www
<Directory />
Options FollowSymLinks
AllowOverride ALL
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride ALL
Order allow,deny
allow from all
</Directory>
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
<VirtualHost *:443>
ServerAdmin webmaster#localhost
ServerName newdomain.com
SSLEngine on
SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
SSLCertificateFile /etc/apache2/ssl/certs/newdomain.com.crt
SSLCertificateKeyFile /etc/apache2/ssl/private/newdomain.key
SSLCertificateChainFile /etc/apache2/ssl/ssl_bundle.crt
DocumentRoot /var/www/
</VirtualHost>
<VirtualHost *:443>
ServerAdmin webmaster#localhost
ServerName olddomain.com
ServerAlias www.olddomain.com
RewriteEngine on
RewriteCond %{HTTP_HOST} ^olddomain.com
RewriteRule ^/(.*)$ https://newdomain.com/$1 [L,R=301]
RewriteCond %{HTTP_HOST} ^www.olddomain.com
RewriteRule ^/(.*)$ https://newdomain.com/$1 [L,R=301]
SSLEngine on
SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
SSLCertificateFile /etc/apache2/ssl/certs/olddomain.com.crt
SSLCertificateKeyFile /etc/apache2/ssl/private/olddomain.key
SSLCertificateChainFile /etc/apache2/ssl/ssl_bundle.crt
DocumentRoot /var/www/
</VirtualHost>
Did you try to use the HTTP status 307 (Temporary redirect) instead of 301? According to the W3C's HTTP/1.1 Status Codes Definitions, this method would allow you to preserve the original HTTP method (and therefore its associated body in case of a POST) of the redirected request, although the standards also mandates that the user agent asks confirmation from the user in case of a non-GET and non-HEAD.
eg., in you Apache configuration file, try to replace lines like:
RewriteRule ^/(.*)$ https://newdomain.com/$1 [L,R=301]
by:
RewriteRule ^/(.*)$ https://newdomain.com/$1 [L,R=307]
Note that some user agents have been reported not to be conforming to the standard regarding the HTTP 307 status (eg. not asking user confirmation), while some others do not understand it at all. So I suggest to test it carefully with the browsers you target if you choose to use this method and look for fallback mechanisms if needed.

rewrite rule for any subdomain to main domain

I have a site called mailcake.com, and I would like to have beta.mailcake.com, to redirect to mailcake.com, How can I achieve this? I have it like this on /etc/httpd/conf.d/mailcake.conf
NameVirtualHost *:443
<VirtualHost *:80>
DocumentRoot /var/www/mailcake
ServerName mailcake.com
ServerAlias www.mailcake.com beta.mailcake.com
RewriteEngine On
RewriteCond %{HTTP_HOST} ^beta\.mailcake\.com$ [NC]
RewriteRule (.+)$ "http://mailcake.com" [L,P]
ErrorLog /var/log/mailcake.com-error_log
<Directory />
Options Indexes FollowSymLinks
AllowOverride All
</Directory>
</VirtualHost>
<VirtualHost *:443>
DocumentRoot /var/www/mailcake
ServerName mailcake.com
ServerAlias www.mailcake.com
SSLEngine on
SSLCertificateFile /var/www/mailcake.crt
SSLCertificateKeyFile /var/www/mailcake.key
ErrorLog /var/log/mailcake.com-error_log
<Directory />
Options Indexes FollowSymLinks
AllowOverride All
</Directory>
</VirtualHost>
but it does not work
The following seems to work when tested with a few URLs:
RewriteCond %{HTTP_HOST} ^(beta\.)?mailcake\.com
RewriteRule (.*) http://mailcake.com/$1 [QSA]
Part of the important bit here is adding the $1 to ensure that any paths get added to the URL (in your example, http://beta.mailcake.com/stats/ would get redirected to http://mailcake.com/, which possibly isn't desireable. Also, adding [QSA] should ensure any query strings are passed along too.
If you're doing the redirect within the httpd.conf, I probably also wouldn't add [L], as it could stop other valid redirects within any .htaccess files from working.