Remove www. from host name using Nginx Rewrite - nginx

I am trying to configure my Nginx to strip out www. from hostname.
I am looking for generic rule that handle possible subdomain cases.
E.g. If http://www.foo1.sample.com and http://www.fooX2.sample.com are two domains.
Then I want to strip any www. before such subdomains, and redirect them to http://foo1.sample.com and http://fooX2.sample.com respectively (WITHOUT knowing the exact subdomain in the rule.)
Thanks.

Best Practice:
The best practice, as well as the most efficient way, would be to use a separate server definition for this.
This will not only ensure that the config is automatically applied to every single one of the websites that are hosted on your nginx instance, but it'll also makes sure that you don't end up running regular expressions on the hostname from multiple instances in your code.
The following is the simplest form:
server {
listen 80;
server_name ~^www\.(?<domain>.+)$;
return 301 $scheme://$domain$request_uri;
}
If you do use https, then things get more complicated, because you'd have to ensure that the certificates don't mismatch. Unless you have a single certificate for all of your domains, it would be the best practice to simply hardcode everything, as it's already hardcoded in the certificate anyways, and a solution like above simply isn't possible due to the certificate requirements.
Alternative:
Note that the other answer to the question, which uses rewrite ^(.*) http://…$1 …, is incorrect, and will cause you to lose $query_string, as well as potentially mangle the encoding of the request as per Nginx pass_proxy subdirectory without url decoding.
If you require an if-based approach and no hardcoding, neither of which are recommended, e.g., like the other answer, then at least use the correct paradigm, to avoid the bloat and the loss of the $query_string; note that as per nginx server name regex when "Host" header has a trailing dot, the $host variable is already normalised by nginx (trailing dot removed, whole thing brought to lower case), so, you don't need to worry about doing a case-insensitive comparison like in the other answer, either:
if ($host ~ ^www\.(?<domain>.+)$) {
return 301 $scheme://$domain$request_uri;
}
References:
http://nginx.org/r/listen
http://nginx.org/r/server_name
http://nginx.org/r/return
http://nginx.org/en/docs/http/server_names.html

I think adding following If block in your Nginx conf file should work for you. It also takes care of subdomain case you mentioned.
if ($host ~* ^www\.(.*)) {
set $host_without_www $1;
rewrite ^(.*) http://$host_without_www$1 permanent;
}

Related

Nginx forwarding to different app's different path using `#` symbol

Quick question. We have two apps. Ports 3001 and 3002. Our domain is www.domain.com.
What we want to have it once person enters www.domain.com/pathname we want them to be redirected into another app's specific path.
How to do it?
We already came up to this in my nginx
location /pathname/ {
proxy_pass http://127.0.0.1:3002/;
}
It nearly works. However, our app under 3002 works on path /#/pathname.
We can access it by typing www.domain.com/pathname/#/pathname. We want to access same link by typing www.domain.com/pathname.
How to shorten it? What do I miss?
(upd) Just redirect /pathname to /pathname/#/pathname
According to your comment, you want just redirect from /pathname to /pathname/#/pathname
Try these combined directives:
rewrite to append # and fragment identifier
and proxy_pass to reverse proxy to the app.
E.g.:
location /short_path_name/ {
rewrite ^ /pathname/#/$uri permanent;
break;
}
location /pathname/ {
proxy_pass http://127.0.0.1:3002/;
}
And use www.domain.com/short_path_name/ link for your app.
Unfortunately, nginx can't see the fragment identifier
Unfortunately, you can't. Because server never get the fragment identifier from browser.
The fragment identifier functions differently to the rest of the URI: its processing is exclusively client-sided with no participation from the web server
Naming a bit amusing, but it has a long history. See TBL (1997): Fragment Identifiers on URIs:
The URI reference is a thing you build by taking a URI for an information object, adding a "#" sign and then a Fragement identifier. (The last term is historical, so try not to thinl of it necessarily identifying a fragment).
Workarounds
There are workarounds, e.g. encode hashtag symbol into %23 but I'm not sure is it your way.
Handle request arguments with nginx
Note: rewriting url, nginx can preserve request arguments if you add ? at the end of rewrite directive.
See Nginx rewrite manual:
If a replacement string includes the new request arguments, the previous request arguments are appended after them. If this is undesired, putting a question mark at the end of a replacement string avoids having them appended, for example:
rewrite ^/users/(.*)$ /show?user=$1? last;

Nginx 301 Permanent Redirect For Language Support

I am now enabling language support for my web site. I am including the language as part of the URL. For example: domain.com/en/page I need to setup 301 redirects for existing search engine indexing.
The following works in Nginx to redirect from domain.com/blog to domain.com/en/blog
location = /blog {
return 301 /en/blog;
}
I don't understand the redirect needed to go from domain.com/blog/read/# to domain.com/en/blog/read/# (where # is the sequence field in a postgres database table)
I have spent time looking, searching and reading docs to find this answer myself. I am not understanding.
To prefix the existing requested URI with /en you can use:
return 301 /en$request_uri;
The above will add the three characters before the existing request and also include any arguments that may be present.
To match any URI that begins with /blog, use location /blog { ... }. To match any URI that begins with /blog/read/ use location /blog/read/ { ... }.
Nginx chooses a location to process a request based on a set of rules. So, you will need to consider the other location blocks present within your configuration.

nginx rewrite Issue, why does it just replaces one matched string?

I want to replace my url via Nginx's rewrite directive. For instance, the client side requests http://127.0.0.1/user/user_id/, and I want to let Nginx rewrite the url to http://127.0.0.1/person/person_id/.
My Nginx configuration is like this:
rewrite (.*)user(.*) $1person$2;
But I fount the Nginx changes the url to .../user/person_id/
Could someone tell me how to change the user to person via rewrite directive?
Assuming that the first instances of user and personare constant and that there is always a slash after the second item, you can try:
rewrite ^/user/user_([^/]+)/(.*)$ /person/person_$1/$2 ;
well this single case you are talking about can be solved simple:
rewrite ^/user/user_id/(.*)$ /person/person_id/$1 ;

NGinx : How to test if a cookie is set or not without using 'if'?

I am using the following configuration for NGinx currently to test my app :
location / {
# see if the 'id' cookie is set, if yes, pass to that server.
if ($cookie_id){
proxy_pass http://${cookie_id}/$request_uri;
break;
}
# if the cookie isn't set, then send him to somewhere else
proxy_pass http://localhost:99/index.php/setUserCookie;
}
But they say "IFisEvil". Can anyone show me a way how to do the same job without using "if"?
And also, is my usage of "if" is buggy?
There are two reasons why 'if is evil' as far as nginx is concerned. One is that many howtos found on the internet will directly translate htaccess rewrite rules into a series of ifs, when separate servers or locations would be a better choice. Secondly, nginx's if statement doesn't behave the way most people expect it to. It acts more like a nested location, and some settings don't inherit as you would expect. Its behavior is explained here.
That said, checking things like cookies must be done with ifs. Just be sure you read and understand how ifs work (especially regarding directive inheritance) and you should be ok.
You may want to rethink blindly proxying to whatever host is set in the cookie. Perhaps combine the cookie with a map to limit the backends.
EDIT: If you use names instead of ip addresses in the id cookie, you'll also need a resolver defined so nginx can look up the address of the backend. Also, your default proxy_pass will append the request onto the end of the setUserCookie. If you want to proxy to exactly that url, you replace that default proxy_pass with:
rewrite ^ /index.php/setUserCookie break;
proxy_pass http://localhost:99;

nginx multi-stage 404 handling

We just moved to a new site, and want to redirect old links where necessary - however, some still work. For instance,
/holidays/sku.html
still works, while
/holidays/christmas/
no longer works. I'd like to be able to allow the site to attempt to serve a page, and when a 404 is reached, THEN try to pass it through a series of regex redirects, that may look like:
location ~* /holidays/(.*)+$ { set $args ""; rewrite ^ /holidays.html?r=1 redirect; }
I'm using a ~* location directive instead of doing a direct rewrite because we're moving from a Windows-based ASPX site to Magento with php-fpm behind nginx, so we suddenly have to worry about case sensitivity.
Without using nested location directives (which are actively discouraged by nginx documentation) with an #handler of some sort, what's the best way to allow nginx to attempt to serve the page first, THEN pass it across redirects if it fails?
Thanks!
http://wiki.nginx.org/NginxHttpCoreModule#try_files

Resources