Nginx ignores return directive - nginx

The problem:
I have an application running with Nginx serving as a reverse proxy. I have a ssl certificate to a certain example.com, but I also want my application to respond to example.organization.com (even without a certificate for the domain).
My idea was to set a return directive to return the desired URL and 301 as the status code... The problem is, my directive is not being used by Nginx. The nginx does force a HTTPS connection, but with any URL used and returning 302, so with the example.organization.com the browser does not accept it because of the lack of a ssl certificate. Even when the listen 80 block is disabled the redirect still goes on. Nginx is running inside a Docker container and it's hitting another Docker container (I don't think it is influencing the behavior, but I'm not sure)
What I've tried:
I tried to use the rewrite ^ https://example.com$request_uri permanent instead of the return 301 https://example.com$request_uri.
I also tried this:
server {
listen 443 ssl;
server_name example.com;
if ($host != "example.com") {
return 301 https://example.com;
}
}
But it didn't work.
server configuration:
server {
listen 80;
server_name example.com example.organization.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/conf/cert.crt;
ssl_certificate_key /etc/nginx/conf/cert.key;
location / {
proxy_pass http://container:80/
}
proxy_set_header HOST $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

Related

nginx redirecting all subdomains (when it shouldn't)

I have an nginx server running. I want it to redirect http://www.example.com to https://www.example.com, but not touch any other subdomains like http://foo.example.com.
For some reason, no matter what I add in the subdomain, it still gets rerouted. My webpage shows on www.example.com (as it should), but also on foo.example.com and example.com (as it shouldn't)
This is my example.com config file:
server {
listen 80;
server_name www.example.com;
# For debug
add_header X-debug-message "listen:80, server_name:www.example.com, redirect:https://$host$request_uri" always;
# Riderect
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name www.example.com;
# For debug
add_header X-debug-message "listen:443, server_name:www.example.com, redirected:https://$host$request_uri" always;
# SSL
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root /var/www/example.com;
# Redirect
location / {
proxy_pass http://192.168.1.224:80;
}
}
Going to www.example.com shows me my webpage as expected. But going to foo.example.com also gives me my webpage - which it shouldn't. example.com also gives me the webpage.
Opening www.example.com in my browser, I see the following http header (as expected):
X-debug-message: DEBUG: listen:443, server_name:www.example.com, redirected:https://www.example.com/
Opening foo.example.com in my browser, I see the following http header (not as expected):
X-debug-message: DEBUG: listen:443, server_name:www.example.com, redirected:https://foo.example.com/
How can I make my nginx only redirect www.example.com ?
Ensure that the dns record for foo.yourdomain.com is actually created with
dns provider
Create a second server block for the subdomain 'foo.example.com'
otherwise all request to port 80
will be redirected to available server block, which in your case
www.example.com - the server block should look like this:
server {
server_name foo.example.com;
location / {
root path/to/foo/index.html;
index index.html index.htm;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
try_files $uri $uri/ /index.html;
}
listen 443 ssl; # managed by Certbot
ssl_certificate
/etc/letsencrypt/live/example.com/fullchain.pem; # n
managed by Certbot
ssl_certificate_key
/etc/letsencrypt/live/nextoma.com/privkey.pem; # managed by
Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by
Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by
Certbot
}
Add ssl certificate to the foo.example.com with the command:
certbot --nginx -d foo.example.com
Restart nginx and recheck foo.example.com again
You need to make the first entry listen on 443 for HTTPS and server name _ and return 404.
server {
listen 443 ssl;
server_name _;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_certificate /etc/nginx/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/nginx/certs/nginx-selfsigned.key;
location / {
return 404;
}
}
By having the typical HTTP to HTTPS redirect in the file (I have it as the last entry):
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
Then all HTTP requests get converted to the HTTPS counterparts. Then, if you request a subdomain that has not been configured in the NGINX configuration file, it will default to the first entry which returns a 404. All other configured subdomains, and the root domain, if you have that as an entry, will resolve correctly.
Also you can keep your wildcard DNS, which is more practical than having to add each subdomain as an entry, as you point out in your answer.
Thank you for all the comments!
For other readers, and future reference, this is now my enlightened understanding.
nginx treats the first entry in it's enabled-sites conf as a default route. Thus, the first entry
server {
listen 80;
server_name example.net www.example.net;
...
}
is in fact treated as
server {
listen 80 default_server;
server_name example.net www.example.net;
...
}
So, my mistake, was to add *.example.com -> MyIP to my DNS, and assuming nginx would just 404 all routes I didn't explicitly define. When in fact, it looks for a route that matches foo.example.com, and if it doesn't, routes it to the default route.
So, I now changed my DNS to explicitly handle all subdomains I want routed, and I list all of them explicitly in nginx.
Now - how I achieve my original plan - to just route *.example.com to my IP, and have nginx 404 all requests except the ones I excplicitly define - I still don't understand.
Explicitly routing all subdomains in the DNS is a bit less flexible, as I need to update the DNS and wait for the change to propagate if I want to test a new service internally. But, I guess that is fine for now.

Nginx reverse proxy to an https address behind corporate proxy

I am trying to setup an Nginx reverse proxy to an AWS API Gateway address like https://12345.execute-api.eu-central-1.amazonaws.com/v2 behind a corporate proxy.
I tried the following setup to www.example.com and it works. But as soon as I add https to it like https://www.example.com it fails. I add https since my API Gateway address is not accessible without it.
Current working config:
server {
listen 80;
listen [::]:80;
listen 443;
underscores_in_headers on;
location / {
proxy_pass_request_headers on;
proxy_set_header Host www.example.com;
proxy_pass http://myCorporateProxy.org:8080;
}
}
What I want to achieve and error I get:
Redirect all incoming traffic to localhost to be redirected to API Gateway address which looks similar to https://123456.execute-api.region.amazonaws.com/v2/
When trying following config, I get a 302 temporarily Moved error.
In configuration it would look like this:
server {
listen 80;
listen [::]:80;
listen 443;
underscores_in_headers on;
location / {
proxy_pass_request_headers on;
proxy_set_header Host https://www.example.com;
proxy_pass http://myCorporateProxy.org:8080;
}
}
You should try something like this. To redirect from http to https is a little different.
server {
listen 80;
server_name myCorporateProxy.org www.myCorporateProxy.org;
return 301 https://myCorporateProxy.org$request_uri;
}

Is there any way to make your nginx proxy not forward HTTP -> HTTPS for a specific URL only?

I have auto SSL enabled for a VHOST, but I need to disabled that for a specific URL that needs to accept only non SSL requests.
This, put into vhosts, is working fine if the specific old URL was HTTPS, but it is HTTP. I cannot use HTTPS_METHOD=noredirect disabling auto SSL for the entire VHOST. Is it possible just to disable it for the context of this custom nginx location? I can see in the nginx-proxy logs that it gets a 301 before it even hits this nginx customization. So unfortunately I've only been able to get this proxy_pass config to work with HTTPS URLs, not HTTP.
Thanks for your help.
location /specific/old/http/URL {
proxy_pass http://service.new.tld/new;
proxy_set_header host http://service.new.tld;
proxy_ssl_certificate /etc/nginx/certs/new.tld/fullchain.pem;
proxy_ssl_certificate_key /etc/nginx/certs/new.tld/key.pem;
}
location /upstream {
proxy_pass http://service.new.tld;
proxy_ssl_certificate
/etc/nginx/certs/service.new.tld/fullchain.pem;
proxy_ssl_certificate_key
/etc/nginx/certs/service.new.tld/key.pem;
}
You need to Have one server directive for both http and https (will listen on 80 and 443) and you need to add the redirect script only on the wanted locations.
See example:
server {
listen 80;
listen 443 ssl;
server_name example.com www.example.com;
ssl on;
ssl_certificate example.crt;
ssl_certificate_key example.key;
location /specific/old/http/URL {
proxy_pass http://service.new.tld/new;
proxy_set_header host http://service.new.tld;
proxy_ssl_certificate /etc/nginx/certs/new.tld/fullchain.pem;
proxy_ssl_certificate_key /etc/nginx/certs/new.tld/key.pem;
}
location /upstream {
# add this condition only on the locations you want to redirect to https
if ($scheme = http) {
return 301 https://$server_name$request_uri;
}
proxy_pass http://service.new.tld;
proxy_ssl_certificate /etc/nginx/certs/service.new.tld/fullchain.pem;
proxy_ssl_certificate_key /etc/nginx/certs/service.new.tld/key.pem;
}

Make it so nginx always has site using https

NOTE: example.com is just that. Per the rules of stackoverflow, I'm not using an actual domain.
I've been trying to get it so my nginx server for a single site always uses https.
I have the certificate installed and if I view the site with:
https://www.example.com it works fine.
But by default it goes to http and shows the site as insecure.
Here is the config:
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /var/www/nodeapp;
index index.html index.htm;
server_name www.example.com example.com;
location / {
proxy_pass https://[IP address here]:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
I esentially want everything to point to https://www.example.com
Because your site has both of http and https. (80 port and 443 port).
To activate the only https you have to remove the config for http.
Please remove listen 80 and use listen 443 instead.
If you want to redirect all traffics to https,
you could add redirection config as following.
server{
if ($host = your_domain) {
return 301 https://$host$request_uri;
}
server_name your_domain;
listen 80;
return 404;
}
I've assumed that your config has ssl part in your main config.
For example,
listen 443 ssl;
ssl_certificate /etc/***/fullchain.pem;
ssl_certificate_key /etc/**/privkey.pem; # managed by Certbot
ssl_dhparam /etc/**/ssl-dhparams.pem; # managed by Certbot

Nginx redirect only root domain but not subdomain to www

Currently I'm using setting below to redirect non-www domain to www domain and it's working fine:
server {
listen 80;
server_name example.com;
return 301 http://www.example.com$request_uri;
}
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://www.example.com:8888;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
However, now I would like to allow wildcard subdomain but it seems like all the subdomains were being redirect to www.domain.com. So my question is how can I make it only redirect the root domain to www only and excluding all other subdomain? Thanks.
The first server block is also the implicit default server, which means that any domain name that does not match www.example.com will be handled by it.
If you would like that second server block to handle all domains except example.com, you can make it the default server explicitly, by adding the default_server option to the listen directive. See this document for details.
For example:
server {
listen 80;
server_name example.com;
return 301 http://www.example.com$request_uri;
}
server {
listen 80 default_server;
...
}

Resources