Apache dynamic wildcard host rewrite with dynamic subdomains - apache

I'm currently in the process of converting an old apache vhost, where one is currently created for each new release, to a dynamic host that can handle all the subdomains so we don't have to create a new one all the time. I need some help! We're using apache v2.2.
The Goal
Dynamic all the things. To have a single virtual host that handles all redirects for a specific set of subdomains. The url is below, note that sub1 and branch are dynamic and could be anything.
sub1.branch.sandbox.domain.com
The directory structure for this is as follows:
/var/www/vhosts/branch/sub1.branch.sandbox.domain.com
As you can see above, the directory structure has the branch as a sub-directory before the full url is the name of another sub-directory.
Also, /images/ in the url needs to forward to shared-httpdocs/images for each domain.
The vhost I have so far
<VirtualHost *:80>
ServerName branch.sandbox.domain.com
ServerAlias *.branch.sandbox.domain.com
VirtualDocumentRoot /var/www/vhosts/branch/%0
Options Indexes FollowSymLinks
# Rewrite Engine Stuff Here
RewriteEngine On
DirectoryIndex index.php
# Assets needs to be forwarded - currently not working
RewriteCond %{REQUEST_URI} ^/(css|js|images)/.*
RewriteRule .*$ /var/www/vhosts/%0/shared-httpdocs/%1$ [L]
# The HTTP dispatcher - currently not working
RewriteCond %{HTTP_HOST} ^(.*)\.branch\.sandbox\.domain\.com [NC]
RewriteRule ^(.*)$ /var/www/vhosts/%1/applications/portal/dispatchers/http.php [L,QSA,NS,NE,NC]
</VirtualHost>
The old host I'm trying to copy
This is the old vhost I'm trying to convert from. It's horrible, messy, and our ops has to create a new DNS entry every time. What a joke! I need to sort this out...
<VirtualHost *:80>
# Notice how the stupid convention below will require a new DNS entry each time?
ServerName sandbox.branch.domain.com
ServerAlias sandbox.api.branch.domain.com
DocumentRoot /var/www/vhosts/sandbox.branch.domain.com/applications/portal/httpdocs
<Directory "/var/www/vhosts/sandbox.branch.domain.com/applications/portal/httpdocs">
allow from all
order allow,deny
# Enables .htaccess files for this site
#AllowOverride All
RewriteEngine On
# Rewrite all non-static requests to go through the webapp
RewriteCond %{REQUEST_URI} ^/(css|js|images)/.*
RewriteRule .* - [L]
# Rewrite everything else to go through the webapp
RewriteRule ^(.*)$ /dispatchers/http.php [QSA,L]
</Directory>
<Directory "/var/www/vhosts/sandbox.branch.domain.com/applications/portal/dispatchers">
allow from all
</Directory>
# Allow us to rewrite to the webapp without it being in the webroot
Alias /dispatchers /var/www/vhosts/sandbox.branch.domain.com/applications/portal/dispatchers
# Get shared/ to point to the shared static resources
Alias /shared /var/www/vhosts/sandbox.branch.domain.com/shared-httpdocs
</VirtualHost>
A new DNS entry is required each time we have a new branch, so I'm trying to mitigate this by providing a dynamic subdomain vhost (see the vhost I have so far). I've gone from not even being able to match /images/ in the url to a permanent redirect loop.
How can I achieve my goal? I know it's a little complex. If I can't do it, I'll just have to write a script that will generate a new vhost each time but a dynamic one that 'just works' would be fantastic. I've put two days into this so far, I'm no sysadmin. Your help would be greatly appreciated.
Resources I have been using:
mod_rewrite official docs - Shows the basics like things on conditions with REWRITE_COND
Sub domain rewriting - A question on subdomain rewriting
Asset rewriting - Another question on rewriting things like images / css / js, which doesn't seem to work for me

It's not a complete answer, but is too long for comment.
The %0 (%0 to %9) in a rewrite rule are back references to captures in the last RewriteCond. It seems to me you wanted instead the host name. Also it seems you miss the "branch" part of the path. In the Asset's rewrite you also throw away the filename part.
# Assets needs to be forwarded - currently not working
RewriteCond %{REQUEST_URI} ^/(css|js|images)/(.*)
RewriteRule .*$ /var/www/vhosts/branch/%{HTTP_HOST}/shared-httpdocs/%1/%2$ [L]
# The HTTP dispatcher - currently not working
RewriteCond %{HTTP_HOST} ^(.*)\.branch\.sandbox\.domain\.com [NC]
RewriteRule ^(.*)$ /var/www/vhosts/branch/%{HTTP_HOST}/applications/portal/dispatchers/http.php [L,QSA,NS,NE,NC]
You can get debugging help also from mod_rewrite dedicated logging with RewriteLog and RewriteLogLevel directives.
Hope this will bring you further.

Related

Redirect and mask URL but leave query parameters (Apache or htaccess) [duplicate]

After looking on the internet for about an hour, I didn't find the answer to my question. So I'm searching with the wrong keywords or what I want is not possible.
What I want:
I have multiple domains with different extensions, for example:
mydomain.be
mydomain.nl
Now what I want is that the mydomain.be is redirected to mydomain.nl. The solution for this I have found on the internet and shown below, with the need of .htaccess:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^mydomain.be$ [OR]
RewriteCond %{HTTP_HOST} ^www.mydomain.be$
RewriteRule (.*)$ http://www.mydomain.nl/$1 [R=301,L]
With this code, when you type mydomain.be you will be redirect to mydomain.nl. But also the URL in the addressbar is changed to mydomain.nl. What I want is to keep the URL in the addressbar mydomain.be.
So, mydomain.be:
keep URL
show content of mydomain.nl
How To?
It is possible to get it done via mod_rewrite but make sure mod_proxy is enabled in your Apache's httpd.conf. Once that is done enable mod_rewrite and .htaccess through httpd.conf and then put this code in your .htaccess under DOCUMENT_ROOT directory:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^(www\.)?mydomain\.be$ [NC]
RewriteRule ^ http://www.mydomain.nl%{REQUEST_URI} [L,NE,P]
Take note of flag P which is used for handling the proxy request.
Read more about flag: P in mod_rewrite
Another option without hassling with .htaccess would be to point both domains to the same document root or setting one domain as an alias for the other, depending on how you are able to configure your Apache. However, this has downsides:
If your content management system uses absolute URLs a user who clicks on mydomain.nl on a link will be directed to the mydomain.be domain (WordPress does this, as an example).
Search engines punish this behaviour by placing you further down on the search results. at least Google does, they have an interesting blog post about duplicate content. Not sure about competitors.
An example apache config could be:
<VirtualHost *:80>
ServerName mydomain.nl
ServerAlias mydomain.be
DocumentRoot /var/www/mydomain.nl/htdocs
</VirtualHost>

Phabricator rewrite rules configuring issue

I'm having trouble installing phabricator. It actually seems like it would be a simple thing. I copied the example code exactly.
apache2.conf:
<VirtualHost *>
# Change this to the domain which points to your host.
ServerName localhost
# Change this to the path where you put 'phabricator' when you checked it
# out from GitHub when following the Installation Guide.
#
# Make sure you include "/webroot" at the end!
DocumentRoot /var/www/phabricator/webroot
RewriteEngine on
RewriteRule ^/rsrc/(.*) - [L,QSA]
RewriteRule ^/favicon.ico - [L,QSA]
RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
</VirtualHost>
<Directory "/var/www/phabricator/webroot">
Require all granted
</Directory>
Whenever I go to the server IP on a browser, it gives me this error:
Request parameter '__path__' is not set. Your rewrite rules are not configured correctly.
I found that this was part of the phabricator code:
if (!isset($_REQUEST['__path__'])) {
self::didFatal(
"Request parameter '__path__' is not set. Your rewrite rules ".
"are not configured correctly.");
}
Anyone have any idea how to get past this?
I had a similar issue with Phab and solved it with the following:
Place the Directory segment inside the VirtualHost segment.
Are you running any other Virtual Server in your system? If so, specify the port *:80 (Or try a different one Remember adding Listen 8081 before declaring the VirtualHost segment if you try another port)
And last replace the content of the Directory segment with this:
Order allow,deny
Allow from all
I was also facing same issue.
Just place
RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
and remove following line from your apache2.conf.
RewriteRule ^/rsrc/(.*) - [L,QSA]
RewriteRule ^/favicon.ico - [L,QSA]

htaccess and rewriting

I just made a subdomain on my webside mainly becouse i want a spesific address to it.
Lets say my website is : http://website.com
And my subdomain is http://sub.website.com with its main folder in /home/username/public_html/sub/
When i enter the subdomain address the address suddently changes to http//website.com/sub/
how can i keep the subdomain address?
EDIT for Dennis:
i have a rule that directs all http://www.website.com to http://website.com
I use
RewriteEngine on
Redirect to non-www
RewriteCond %{HTTP_HOST} !^(website\.com)?$
RewriteRule (.*) http://website.com/$1 [R=301,L]
even if i comment out this the address still changes to
http://website.com/sub/
Best of regards,
Alexander
I would imagine something like this would work (not tested):
Options FollowSymLinks
RewriteEngine On
RewriteCond %{HTTP_HOST} !^website\.com
RewriteCond %{HTTP_HOST} ^([^.]+)
RewriteRule \?cat_id=([0-9]+)&photo_id=([0-9]+) http://website.com/$1/$2/
RewriteRule ^/(.*)/(.*)/ /%1.php?cat_id=$1&photo_id=$2 [P]
Note: according to the documentation, Options FollowSymLinks needs to
be an option you can override to get the rewrite to work.
The first RewriteCond will ensure the "webiste.com" host is not rewritten (but
domains like sub.website.com will). The second one matches anything
up to the first dot of the hostname. Both of these must succeed and if so the host
part is accessible in %1.
The first RewriteRule rewrites the args to the php script to the directory paths
(a change seen on URL on the browser). The next RewriteRule uses the [P]
flag to proxy any requests of the form /xx/yy/ to %1.php (our remembered host name)
with the args passed to the php script.
As I've stated, this is not tested, but hopefully it will get you "in the right direction".
EDIT: removed the [R] from the first rewrite rule.
Another solution is to have a Virtualhost dedicated for your subdomain (that should already be the case, if not you'll get a lot of problems) and to make this VirtualHost ignore .htaccess instructions of the master domain. You should really try to keep your subdomain configuration independant of the master domain domain configuration.
Let's say your documentRoot in the subdomain VH is /home/username/public_html/sub/, when Apache serve the index.php or index.html file or anything else in this directoy it performs a recursive search of all .htaccess in /home/username/public_html/sub/, /home/username/public_html/, /home/username/, /home/ and /. So the rules defined in your master domain (I think it's in /home/username/public_html/) are applied.
You can tell this subdomain VirtualHost to ignore all .htaccess files which are before the VH DocumentRoot by adding:
<Directory />
AllowOverride None
</Directory>
<Directory /home/username/public_html/sub/>
AllowOverride All
</Directory>
You could even remove the AllowOverride All, remove all .htaccess and put the things you have in the .htaccess of your subdomain (if you have one) directly in the <Directory /home/username/public_html/sub/> section, same effect without having Apache searching for configuration parts on the filesystem (so faster).

Dynamically configured virtual hosting

Helo!
I would like to prepare a dynamic virtual host for all subdomains that will be created in future using mod_rewrite. All subdomains would be configured prety much same way, so i thought of using dynamic VH configuration.
I want my document root for each subdomain to be /home/user/public_html/subdomainName.
I've tried with following configuration, but had no success:
<VirtualHost xxx.xxx.xxx.xxx:80>
# get the server name from the Host: header
UseCanonicalName Off
<Directory /home/user/public_html/>
# ExecCGI is needed here because we can't force
# CGI execution in the way that ScriptAlias does
Options FollowSymLinks ExecCGI
</Directory>
RewriteEngine On
# a ServerName derived from a Host: header may be any case at all
RewriteMap lowercase int:tolower
#rule that is suposed to set document root of virtual host!???
RewriteRule ^([a-z-]+)\.domain\.com/?(.*) /home/user/public_html/$1/$2
</VirtualHost>
The rule or somethinh seems to be wrong andit doesn't apply. I've never worked with dynamic VH before so i have no idea where i'm wrong...
This is a need a lot of people had before you. So there's an apache module which can do that for you mod_vhost_alias http://httpd.apache.org/docs/2.2/mod/mod_vhost_alias.html
Provides for dynamically configured
mass virtual hosting
instead of dynamic virtual hosts, you can also do this using wildcard dns which means configuring {anything}.yourdomain.tld to point to your server.
This will also get you same document root for each domain.
note that you will need to add ServerAlias *.yourdomain.tld to the virtual host entry
With RewriteRule you can't access the domainname. Also use RewriteCond for that part and use %1 etc. for backreference.
RewriteCond %{HTTP_HOST} ^([a-z-]+)\.domain\.com$ [NC]
RewriteRule (.*) %1/$1
The only problem is this will create a continues loop of prepending the subdomainname string. So what I normally do is create a separate folder for subdomains, like 'subdomains'
RewriteRule ^subdomains - [L]
RewriteCond %{HTTP_HOST} ^([a-z-]+)\.domain\.com$ [NC]
RewriteRule (.*) subdomains/%1/$1

How can I implement a global RewriteCond / RewriteRule in Apache that applies to all virtual hosts?

The title pretty much says it all. :-) I have lots of virtual hosts and I want to put a single rewriting block at the top of the httpd.conf file that rewrites URLs no matter which virtual host the request might be directed to. How the heck do I do this?
I found this but my question is the same: how can I do this without resorting to .htaccess files and performing some other action for each virtual host?
OMGTIA!
Specify RewriteOptions InheritDown in the parent scope (such as httpd.conf) to get your rules applied in child Virtual Hosts without modifing them.
This will only work on Virtual Hosts where the RewriteEngine directive is set to on:
Note that rewrite configurations are not inherited by virtual hosts. This means that you need to have a RewriteEngine on directive for each virtual host in which you wish to use rewrite rules.
(source)
Apache supports this since 2.4.8 (not available at the time of the original question).
From documentation for RewriteOptions:
InheritDown
If this option is enabled, all child configurations will inherit the configuration of the current configuration. It is equivalent to specifying RewriteOptions Inherit in all child configurations. See the Inherit option for more details on how the parent-child relationships are handled.
Available in Apache HTTP Server 2.4.8 and later.
InheritDownBefore
Like InheritDown above, but the rules from the current scope are applied before rules specified in any child's scope.
Available in Apache HTTP Server 2.4.8 and later.
IgnoreInherit
This option forces the current and child configurations to ignore all rules that would be inherited from a parent specifying InheritDown or InheritDownBefore.
Available in Apache HTTP Server 2.4.8 and later.
(http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriteoptions)
By default, mod_rewrite configuration settings from the main server context are not inherited by virtual hosts. To make the main server settings apply to virtual hosts, you must place the following directives in each <VirtualHost> section:
RewriteEngine On
RewriteOptions Inherit
click http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html to find more information
Looks like the simplest possible solution is to add
RewriteOptions inherit
to each VirtualHost directive. This is at least a lot simpler than messing with .htaccess files. Apache is pretty clear on the fact that
by default, rewrite configurations are
not inherited. This means that you
need to have a RewriteEngine on
directive for each virtual host in
which you wish to use it.
(http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html)
and apparently the way to change the default is via RewriteOptions in the child (vhost or director), so you have to do something in each child.
I've never tested it, so it might not work, but I would try adding an include directive in all of the virtual host blocks to a single file. You would have to change each virtual host configuration block once, but after that, you should have a central place from which to make changes. YMMV.
If you're only trying to rewrite something in the domain part of the name, e.g. to fix a common misspelling, you don't even need the 'inherit' option. I setup a no-name virtual host to catch all invalid host names and respell them correctly before redirecting them.
Since this uses redirects, the appropriate virtual host will be found after the rewrites have been applied.
Options +Indexes +FollowSymLinks
RewriteEngine on
# If it begins with only domain.com, prepend www and send to www.domain.com
RewriteCond %{HTTP_HOST} ^domain [NC]
RewriteRule ^(.*) http://www.domain.com$1 [L,R=301]
# Correct misspelling in the domain name, applies to any VirtualHost in the domain
# Requires a subdomain, i.e. (serviceXXX.)domain.com, or the prepended www. from above
RewriteCond %{HTTP_HOST} ^([^.]+\.)dommmmmain\.com\.?(:[0-9]*)?$ [NC]
RewriteRule ^(.*) %{HTTP_HOST}$1 [C]
RewriteRule ^([^.]+\.)?domain.com(.*) http://$1domain.com$2 [L,R=301]
# No-name virtual host to catch all invalid hostnames and mod_rewrite and redirect them
<VirtualHost *>
RewriteEngine on
RewriteOptions inherit
</VirtualHost>
You may want to use InheritDownBefore to avoid having to add more junk to your vhosts.
An example of a global letsencrypt alias:
# letsencrypt
<IfModule alias_module>
Alias /.well-known/ /var/www/html/.well-known/
</IfModule>
<IfModule mod_rewrite.c>
# prevent vhost rewrites from killing the alias
RewriteEngine On
RewriteOptions InheritDownBefore
RewriteCond %{REQUEST_URI} ^/\.well\-known
RewriteRule . - [L,PT]
</IfModule>
Then you can do this in each of your vhosts, with no other directives:
<VirtualHost *:80>
....
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^/.* /index.php [L,PT]
</IfModule>
</VirtualHost>
Thanks to everyone to answered above. It helped me find my answer.
Question has been answered already, I just wanted to add an example in case you are using Google Compute Engine. It says it requires Apache HTTP Server 2.4.8 BUT it works with Apache/2.4.25 (Debian). Even when I try to upgrade, I cannot go past Apache/2.4.25. It says this version is the latest version.
Here's an example of how to implement.
RewriteOptions InheritDown
RewriteCond %{HTTP_HOST} ^www\. [NC,OR]
RewriteCond %{HTTP_HOST} !\.co$ [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)\.[^.]+$ [NC]
RewriteRule ^ https://%1.co%{REQUEST_URI} [L,NE,R=301]
<VirtualHost *:80>
RewriteEngine On
ServerAlias *.*
</VirtualHost>
ALSO OF NOTE (For Testing):
When you are testing your rewrite engine. It is really easy to get confused about if it is working or not because of cache and cookies. If you got it to work once on a browser, it will continue to work even if you delete the rewrite code. Testing rewrite is really annoying sometimes. You might think it works but then it stops or starts.
Best way to test rewrite code is to open an incognito tab in your browser, clear or cookies and cache. Open developer mode just in case. DO NOT JUST REFRESH. You need to click into the URL and refresh. Or open new tab. Or copy/paste URL into new window. If you use same window with refresh, it might be just redoing results from the past instead of renewing the new code.
I've always used a "catch-all" VHost for directives I wanted across the board, like......
Listen 80
NameVirtualHost *:80
<VirtualHost *:80>
ErrorLog "/var/log/apache2/error_log"
</VirtualHost>
<VirtualHost *:80>
ServerName alloftherestoftheVHosts.com
DocumentRoot "/ServiceData/.........
............
And it's always seemed to work... error logs were getting combined properly, etc...... but it IS possible that this was the result of an earlier / conflicting / like-minded directive.
Personal note.. Whoever dreamed up the Apache configuration schema and syntax was a dingbat, or a group of dingbats, who spent too much time in their cave.... The whole thing should be exorcised and XMLized, or something! Although they are both wildly different... the Hello-Kitty setup process of Cherokee.. to the viciously succinct NGinx config.... are both so much more logical..