How to set up rewrite rule in Azure Web App - Linux - linux

I have an Azure Web App running on linux and i want to set up a rewrite rule for my application. When users visit example.com, i will redirect them to www.example.com.
In windows, it is easier to use web.config but how is it done in Linux ?
On the linux, there is no Apache or Nginx installed but i am wondering how the application is running.
How can i get this done ? Set up a rewrite rule on either Apache or Nginx to affect my Azure Web App running on linux ?

In theory, your needs can be solved in two ways.
For more details, you can read this blogs.
And also can download sample code(ASP.NET Core URL Rewriting Sample)to test it.
The first method:
Re-Writing a URL
Here's how to handle a Rewrite operation in app.Use() middleware:
app.Use(async (context,next) =>
{
var url = context.Request.Path.Value;
// Redirect to an external URL
if (url.Contains("/home/privacy")) // you can use equal
{
context.Response.Redirect("https://markdownmonster.west-wind.com")
//return; // short circuit
}
await next();
});
The second method:
The ASP.NET Core Rewrite Middleware Module
The above two methods are officially provided. The actual test needs to be deployed to Azure for testing. If you have any questions, you can also raise a support ticket for help.

Related

Remove additional slash from URL in Asp.Net Core

I have a web-site, hosted on Azure App Service. What I'd like to do is to redirect traffic, such that an address like:
https://mysitecom//test//test2
Or:
https://mysitecom/test//test2
Would redirect to the same location:
https://mysitecom/test/test2
So far, I've tried adding some middleware to deal with this; for example:
app.Use(next => context =>
{
if (context.Request.Path.Value.Contains("//"))
{
context.Response.Redirect(context.Request.Path.Value.Replace("//", "/"), true);
return;
}
});
I've also tried:
var options = new RewriteOptions()
.AddRedirect("redirect-rule/^(.*)//(.*)$", "redirected/$1/%2");
app.UseRewriter(options);
Both of these work locally to an extent; however, it appears that running under Kestrel the slashes are automatically reduced to a single one. When this is deployed to Azure App Service, the following happens:
The slashes remain (e.g. https://mysitecom//test//test2)
The correct page is located
The middleware sees only a single slash
Please can someone explain why the middleware (or the redirect) is only ever seeing a single slash when this is deployed to Azure?
(SO wouldn't allow me to use an actual URL in the post)
If your site runs on a Windows AppService, it runs in IIS. You are encountering an IIS feature (The "URL Rewrite Module", I think). If you run the same site on Linux, it will behave differently.
If you want to detect the "original" URL, you can try something like this:
// => /test/test2
var path1 = Request.Path
// => //test//test2
var path2 = HttpContext.Features.Get<IServerVariablesFeature>()["UNENCODED_URL"]
There are multiple sources for this behavior, though I am not sure how you could turn it off if you wanted to.
Remove multiple forward slashes
https://www.ctrl.blog/entry/relative-double-slashes-url.html
http://www.timacheson.com/Blog/2010/jun/prevent_multiple_slashes_in_url
It should work in .NET Core
var options = new RewriteOptions()
.AddRedirect("(.*)/$", "$1", 301 /* Moved Permanently */);
app.UseRewriter(options);

Redirect with express in serverless/lambda container not working

I have setup an express application with various routes like:
/api/route1
/api/route2
/api/newroute
…
I need to redirect a request for route /api/route2 to /api/newroute. Thus I use res.redirect(); to achieve this. It works fine on my local development environment, where the application is hosted on http://localhost/api. A request for http://localhost/api/route2 gets successfully redirected to http://localhost/api/newroute.
We have now deployed the express application in a serverless/lambda container using aws-serverless-express. The application is hosted by AWS on https://xxx.execute-api.us-east-1.amazonaws.com/production/api.
In case of a request for:
https://xxx.execute-api.us-east-1.amazonaws.com/production/api/route2
it gets redirected to:
https://xxx.execute-api.us-east-1.amazonaws.com/api/newroute.
The redirect fails as the correct endpoint should be now /production/api/newroute.
I would like to avoid to hardcode the infix “/production” in res.redirect(); as the it will vary due to environment.
Thus I have checked whether
req.originalUrl
req.baseUrl
req.path
will provide the infix “/production”, however this is not the case.
Also req.get('Host') does not provide “/production” as it returns https://xxx.execute-api.us-east-1.amazonaws.com.
Are there any other options how I could get the full URL where the application is hosted? Or are there any better ideas?
I ran into this same issue. Here's my solution:
const baseUrl = req.url
.replace(
event.pathParameters.proxy, // => returns api/your/path
event.requestContext.path // => returns /production//api/your/path
)
.split('//') // fix the double-slashes (//)
.join('/');

Always redirect http traffic to https traffic in google app engine nodejs flex environment [duplicate]

I've followed the answer of this: Redirect from http to https in google cloud but it does not seem to be currently accurate any more. The anchor referenced ( https://cloud.google.com/appengine/docs/flexible/nodejs/configuring-your-app-with-app-yaml#security ) seems to have been removed but without a note of a replacement.
For reference, I am serving NodeJS over a Google App (flex) Engine. As per the answer I've got in my app.yaml:
handlers:
- url: /.*
script: IGNORED
secure: always
Since HTTPS is obviously terminated before it hits my Express engine (and redirection on there would be useless); how is it currently correctly implemented?
Potentially helpful, I have an external domain attached via the "Custom domains" tab in the console, and there is indeed a SSL certificate configured (so if a user manually goes to https://.com everything is fine)
The flexible environment does not current support handlers in the app.yaml. If you want https:// redirection, you have a few options:
Use helmet to do to HSTS stuff for you, and implement your own initial redirect.
I wrote a happy little library to always forces SSL on all routes for express yes-https
We are considering auto-redirecting all traffic to SSL by default. Do you think that would be a good thing for your apps?
Pulling Justin's yes-https library, I was able to get this to work:
var app = express();
app.use(function(req, res, next){
if (req.host != 'localhost' && req.get('X-Forwarded-Proto') == 'http') {
res.redirect(`https://${req.host}${req.url}`);
return;
}
app.router(req, res, next);
});
At first I thought I had to do that since I was on an appengine subdomain and couldn't use HSTS. Then I learned HSTS works fine for subdomains. :) Regardless, I thought people might want to see what the magic bit to use was if they didn't want to use yes-https for some reason.
Justin, auto-redirecting all traffic to SSL by default sounds great to me. I just spent hours trying to figure out how to do so before I found this post because I was trying to get my app to get Chrome's add to homescreen install banner as per https://developers.google.com/web/fundamentals/engage-and-retain/app-install-banners/.
GCP This should be as easy to just use the gcloud app cli and configure a header (Strict-Transport-Security) or redirect rule. Perhaps the push is to force us to Firebase Hosting instead which is forcing HTTPS already. For a quick solution for Single Page apps (static content) with React, Angular etc, we can use this JS snippet.
It ignores localhost environments. You can change localhost with a host name that you would like to exclude. It then redirects using https as protocol.
if ( location.host.indexOf("localhost") < 0 && location.protocol.toLowerCase() !== "https:"){
const url= `https://${location.host}`;
location.replace(url);
}

Disable default domain https://[project-id].appspot.com of Node JS on Google App Engine

I have deployed my Node JS app onto Google Cloud App Engine, and I can successfully add my custom domain for my app.
Let say my custom domain is example.com.
Now I can browse my app via example.com & www.example.com, it works as expected. But I find that I can still browse my app through the default domain.
https://[project-id].appspot.com
I want to disable the default domain, is it possible to do that?
You cannot disable that default domain. You would have to write a redirect script. You can test for "appspot" in the request's HTTP_HOST, and test for "AppEngine-Google" in the request's HTTP_USER_AGENT, to determine if it is an internal request.
Also, internal functions, like cron jobs and task queues, run on that domain, so be careful what you do. Task queues will fail given a 301.
After considering GAEfan suggestion, I have made some change on the router logic. If the host name is ended with "appspot.com" and the user agent is included "AppEngine-Google", it will redirect to my custom domain.
router.get('/', function(req, res, next) {
if(req.get("host").endsWith(GOOGLE_APP_SPOT) &&
req.get("User-Agent").includes(GOOGLE_USER_AGENT))
{
var redirectURL = url.format({
protocol: req.protocol,
host: CUSTOM_DOMAIN,
pathname: req.originalUrl
});
res.redirect(redirectURL);
}
res.render('templateName', viewModel);
});
You can do it just using the dispatch.yaml file from App Engine, list all your domains there, but not the *.appspot.com one. Google will show a 404 route when you try to access that.
EDIT: Not possible anymore, check comments.
Checkout the official reference.

HTTP to HTTPS redirection on App Engine Flexible

I've followed the answer of this: Redirect from http to https in google cloud but it does not seem to be currently accurate any more. The anchor referenced ( https://cloud.google.com/appengine/docs/flexible/nodejs/configuring-your-app-with-app-yaml#security ) seems to have been removed but without a note of a replacement.
For reference, I am serving NodeJS over a Google App (flex) Engine. As per the answer I've got in my app.yaml:
handlers:
- url: /.*
script: IGNORED
secure: always
Since HTTPS is obviously terminated before it hits my Express engine (and redirection on there would be useless); how is it currently correctly implemented?
Potentially helpful, I have an external domain attached via the "Custom domains" tab in the console, and there is indeed a SSL certificate configured (so if a user manually goes to https://.com everything is fine)
The flexible environment does not current support handlers in the app.yaml. If you want https:// redirection, you have a few options:
Use helmet to do to HSTS stuff for you, and implement your own initial redirect.
I wrote a happy little library to always forces SSL on all routes for express yes-https
We are considering auto-redirecting all traffic to SSL by default. Do you think that would be a good thing for your apps?
Pulling Justin's yes-https library, I was able to get this to work:
var app = express();
app.use(function(req, res, next){
if (req.host != 'localhost' && req.get('X-Forwarded-Proto') == 'http') {
res.redirect(`https://${req.host}${req.url}`);
return;
}
app.router(req, res, next);
});
At first I thought I had to do that since I was on an appengine subdomain and couldn't use HSTS. Then I learned HSTS works fine for subdomains. :) Regardless, I thought people might want to see what the magic bit to use was if they didn't want to use yes-https for some reason.
Justin, auto-redirecting all traffic to SSL by default sounds great to me. I just spent hours trying to figure out how to do so before I found this post because I was trying to get my app to get Chrome's add to homescreen install banner as per https://developers.google.com/web/fundamentals/engage-and-retain/app-install-banners/.
GCP This should be as easy to just use the gcloud app cli and configure a header (Strict-Transport-Security) or redirect rule. Perhaps the push is to force us to Firebase Hosting instead which is forcing HTTPS already. For a quick solution for Single Page apps (static content) with React, Angular etc, we can use this JS snippet.
It ignores localhost environments. You can change localhost with a host name that you would like to exclude. It then redirects using https as protocol.
if ( location.host.indexOf("localhost") < 0 && location.protocol.toLowerCase() !== "https:"){
const url= `https://${location.host}`;
location.replace(url);
}

Resources