Serve content from different domain - asp.net

We're moving our physical file server to cloud storage, but due to custom domain name limitations, we can't keep using the current domain for the new cloud storage.
When a request is made to:
https://old-subdomain.old-website.com/old-directory/image.png
Is it possible to preserve the user-entered URL from above in the location bar, while serving content from the cloud storage location?
https://new-subdomain.new-website.com/new-directory/image.png
The closest I've been able to achieve is a redirect (cannot get a rewrite to work) using the IIS URL Rewrite module, but this doesn't preserve the original URL:
<rule name="FileStorageRedirect" stopProcessing="true">
<match url="^old-directory(.*)$" />
<conditions>
<add input="{HTTP_HOST}" pattern="^old-subdomain.old-website.com$" />
</conditions>
<action type="Redirect" url="https://new-subdomain.new-website.com/new-directory{R:1}" />
</rule>
If it's possible to do what I'm asking, the solution doesn't need to be limited to using the IIS URL Rewrite module. I'm open to all solutions.

Related

Reverse proxy Kibana 7 with ARR in IIS

I set up some days ago an ELK 7 stack to monitor some logs in one place. For now it perfectly operational and works well from inside the network. I now want to access Kibana from outside the network without the need of a VPN.
I already have a website running in IIS which is served through a global reverse proxy. The website itself is doing nothing but there are 2 WebApplications under it (there's just a little app at the webiste root doing a redirect to the right app depending of the source of the request).
So at the moment, i have the following URLs available (servername could be either my machine name when i'm on the intranet or the external domain when i'm remoting) :
http(s)://servername/app1
http(s)://servername/app2
Now i would like to be able to get the following URL working to access Kibana
http(s)://servername/elk
For now i didn't manage to make it work - even internally - (so without involving the first global reverse proxy).
I set up a application under a website dedicated for testing purpose (so it won't mess with the real website). This is an extract of my web.config file for this application :
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="KibanaProxy">
<match url="(.*)" />
<action type="Rewrite" url="http://kibanahost:5601/{R:1}" />
</rule>
</rules>
<outboundRules>
<rule name="KibanaRedirect" preCondition="Redirect">
<match serverVariable="RESPONSE_Location" pattern="^/(.*)" />
<action type="Rewrite" value="/elk/{R:1}" />
</rule>
<rule name="KibanaContent" preCondition="ResponseIsHtml1">
<match filterByTags="A, Area, Base, Form, Frame, Head, IFrame, Input, Link, Script" pattern="^/(.*)" />
<action type="Rewrite" value="/elk/{R:1}" />
</rule>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
I wrote a rule to handle the first redirect done when accessing the Kibana root and i tried to add a rewrite rule so external resources can be accessed also. It seems like i have still some other rewrites to do mainly because of URL inside bootstrap.js and such things like CSS... It seems like it's a pain to achieve and i wonder if anyone managed to accomplish such a proxying. If i can proxy Kibana correctly internally, i would be able to add an authentication layer thanks to IIS before trying to expose it over the internet through the global reverse proxy.

Using web.config to configure multiple websites/domains

I have several shared hosting accounts with Newtek. They told me one account can be used to host several websites, but I don't know how to do that.
They said it can be done using either an .htaccess or web.config file. And since it's ASP.NET, that suggests web.config is the way to go.
Does anyone know how to use web.config to route requests for a given domain to a subfolder? I assume that subfolder would need to be set as an application starting point, which it appears their control center will allow me to do. I just need to associate that starting point with a particular domain.
And does this sound like a reasonable approach (shy of forking out money for a virtual server)?
If the IIS URL Rewrite Module is installed, you can create a Rule to redirect the request to a subfolder based on the domain name.
<rule name="site2.com" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(www.)?site2.com" />
<add input="{PATH_INFO}" pattern="^/site2/" negate="true" />
</conditions>
<action type="Rewrite" url="\site2\{R:0}" />
</rule>
Source: https://weblogs.asp.net/owscott/iis-url-rewrite-hosting-multiple-domains-under-one-site

IIS HTTP to HTTPS relative redirect

I recently got a SSL certificate for my website and want to redirect all traffic to HTTPS. I got everything to go to https://mydomain.com but if someone enters http://mydomain.com/anotherpage it drops the other page and just takes the user to the home page.
My rule in my web.config file looks like this:
<rule name="HTTP to HTTPS redirect" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" />
</rule>
I also tried https://{HTTP_HOST}{REQUEST_URI} without any success. Can anyone tell me what I need to do to make the website redirect to the proper HTTPS version of the page? I have a feeling it has something to do with the pattern, but I can't seem to figure out the syntax.
I found a way to do this, and you don't need the Rewrite module for it. The following worked for me on Windows 8 (IIS 8.5):
Remove the HTTP binding from your site (leave HTTPS in place)
Add another site
Make sure that the new site has HTTP binding
Configure HTTP Redirect as shown:
Now all HTTP request will redirect to your HTTPS site and will preserve the rest of the URL.
Change it to:
<rewrite>
<rules>
<rule name="Redirect to HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" />
</rule>
</rules>
</rewrite>
I had the same problem where the R:1 was dropping my folders.
I fixed it like this.
<rule name="http to https" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}"
appendQueryString="false" redirectType="SeeOther" />
</rule>
I can't comment yet or I'd leave this as a comment under AndyH's answer. The solution was correct, though I hit a single further snag (likely tied to the use of Adobe's Coldfusion server). I wanted to share some further research I had to do for any other unfortunate soul who may run into it.
Once set up, the redirect would always end at this url:
https://xxx.xxx.com/jakarta/isapi_redirect.dll
The fix for this was found in an Adobe thread (https://forums.adobe.com/thread/1034854): I had to change an application pool's settings as follows:
Real site (HTTPS binding only, actually contains code and virtual directories)
Application pool's Advanced Settings: Enable 32-Bit Applications : False
Http_Redirect site (HTTP binding only, is a blank shell of a folder with no directories)
Application pool's Advanced Settings: Enable 32-Bit Applications : True
EDIT: Another detail, tied to query string preservation:
Per suggestion in this post (http://www.developerfusion.com/code/4678/permanent-301-redirect-with-querystring-in-iis/)
Add $S$Q at the end of the domain and make sure the box for Redirect all requests to exact destination is checked. Then it will save the query string as well.
I believe AndyH's answer to be the easiest and best way. I have found using the URL rewrite can also conflict with code that may redirect the user to another page. IT commonly broke in our environment. But Andy's solution worked flawlessly. I also think Andy's solution will put less overhead on the server as it doesn't need to examine every url hitting it for possible re-write conditions.
I found a workaround:
Consider what in IIS is consired a website: simply a set of rules, the path in which get files and its bindings.
Furthermore, there's available a function called "HTTP Redirect" (included standardly in IIS), that redirect an host to another, keeping all subdirectory (it makes a relative path). The workaround is to leave just the binding for HTTPS (port 443) in your website, and create another with the binding on HTTP (port 80) and set for this an HTTP redirect to your URL with https://.
For example, consider a website called mytest and its urls http://www.mytest.com/ and https://www.mytest.com/.
Set for it instead only binding on https://www.mytest.com/, and delete the http binding. Then create a new website with the same local path, called mytest http with just a binding over port 80 (http://www.mytest.com/) and set for this one an HTTP Redirect to https://www.mytest.com/.
Simple and clean, and that should be as fast as directly the https url for the user, because it's just an internal redirect. I hope that can work for you!
You can add the URL Rewrite module to IIS (IIS 7 or higher) which allows you to add create the redirect in a visual way. The module can be downloaded here.
This step-by-step tutorial worked wonders for me and explains that when using this module, all it actually does is add some code to your web.config file as such:
<rewrite>
<rules>
<rule name="Redirect to HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="SeeOther" />
</rule>
</rules>
</rewrite>
I have found that the
<action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" />
syntax will only work for the website's ROOT web.config file.
If the rewrite rule is applied to a virtual web.config file, then use..
<action type="Redirect" redirectType="Found" url="https://{HTTP_HOST}{URL}" />
The {URL} syntax will include the initial forward slash, the virtual path, and any URL parameters.

Error when reprocessing a rewritten url in IIS URL Rewrite 2

I'm trying to create a system to serve images and their resized versions from GridFS using MVC3 and IIS URL Rewrite 2. After testing, I've realized that serving images directly from filesystem is 10x faster than serving them using GridFS file streams. Then I've decided to keep the originals in GridFS and create a copy of the original file and resized versions on servers local file system using a combination of Url Rewrite 2 and Asp.Net handlers.
Here are the rewrite rules I use for serving the original and the resized version:
<rule name="Serve Resized Image" stopProcessing="true">
<match url="images/([a-z]+)/[a-f0-9]+/[a-f0-9]+/[a-f0-9]+/([a-f0-9]+)-([a-f0-9]+)-([a-f0-9]+)-([0-9]+)\.(.+)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="/Handlers/ImageResizer.ashx?Uri={REQUEST_URI}&Type={R:1}&Id={R:2}&Width={R:3}&Height={R:4}&ResizeType={R:5}&Extension={R:6}" appendQueryString="false" logRewrittenUrl="true" />
</rule>
<rule name="Serve Original Image" stopProcessing="true">
<match url="images/([a-z]+)/[a-f0-9]+/[a-f0-9]+/[a-f0-9]+/([a-f0-9]+)\.(.+)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="/Handlers/Images.ashx?Uri={REQUEST_URI}&Type={R:1}&Id={R:2}&Extension={R:3}" appendQueryString="false" logRewrittenUrl="true" />
</rule>
As you can see, rewrite engine checks if the file exist on the file system, and if not. rewrites the url and sends the request to the handler. Handler serves the stream and writes the file to the file system. On the next request, file is served directly from file system. I've seperated the files to folders by splitting their 24 char IDs (MongoDB Object ID as string) to avoid hunderds of thousands images in same folder.
Here is a sample original image request:
http://localhost/images/test/50115c53/1f37e409/4c7ab27d/50115c531f37e4094c7ab27d.jpg
This and the resized versions works without any problems.
Since this URL is too long and has duplicates in it, I've decided to use rewrite engine again to shorten the url to generate folder names automatically. Here is the rule which I put to the top:
<rule name="Short Path for Images">
<match url="images/([a-z]+)/([a-f0-9]{8})([a-f0-9]{8})([a-f0-9]{8})(.+)" />
<action type="Rewrite" url="images/{R:1}/{R:2}/{R:3}/{R:4}/{R:2}{R:3}{R:4}{R:5}" appendQueryString="false" logRewrittenUrl="true"></action>
</rule>
When I request an image using this rule for example with the following URL:
http://localhost/images/test/50115c531f37e4094c7ab27d.jpg
it only serves the image if the image is already on filesystem, otherwise I get the following error:
HTTP Error 500.50 - URL Rewrite Module Error.
The page cannot be displayed because an internal server error has occurred.
I've checked IIS Log File Entry for the request. It doesn't show any details except:
2012-08-02 14:44:51 127.0.0.1 GET /images/test/50115c531f37e4094c7ab27d.jpg - 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+6.1;+WOW64)+AppleWebKit/537.1+(KHTML,+like+Gecko)+Chrome/21.0.1180.60+Safari/537.1 500 50 161 37
On the other hand, successfull requests log the rewritten URL's like:
GET /Handlers/ImageResizer.ashx Uri=/images/test/50115c53/1f37e409/4c7ab27d/50115c531f37e4094c7ab27d-1f4-1f4-2.jpg&Type=test&Id=50115c531f37e4094c7ab27d&Width=1f4&Height=1f4&ResizeType=2&Extension=jpg
Elmah and EventLog also doesn't show anything. Added a filesystem logger to the top of my controller method and it doesn't log these particular problematic requests.
Can anyone suggest a workaround to get it work?
Edit: After RuslanY's suggestion about Failed Request Tracing, I've managed to identify the error:
ModuleName: RewriteModule
Notification: 1
HttpStatus: 500
HttpReason: URL Rewrite Module Error.
HttpSubStatus: 50
ErrorCode: 2147942561
ConfigExceptionInfo:
Notification: BEGIN_REQUEST
ErrorCode: The specified path is invalid. (0x800700a1)
Entire Trace Result can be see here (IE only)
Unfortunately, this is still not taking me to the solution since the second rule (therefore shortening rule) is working when the file exist on the file system.
As an alternative approach to using UrlRewrite to do this checking, why not using Application Request Routing w/ disk based caching. Dynamic images will be generated, and the caching infrastructure of ARR will save generated images to disk. Less mess, and I've used ARR to great success in production scenarios. Disk cache persist between IIS restarts and can live as long as you say (default is to use cache information from the response, but you can override this to be longer).
Application Request Routing

Canonical Hostname with URLRewrite 2.0 behind load balancer

I have two IIS7 web servers behind a load-balancer. The URL Rewrite 2.0 module is installed on both servers and the following rewrite rule applied to both instances:
<rule name="Enforce canonical hostname" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" negate="true" pattern="^www\.mydomain\.com$" />
</conditions>
<action type="Redirect" url="http://www.mydomain.com/{R:1}" redirectType="Permanent" />
</rule>
When I try to navigate to http://mydomain.com, my web browser hangs indefinitely. I suspect the load-balancer is affecting the way URL Rewrite works, but I can't be certain.
We ended up using the following technique:
http://www.mcanerin.com/en/articles/301-redirect-iis.asp
The key was to add the $S$Q to the end of the domain name.
My guess is ,
1. load balancer forwards your request to your child servers
2. and when request comes to child servers they redirect the request according to your URL redirect rule, so your request is redirected and again comes on Load balancer
3. and the same procedure(step 1-2) is followed,
thus your request loops again and again and your browser gets hanged.

Resources