nginx redirecting all subdomains (when it shouldn't) - http

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.

Related

Question regarding subdomains and rerouting into domain, using Flask/Nginx on Ubuntu Linode

I currently have a problem regarding my nginx configuration. I bought a domain name and set up a Linode Compute Instance. It's a simple microblog, which uses Flask/Nginx/Gunicorn/Supervisor. Now, the site is running as intended when I have the gunicorn workers going at it, serving (an example, for privacy) "domain.com". But upon navigating to "www.domain.com" (what I assume to be a subdomain), nginx just says "500 error". I managed to get a hold of the logs, and this is what's being displayed around the time of the 500 error:
rewrite or internal redirection cycle while internally redirecting to "/index.html", client: 2603:7000:a700:cc1:c867:5aae:ff32:199c, server: www.domain.com, request: "GET / HTTP/1.1", host: "www.domain.com"
Now, some research on SO and Nginx docs suggest a number of reasons, while the latter also has a laundry list of what NOT to do. I'd like to approach this in the proper way. Any and all help is appreciated, and I'll also post my most current (and working) nginx configuration for the site in question below:
server {
server_name domain.com www.domain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/domain.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
}
server {
if ($host = domain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen [::]:80;
listen 80;
server_name domain.com;
return 404; # managed by Certbot
}
I'll admit I don't want to toy around with the config too much because of the LE configuration, but what am I doing wrong here?

How do I configure an ssl certificate with Nginx on Ubuntu 18.04?

I am trying to install an SSL certificate on an Ubuntu server with Nginx (my project is on a Flask server). When I try to reach my domain with my current configuration, the site can't be reached and ERR_CONNECTION_TIMED_OUT appears. I'm also trying to redirect all http requests to https. This is my current .conf file:
server {
server_name backlogtracker.live www.backlogtracker.live;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
}
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate /etc/letsencrypt/live/backlogtracker.live/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/backlogtracker.live/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
}
server {
if ($host = www.backlogtracker.live) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = backlogtracker.live) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 default_server;
listen [::]:80 default_server;
server_name backlogtracker.live www.backlogtracker.live;
return 301 https://$server_name$request_uri;
}
Even with https, I can't reach the domain. Is there something that I'm missing?
Redirect http->https
This is a simple pattern for redirecting everything to https:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
It does not fit to all use-cases, but for most it is the simplest way without strange directives.
Order
Order does in some cases make a difference in config-files. Nginx is working top-down, so to prevent strange behaviour I'd suggest to always write your config as a story. E.g. return immediately stops execution, so stuff behind that is not processed. I would suggest the order:
connection settings (listen, server_name)
general config (ssl, headers, log, etc)
logic (if, map, ..)
locations
Headers for reverse proxy
I would suggest to always add headers (can be put in server-block to work for all locations):
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Referer $http_referer;
proxy_set_header X-Forwarded-Proto $scheme;
SSL Protocol
Disable old TLS protocols
ssl_protocols TLSv1.2 TLSv1.3;
Further inspection
If not working then:
What is included in /etc/letsencrypt/options-ssl-nginx.conf
What are the logs of Flask and Nginx telling?
Are both running on host machine (no containers)?

Nginx ignores return directive

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";
}

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

Accessing site on nginx by https by default

I have website on nginx server! I want to make accessing the site by https by default(on specified port, I wrote in below)! I mean, when I write in browser - mysite.net:90, or www.mysite.net:90, it will go on https, instead of http! I've already tried to redirect requests with "rewrite" in server block, and "return", but it doesn't work.
This is how my server block looks now:
server {
listen 90;
listen 9090 ssl;
server_name example.com;
ssl on;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
root /var/www/path;
fastcgi_param HTTPS on;
fastcgi_param HTTP_SCHEME https;
......
}
You may find this forum post useful:
https://www.digitalocean.com/community/questions/http-https-redirect-positive-ssl-on-nginx
Basically you need to create a redirection from your HTTP instance where all requests are automatically redirected to HTTPS.
Like this:
server {
listen 90;
server_name example.com;
# Redirect all requests to https
return 301 https://$server_name$request_uri;
}
server {
listen 9090 ssl;
server_name example.com;
ssl on;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
root /var/www/path;
fastcgi_param HTTPS on;
fastcgi_param HTTP_SCHEME https;
}
Try that and see if that works for you.
But basically you for the first instance, you are simply creating a redirection and all the real configuration will be on the second one.

Resources