Redirect and Rewrite Rule for Apache - apache

I am trying to install a CalDAV client on my apache webserver, and I am having trouble using a combination of redirects and rewrite rules to get a desired url.
The document root for my webserver is /var/www, and the calendar files are stored in /var/www/agendav/web/public. If I go in through my browser at <website>/agendav/web/public/index.php, I have no trouble getting to the interface and using it, so that is not a problem. However, my desired URL for the calendar is <website>/calendar/, instead of having to go down through the agendav folder tree. I have been trying to perform this with a redirect rule, and a rewrite rule, but to very little success. I have found a few other answers here that have gotten me close, such as this one and this one, with a working redirect, but I am still having issues with the rewrite rule. Here is the current solution I have:
# Rules for the Calendar
Redirect "/calendar" "/agendav/web/public"
RewriteEngine On
RewriteCond %{REQUEST_URI} "^/agendav"
RewriteRule "^/agendav/web/public/(.*?)$" "/calendar/$1"
My current solution seems a little circular. First, I redirect the user to the agendav folder, then then try to hide the redirect behind a rewrite rule, when it seems that I could just get away with a single rewrite rule. Unfortunately the group I am working for is not big enough to have their own dedicated server manager, and I ended up with the job despite knowing very little about it. Any help to get this would be greatly appreciated.

You don't need the redirect, you can do it with just a rewrite rule, the problem was that you have the condition and the rule reversed, you were using the real path for the conditions instead of the "virtual" path:
RewriteEngine on
RewriteCond %{REQUEST_URI} "^/calendar" [NC]
RewriteRule "^calendar/(.*)" "/agendav/web/public/$1"
With this rules all requests for http://yourwebsite/calendar/* are internally served with http://yourwebsite/agendav/web/public/*.

Related

Apache RewriteRule for Two URLs

I'm trying to redirect the following two URLs:
https://www.example.com/blog/content/Das.com
https://www.example.com/blog/content/page/2
To:
https://www.example.com/blog/content
Using:
RewriteEngine on
RewriteRule (blog/content/Das.com|blog/content/page/2) /blog/content [L,R=301]
But it's not working. What am I doing wrong?
Are you sure you want to redirect different requested URLs to the same target URL? That means you will loose the information which URL has originally been requested. So you cannot differ between the two requests any more. If you actually only want to internally rewrite those URLs, so that they can be processed by the same controller, then just leave away the R=301 flags below...
I personally would suggest to implement two separate rules. Readability of code is of high importance, it should be possible to immedately understand what code does even for someone who did not write the code:
RewriteEngine on
RewriteRule ^/?blog/content/Das\.com$ /blog/content [R=301,END]
RewriteRule ^/?blog/content/page/2$ /blog/content [R=301,END]
But if you prefer a single rule you certainly can combine that:
RewriteEngine on
RewriteRule ^/?blog/content/(?:Das\.com|page/)$ /blog/content [R=301,END]
For this to work the rewriting module needs to be loaded into the http server obviously. You should prefer to implement such rules in the actual http server's host configuration. You can use a distributed configuration file (".htaccess") in case you do not have control over the normal configuration, but that comes with a performance penalty. And obviously also needs to be enabled first. You'd need to place that file in the top folder of your DOCUMENT_ROOT in that case.
In general it is a good idea to start out with a R=302 temporary redirection and only to change that to a R=301 permanent redirection once you are sure things work as expected. That prevents annoying caching issues.

Apache %{REQUEST_URI} not working correctly

I am not using Virtual Hosts or anything fancy though I have some .htaccess files setup. Following is my rewrite rule in httpd.conf:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/app/smsapi [NC]
RewriteRule (.*) https://www.example.com/uri=%{REQUEST_URI} [R,L]
This rule basically says that if the uri does not begin with /app/smsapi then fire the rewrite. But when I restart the server and try it I get some weird results.
When I request the URL https://www.example.com/app/smsapi/index.php, I get a 200 Success code which is as expected. But, when I request the URL http://www.example.com/app/smsapi/index.php, it redirects to https://www.example.com/uri=/app/smsapi/index.php. So it actually fires the rule even though the request URI does not satisfy the condition.
So, then I decided to turn off the rewrite rules and give it a go. Now, both those URL give me a 200 Success code.
Now, I know this problem cannot be solved easily by other people who do not have access to the server, but am I right in saying that this is certainly a problem with REQUEST_URI not firing correctly? I have shown that without the rewrite rule, everything works normally, but with the rewrite rule, the second URL is redirected. Therefore, the redirection must be caused by the rewrite rule? Additionally, the condition for redirect rule is not satisfied. Doesn't this prove that there is something wrong with the functioning of the rewrite rule?
Is there any other possibility?
UPDATE
Something very weird is happening here. I setup a local server and tried the same rule and what I got for the URL http://192.168.0.112/app/ is
http://192.168.0.112/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/uri=/app/
which is correct because as long as the URL is not like /app/smsapi, it should redirect it. Wonder why this is not happening on the real server. Also, where you insert these rules seems to make a difference. (I am only including these rules after the LoadModule command).
On localhost, if I put these rules either above or below the Directory section, it won't work. But, if I include it inside the Directory section it will.
On server, if I include the rules inside the Directory section, they won't work. But, if I include them either above or below the Directory section, they start working.
This seems to me to be due to a difference in the versions. My localhost is an Ubuntu Desktop 16.04 running Apache 2.4.18. While the server is CentOS 6.8 running Apache 2.2.15.
But, i think the mystery as to why on the server redirect happens only once (though it is configured to go upto 20 times) has something to do with https. Which is also related to the original problem in which https is redirected even on a non-matching rule.
Clues anyone?
UPDATE
I updated the httpd.conf file with the same rules but I used http:// instead of https:// and it gave me the correct result with 20 redirects. That means I have isolated the problem to https.
You are reporting the exact issue in the first phrase: "I am not using Virtual Hosts or anything fancy though I have some .htaccess files setup"
.htaccess is "fancy" and overcomplicated, not virtualhosts.
If you had defined that RewriteCond in virtualhost in the first place it would work, but .htaccess is per-dir context (aka a nightmare) and the regex ^/ will never match in that context.
If you want to match REQUEST_URI in per-dir context (directory or .htaccess) you need to drop the initial slash, that is:
RewriteCond %{REQUEST_URI} !^app/smsapi [NC]
Extra, also consider you MAY NOT need to add a RewriteCond for this:
RewriteRule ^(?!app/smsapi)(.*) https://www.example.com/uri=$1 [R,L]

Apache 301 redirect with get parameters

I am trying to do a 301 redirect with lightspeed webserver htaccess with no luck.
I need to do a url to url redirect without any related parameters.
for example:
from: http://www.example.com/?cat=123
to: http://www.example.com/some_url
I have tried:
RewriteRule http://www.example.com/?cat=123 http://www.example.com/some_url/ [R=301,L,NC]
Any help will be appreciated.
Thanks for adding your code to your question. Once more we see how important that is:
your issue is that a RewriteRule does not operate on URLs, but on paths. So you need something like that instead:
RewriteEngine on
RewriteRule ^/?$ /some_url/ [R=301,L,NC,QSD]
From your question it is not clear if you want to ignore any GET parameters or if you only want to redirect if certain parameters are set. So here is a variant that will only get applied if some parameter is actually set in the request:
RewriteEngine on
RewriteCond %{QUERY_STRING} (?:^|&)cat=123(?:&|$)
RewriteRule ^/?$ /some_url/ [R=301,L,NC,QSD]
Another thing that does not really get clear is if you want all URLs below http://www.example.com/ (so below the path /) to be rewritten, or only that exact URL. If you want to keep any potential further path component of a request and still rewrite (for example http://www.example.com/foo => http://www.example.com/some_url/foo), then you need to add a capture in your regular expression and reuse the captured path components:
RewriteEngine on
RewriteRule ^/?(.*)$ /some_url/$1 [R=301,L,NC,QSD]
For either of this to work you need to have the interpretation of .htaccess style files enabled by means of the AllowOverride command. See the official documentation of the rewriting module for details. And you have to take care that that -htaccess style file is actually readable by the http server process and that it is located right inside the http hosts DOCUMENT_ROOT folder in the local file system.
And a general hint: you should always prefer to place such rules inside the http servers host configuration instead of using .htaccess style files. Those files are notoriously error prone, hard to debug and they really slow down the server. They are only provided as a last option for situations where you do not have control over the host configuration (read: really cheap hosting service providers) or if you have an application that relies on writing its own rewrite rules (which is an obvious security nightmare).

SEO URLs with ColdFusion controller?

quick ref: area = portal type page.
I would like old urls http://domain.com/long/rubbish/url/blah/blah/index.cfm?id=12345
to redirect to http://domain.com/area/12345-short-title
http://domain.com/area/12345-short-title should display the content.
I have worked out so far to do this I could use apache to write all URLs to
http://domain.com/index.cfm/long/rubbish/url/blah/blah/index.cfm?id=12345
and
http://domain.com/index.cfm/area/12345-short-title
The index.cfm will either server the content or apply a permanent redirect, but it will need to get the title and area information from the database first.
There are 50,000 pages on this website. I also have other ideas for subdomain redirects, and permanent subdomains and controlling how they act through the index.cfm.
Infrastructure are keen to do as much through Apache rewrite as possible, we suspect it would be faster. However I'm not sure we have that choice if we need to get the area and title information for each page.
Has anyone got some experience with this that can provide input?
--
Something to note, I'm assuming we'll have to keep all the internal URLs used on the website in the old format. It would be a mega job to change them all.
This means all internal URLs will have to use a permanent redirect every time.
Rather than redirecting both groups of URLs to the same script, why not simply send them to two distinct scripts?
Simply like this:
RewriteCond ${REQUEST_URI} !-f
RewriteRule ^\w+/\d+-[\w-]+$ /content.cfm/$0 [L]
RewriteCond ${REQUEST_URI} !-f
RewriteRule ^.* /redirect.cfm/$0 [L,QSA]
Then, the redirect.cfm can lookup the replacement URL and do the 301 redirect, whilst content.cfm simply serves the content.
(You haven't specified how your CF is setup; you may need to update the Jrun/Tomcat/other config to support /content.cfm/* and /redirect.cfm/* - it'll be done the same as it's done for index.cfm)
For performance reasons, you still want to avoid the database hits for redirecting if you can, and you can do that by generating rewrite rules for each page that performs the 301 redirect on the Apache side. This can be as simple as appending a line to the .htaccess file, like so:
<cfset NewLine = 'RewriteRule #ReEscape(OldUrl)# #NewUrl# [L,QSA,R=301]' />
<cffile action="append" file="./.htaccess" output=#NewLine# />
(Where OldUrl and NewUrl have been looked-up from the database.)
You might also want to investigate using mod_alias redirect instead of mod_rewrite RewriteRule, where the syntax would be Redirect permanent #OldUrl# #NewUrl# - since the OldUrl is an exact path match it would likely be faster.
Note that these rules will need to be checked before the above redirect.cfm redirect is done - if they are in the same .htaccess you can't simply do an append, but if they are in the site's general Apache config files then the .htaccess rules will be checked first.
Also, as per Sharon's comment, you should verify if your Apache will handle 50k rules - whilst I've seen it reported that "thousands" of regex-based Apache rewrites are perfectly fine, there may well be some limit (or at least the need to split across multiple files).
Using apache rewrites would only be faster if they were static rewrites, or if they all followed some rule that you could write in regex within the .htaccess file. If you're having to touch the database for these redirects, then it may not make sense to do it in .htaccess.
Another approach is the one used by most CMSs for handling virtual directories and redirects. An index.cfm file at the root of the site handles all incoming requests and returns the correct pages and pathing. MURA CMS uses this approach (as well as Joomla and most of the others.)
Basically you're using the CGI.path_info variable on an incoming request, searching for it in your DB, and doing a redirect to the new path. As usual, Ben Nadel has a good write-up of how to use this approach: Ben Nadel: Using IIS URL Rewriting And CGI.PATH_INFO With IIS MOD-Rewrite
You can, however, use the .htaccess to remove the "index.cfm" from the url string entirely if you want by redirecting all incoming requests to the root URL with something that looks like this in your .htaccess:
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteRule ^([a-zA-Z0-9-]{1,})/([a-zA-Z0-9/-]+)$ /$1/index.cfm/$2 [PT]
Basically this would redirect something like http://www.yourdomain.com/your-new-url/ to http://www.yourdomain.com/index.cfm/your-new-url/ where it could be processed as described by the blog post above. The user would never see the index.cfm.

Apache Mod_Rewrite Scenario

I was wondering how I would do a complex mod_rewrite. Below is basically how I want it done.
If the user goes to:
-http://files.stuff.example.txt.r.site.com/doc.txt
Then the server would rewrite the url to:
-http://r.site.com/index.php?type=txt&username=example&dir=files.stuff&file=doc.txt
Better picture:
-http://[dir3-dir2-dir1].[username].[type].r.site.com/[file]
Rewrites to:
-http://r.site.com/index.php?type=[type]&username=[username]&dir=[dir3.dir2.dir1]&file=[file]
I created a colour coded image to clearly show what I mean:
(can't embed images) look here:
http://i.stack.imgur.com/24H8j.png
The first subdomains are a directory structure (shown in red), so the amount of subdomains can change.
I hope someone can provide me with a solution. Either using mod_rewrite or maybe another method. Thanks.
Provided that you have configured your DNS so that requested URL hits server where your application is (maybe wildcard DNS on your domain: *.site.com -> 123.45.67.89, if supported by your DNS server/hosting), you can create more or less complicated rewrite rule. I'd do it this way:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(.*).r.site.com$
RewriteCond $1 !^index.php
RewriteRule (.*) index.php?subdomain_part=%1&file_part=$1
So in index.php you get $_GET['subdomain_part'] and $_GET['file_part'], which you can parse further to extract parameters according to your convention.
Of course, you can write more complicated regex to get URL parts extracted by mod_rewrite (I'm not such an regex expert myself). However doing parsing in PHP would be much easier and you can do better error handling (e.g. if URL is not formed properly).