Nginx: How to rewrite only when all location blocks fail? - nginx

I have a web site which needs to be using https connection for pretty much the whole site except a few locations which I need to be served via http. To do that I have two servers setup in nginx config. One is for non-secure and one for secure connections. However for the non-secure server, I want to be able to rewrite to the secure web one only when none of the location blocks are validated.
Is that possible? If yes, how?
Structure of my nginx config:
server {
listen 80;
...
location /foo1 { ... }
location /foo2 { ... }
# i can't get this rewrite to work only when all location blocks fail
rewrite ^/(.*) https://foo.com/$1 permanent;
}
server {
listen 443;
...
}
Thanx

Add to the end of the server block:
location / {
rewrite ^/(.*) https://foo.com/$1 permanent;
}

Related

Deploying multiple Go applications using Nginx

The are two web applications (websites) written on Go. One is turalasgar.pro (here I am using Go built-in server). Another is engossip.com (for now it displays the same ip as former). I have a vps. I know I should use Nginx, but have no idea how? I have heard of Caddy. Please, I need only nginx server, not Caddy. What I need is run two (or more) applications by using my same vps. How should I configure Nginx configuration? Whether by listening to different ports or to the same port. Practical advices and examples highly appreciated.
It's called reverse proxy. Each application uses it's own port to listen. And then you just point to them in nginx config:
server {
listen 80;
server_name turalasgar.pro;
location / {
proxy_pass http://localhost:8080;
...
}
}
server {
listen 80;
server_name engossip.com;
location / {
proxy_pass http://localhost:8081;
...
}
}
Well is really easy.
follow this guide:
https://www.digitalocean.com/community/tutorials/how-to-use-martini-to-serve-go-applications-behind-an-nginx-server-on-ubuntu
After you achieved one application working with martini+nginx just add another server block for the other app.
In case you need more information about server blocks:
https://www.digitalocean.com/community/tutorials/how-to-set-up-nginx-server-blocks-virtual-hosts-on-ubuntu-14-04-lts
Above solutions I tried but didn't work for me
https://gist.github.com/soheilhy/8b94347ff8336d971ad0
server {
listen ...;
...
location / {
proxy_pass http://127.0.0.1:8080;
}
location /blog {
rewrite ^/blog(.*) /$1 break;
proxy_pass http://127.0.0.1:8181;
}
location /mail {
rewrite ^/mail(.*) /$1 break;
proxy_pass http://127.0.0.1:8282;
}
...
}

Nginx: how to add /something to a uri and still keep it working

I have a nginx instance running. My config is something like the following.
server {
listen 80;
listen 443;
location / {
...
proxy_pass http://127.0.0.1:8080;
...
proxy_redirect http://127.0.0.1:8080 example.com;
}
}
I have some software running in 8080 and I want that the user enters example.com/somepath and be able to be redirected to the root 127.0.0.1:8080 through my domain. The software should receive all urls without /somepath but the browser should still show /somepath in the name.
I am quite new so sorry for the basic question I could not find any relevant info on how to do this exactly: I tried rewrite rules and setting location /mysoftware { tests with no luck.
The client browser uses /somepath/... to access /...in the application. This means that nginx must rewrite the URI before passing it upstream.
The proxy_pass directive has a basic rewrite capability. See this document for details. For example:
location /somepath/ {
proxy_pass http://127.0.0.1:8080/;
...
}
Alternatively, you might use a rewrite ... break statement. See this document for details. For example:
location /somepath {
rewrite ^/somepath/?(.*)$ /$1 break;
proxy_pass http://127.0.0.1:8080;
...
}
The difficult part is preventing your application from breaking out of /somepath. The proxy_redirect directive can handle the 3xx responses from your application. But the location of resource files (.css and .js) and the target for hyperlinks, can cause problems for applications that are not aware that they need to stay inside a subdirectory.

nginx redirect twice from https to http

i have 2 servers, one has ssl and i config it like this,
in the server with SSL certification(which is https:// www.example.com):
location ~^/abc/.* {
proxy_pass http://www.example.com:8214/
}
in another server(which is http:// www.anotherExample.com):
server {
listen 8214;
server_name www.anotherExample.com;
rewrite ^/(.*)$ http://www.anotherExample.com:8080/$1 permanent;
}
and after access https:// www.example.com/abc/api/getGroup
it can't redirect to http:// www.anotherExample.com:8080/api/getGroup
Anything wrong???
There are a couple of things you could do to improve your configuration.
location ^~ /abc/ {
proxy_pass http://www.example.com:8214$uri;
#You should have other directives set here as well.
}
Also, consider setting up an upstream.
Then, for your server block:
server{
listen 8124;
server_name www.anotherExample.com;
rewrite ^/abc/(.*)$ http://www.anotherExample.com:8080/$1 permanent;
}
server{
listen 8080;
server_name www.anotherExample.com;
location ^~ /api/ {
#your_config_here
}
}
The explanation:
In your first location block, you shouldn't have .* in the expression. Nginx will match this for you. Then, when you're proxying, you can explicitly tell Nginx to send the URI as well.
Next, you're sending the URI www.anotherExample.com:8124, which includes /abc/, so you want to extract everything after that.
Lastly, because you've rewritten it to point to 8080 port, you'll need to define a separate server block for this.
I don't know what you're aiming to achieve, but so much proxying and redirects isn't necessary in most cases, and might lead to poor performance. Another consideration that you should take into account is you're sending unencrypted information to anotherExample.com, which, if not on the same local network, might be a security vulnerability.

How to Redirect a non-www to www with Mutiple Sites? (Nginx and Varnish)

First I want to clarify that I searched a lot about this issue, but I haven't found a solution.
I have 2 Wordpress sites configured under the same Nginx (port 8080) and Varnish (port 80).
This is my actual setting:
map $http_host $blogid {
default 0;
www.site1.com 1;
www.site2.com 2;
}
server {
listen 8080;
server_name www.site1.com site1.com;
root /var/www/site1.com;
...
}
server {
listen 8080;
server_name www.site2.com site2.com;
root /var/www/site2.com;
...
}
What I want to do, is to configure a redirect for site2 from a non-www to a www. Example: http://site2.com -> http://www.site2.com
I added another 'server' configuration with the redirect, and let just 'www.site2.com' in the other 'server_name'.
map $http_host $blogid {
default 0;
www.site1.com 1;
www.site2.com 2;
}
server {
server_name www.site1.com site1.com;
root /var/www/site1.com;
...
}
server {
listen 8080;
server_name site2.com;
return 301 http://www.site2.com$request_uri;
}
server {
server_name www.site2.com;
root /var/www/site2.com;
...
}
After changed with the configuration above and restarting Nginx, what happened is when accessing "http://site2.com" (without www) it is loading the content from "http://site1.com" (url continues site2.com without www). Acessing "http://www.site2.com" shows the right content.
What I'm doing wrong?
I think that redirect is not working because I tried to redirect to Google.com, but it didn't redirect. It keeps loading "site1.com" content inside "site2.com".
return 301 http://www.google.com
I tried this code below, but with the same result:
rewrite ^(.*) http://www.site2.com$1 permanent;
My complete Nginx configuration:
http://codepad.org/TfPHS0jH
Your site isn't being served by Nginx but by Varnish.
When you navigate to any of http://www.siteX.com or http://siteX.com, you are going to http://www.siteX.com:80 or http://siteX.com:80 and according to your explanation, Varnish listens on Port 80, not Nginx.
There is no real reason to ever have to use the two together (despite what you may have read on some websites) and you should get rid or one or the other and focus on the one you decide to keep.
After long time, this was my solution:
http://www.softprayog.in/troubleshooting/how-to-redirect-non-www-urls-to-www-in-varnish

Nginx rewrite non-www-prefixed domain to www-prefixed domain

I see the Nginx HttpRewriteModule documentation has an example to rewrite a www-prefixed domain to a non-www-prefixed domain:
if ($host ~* www\.(.*)) {
set $host_without_www $1;
rewrite ^(.*)$ http://$host_without_www$1 permanent; # $1 contains '/foo', not 'www.mydomain.com/foo'
}
How can I do the reverse-- rewrite a non-www-prefixed domain to a www-prefixed domain? I thought maybe I could do something like the following but Nginx doesn't like the nested if statement.
if ($host !~* ^www\.) { # check if host doesn't start with www.
if ($host ~* ([a-z0-9]+\.[a-z0-9]+)) { # check host is of the form xxx.xxx (i.e. no subdomain)
set $host_with_www www.$1;
rewrite ^(.*)$ http://$host_with_www$1 permanent;
}
}
Also I wanted this to work for any domain name without explicitly telling Nginx to rewrite domain1.com -> www.domain1.com, domain2.com -> www.domain2.com, etc. since I have a large number of domains to rewrite.
As noted in the Nginx documentation, you should avoid using the if directive in Nginx where possible, because as soon as you have an if in your configuration your server needs to evaluate every single request to decide whether to match that if or not.
A better solution would be multiple server directives.
server {
listen 80;
server_name website.com;
return 301 $scheme://www.website.com$request_uri;
}
server {
listen 80;
server_name www.website.com;
...
}
If you're trying to serve an SSL (HTTPS) enabled site, you got more or less three different options.
Set up multiple IP addresses having each server directive listening on their own IP (or different ports if that's an option for you). This options needs SSL certificates for both website.com and www.website.com, so either you have a wild card certificate, a UNI certificate (multiple domains) or just plainly two different certificates.
Do the rewrite in the application.
Use the dreaded if directive.
There is also an option to use SNI, but I'm not sure this is fully supported as of now.
if ($host !~* ^www\.) {
rewrite ^(.*)$ http://www.$host$1 permanent;
}
Well I guess I don't really need the outer "if" statement since I'm only checking for domains of the form xxx.xxx anyways. The following works for me, though it's not robust. Let me know if there is a better solution.
if ($host ~* ^([a-z0-9\-]+\.(com|net|org))$) {
set $host_with_www www.$1;
rewrite ^(.*)$ http://$host_with_www$1 permanent;
}
Edit: Added hyphen to the regular expression since it is a valid character in a hostname.
if ($host ~* ^[^.]+\.[^.]+$) {
rewrite ^(.*)$ https://www.$host$1 permanent;
}
It's only possible to get valid hostnames because the request will never make it to your server otherwise, so there's no need to build your own validation logic.
The nginx documentation cautions against the use of if for rewriting. Please see the link here: http://wiki.nginx.org/Pitfalls#Server_Name
HTTP & HTTPS without if conditions:
server {
listen 80;
listen 443;
server_name website.com;
return 301 $scheme://www.website.com$request_uri;
}
server {
listen 80;
listen 443 default_server ssl;
server_name www.website.com;
# Your config goes here #
}
Solution for multiple domains, working on nginx 1.17 for me:
server {
listen 80;
server_name .example.com;
set $host_with_www $host;
if ($host !~* www\.(.*)) {
set $host_with_www www.$host;
}
return 301 https://$host_with_www$request_uri;
}
In this config example additionally rewrites HTTP on HTTPS, if you don't want rewrite — replace https:// with http:// in return string.
If you want keep protocol — use $scheme variable.

Resources