nginx: I can't access default virtual host on port 80. Instead get response from wrong server_name - http

I have two sites-enabled for nginx.
I have the default server:
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
try_files $uri $uri/ =404;
}
}
and I have a FQDN with a redirect for https:
server {
listen SERVER-IP:80 ;
listen [::]:80;
server_name FQDN;
location / {
return 301 https://$host$request_uri;
}
}
My issue is that if I try to access my server using a different domain name or using the IP address, using http on port 80, I will always be redirected to https on port 443. I cannot seem to get the default server to respond at all.
I even created another server block that begins:
server {
listen 80;
listen [::]:80;
server_name OTHER-FQDN;
And even when I try to load http://OTHER-FQDN I get redirected to https port 443 with a certificate of FQDN.
Why?
Or better: how can I gain insight into which server block is being used for which request? Clearly only the block with FQDN is ever accessed even though I have another OTHER-FQDN that matches or a default_server that should match.
I am frustrated because the inner working of nginx in this case seem so opaque to me and counter to exectation.

Related

Change port for http to https -- Nginx

Sorry for limited understanding on Nginx, Iam new to Nginx.
I have a webapp running on React and Nginx. Recently I received the SSL certificates for my website. I tried to configure the website and it worked partially. The problem is when I tried to open "https://example.com", the SSL certificates are visible here but its showing nginx default home page. While when I open "http://example.com" it shows all the webcontent.
I attempted to:
change the port from 80 to 443
Reinstall nginx.
But nothing seems to work. Here is my nginx confs at the moment:
/etc/nginx/sites-available/example.org
server {
listen 443;
listen [::]:443;
ssl on;
ssl_certificate /etc/nginx/ssl/bundle.cer;
ssl_certificate_key /etc/nginx/ssl/example.key
root /var/www/html;
server_name example.org;
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
listen [::]:80;
server_name _;
return 301 https://example.org;
}
/etc/nginx/conf.d/www/example.org.conf
server {
listen 80 default_server;
server www.example.org;
location / {
root /usr/share/nginx/html;
index index.htm; index.html;
}
}
Note: I reload nginx at every new attempt.
Please help where am I going wrong.
Keeping just 1 file for config works for the above problem. I kept the "default" conf at "/etc/nginx/sites-available"

NGINX Forward HTTPS from any domain to specific URL

I am implementing an internal DNS server for block specific DNS requests to malicious websites, using a DNSRBL list against bind9. Whenever there's a match, the DNS server responds with the IP of an internal NGINX server that serves a block page.
Example, when the internal client requests http://www.badsite.com/ the DNS server responds with 192.168.0.100 as an example, which is the IP of the NGINX server. Then NGINX uses a 301 to forward the request to an HTTPS site which serves the block page message to the end user.
That works well using a simple NGINX config:
server {
listen 80 default_server;
server_name _;
return 301 https://block.xyz.com;
}
server {
listen 443 ssl;
server_name block.xyz.com;
ssl_certificate /etc/letsencrypt/live/block.xyz.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/block.xyz.com/privkey.pem;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
The issue I'm having is when the client requests an HTTPS site, i.e.:https://www.badsite.com/ . I would like to forward any incoming SSL/443 requests to https://block.xyz.com. I've tried adding the following directive:
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/letsencrypt/live/block.xyz.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/block.xyz.com/privkey.pem;
return 301 https://block.xyz.com;
}
And I get the typical SSL error saying the certificate doesn't match the domain: NET::ERR_CERT_COMMON_NAME_INVALID, which is understandable. The same thing happens when I change the directive from return to rewrite:
...
rewrite ^ https://block.xyz.com;
....
How would I go about adding a directive in NGINX to accomplish this? This guide (https://sweetcode.io/ad-blocking-with-local-dns-servers-and-nginx/) provided me a way to do the http side for implementing something similar for Ad Blocking, but doesn't speak to https requests.
Any clues?
In your server block try adding:
if ($host != "block.xyz.com") {
rewrite ^/(.*) https://block.xyz.com/$1 permanent;
}

How to fix http redirects with Nginx?

I have a webpage where http redirects are a bit broken.
The current behavior is this:
www.example.com, example.com, http://www.example.com, http://example.com, https://www.example.com all gets redirected to https://www.example.com
and
https://example.com gets an error saying refused to connect.
I want the behavior to be like this:
example.com, http://example.com, https://example.com redirects to https://example.com
www.example.com, http://www.example.com, https://www.example.com redirects to https://www.example.com
Here is my Nginx config file
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name _;
location ~ /.well-known {
allow all;
}
location / {
try_files $uri $uri/ =404;
}
}
Reason is because I want these links to work
https://www.ssllabs.com/ssltest/analyze.html?d=example.com
https://www.ssllabs.com/ssltest/analyze.html?d=www.example.com
https://hstspreload.org/?domain=example.com
https://hstspreload.org/?domain=www.example.com
You have two independent issues:
Your requests all redirect to example.com, regardless of which specific domain is originally accessed.
This happens because the $server_name variable that you are using is effectively a static variable in a given server context, and has a very distant relationship to $http_host.
The correct way would be to use $host instead (which is basically $http_host with some edge-corner cleanups).
You're receiving connection issues when trying to contact https://example.com, but not https://www.example.com.
There is not enough information in your question to pinpoint the exact origin of this problem.
It can be a DNS issue (A/AAAA records of example.com set at an IP address where appropriate bindings to the https port aren't made).
It could be an issue with the mismatched certificate:
Does your certificate cover both example.com and www.example.com? If not, then you can't have both.
If you have separate certificates, you may also need to acquire separate IP addresses, or risk preventing a significant number of users from accessing your site due to lack of SNI.
As of note, it should also be pointed out that it is generally a sloppy practice to not have a unified notation on the way your site is accessed. Especially if SEO is of any concern to you, the best practice is to decide on whether you want to go with or without www, and stick to it.
You need something like this:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name www.example.com;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;
add_header Strict-Transport-Security "max-age=300; includeSubdomains; preload";
return 301 https://www.example.com$request_uri;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name example.com;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;
add_header Strict-Transport-Security "max-age=300; includeSubdomains; preload";
location ~ /.well-known {
allow all;
}
location / {
try_files $uri $uri/ =404;
}
}
All your requests will be ultimately routed to https://example.com.
Your ssl certificate should also be valid for https://www.example.com which I note you have said it is.

NginX http redirection to https returns unreadable respone

I want to redirect all http requests to https with NginX, but I have some difficulties with it.
Here is my vhost file :
server {
gzip off;
listen 80;
listen [::]:80;
server_name mydomain.fr www.mydomain.fr sub.otherdom.fr otherdom.fr;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
root /usr/share/nginx/html;
index index.html index.htm;
ssl on;
server_name mydomain.fr www.mydomain.fr sub.otherdom.fr otherdom.fr;
ssl_certificate /root/tmp/live-ecdsa/mydomain.fr/0001_chain.pem;
ssl_certificate_key /root/tmp/live-ecdsa/mydomain.fr/privkey-p384.pem;
access_log /var/log/nginx/default.access.log;
charset utf-8;
location / {
try_files $uri $uri/ /index.html;
}
}
Trying to access these domain over plain http with different browsers results in the following :
Chrome/Firefox : downloading a file filled with bytes data
Edge : displays a blank page with €ÿÿÿÿ
A curl -I mydomain.fr outputs ▒▒
Accessing these domains directly over https works.
I have already tried with both return 301 https://$host$request_uri; and return 301 https://$server_name$request_uri;
I suspect it has something to do with the fairly large number of server names you are declaring in the one server name field inside a pretty locally scoped context. Although, if I'm honest thats a fairly unfounded assertion based on habits I've become user to.
I'd suggest a few things, although generally most of this wont fix your problem, it might make it easier to work out whats happening:
split your config into purposed files. Ie. Create a ssl.conf in another folder which contains all youe cert settings, cipher suites etc. Then add an include /path/to/ssl.conf in your config.
dont use $host, this variable can be set by the use so probably a less than great idea
Assuming you have all the other relevant ssl/tls settings referenced from somewhere else then the below should roughly work.
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name mydomain.fr;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
root /usr/share/nginx/html;
$server_name mydomain.fr
location / {
try_files $uri $uri/ /index.html;
}
}
Well, although user6788523 response helped me with the debugging, the fault was on my side.
I had several other vhost files with the http2 directive associated with the http port 80 (listen [::]:80 http2;). Removing the http2 directive resolved the problem.
This setting must be used only with ssl enabled server block

Nginx server_name & listen matches specified patterns

In this example the domain has been replaced with domain.com
Our main issue:
When i type https://domain.com i don't get redirected to https://www.domain.com, we currently don't have a rule for this what would be the best way to solve this?
According to our nginx configuration we have not specified 443 for https://domain.com but still its accessible, why is that?
We have valid ssl certificates for both domain.com and www.domain.com.
We do not have a wildcard certificate *.domain.com.
Our Configuration:
#All non-matching patterns
server
{
listen 80;
#enabling this will cause things to break.
#2015/12/18 09:21:54 [error] 32165#0: *1661 no "ssl_certificate" is defined in server listening on SSL port while SSL handshaking, client: *censored*, server: 0.0.0.0:443
#listen 443 ssl;
#Horrible looking match all pattern.
server_name _ "" domain.com *.domain.com;
return 301 https://www.domain.com$request_uri;
}
#Main site ssl enforced
server
{
listen 443 ssl;
server_name www.domain.com ios.domain.com android.domain.com;
...
}
#Staging / Test site
server
{
listen 443 ssl;
listen 80;
server_name stage.domain.com;
...
}
#Rental cars site ssl enforced
server
{
listen 443 ssl;
server_name hyrbil.domain.com;
...
}
#ios redirect to enforce https
server
{
listen 80;
server_name ios.domain.com;
return 301 https://ios.domain.com$request_uri;
}
#android redirect to enforce https
server
{
listen 80;
server_name android.domain.com;
return 301 https://android.domain.com$request_uri;
}
Bonus question:
Is it possible to match all ssl traffic and do a redirect unless it matches a specific domain, for example make https://xxx.domain.com pass a 301 to https://www.domain.com even tho i don't have a certificate for xxx.domain.com without showing "This page is unsecure, are you sure that you want to proceeed"?
If you have one virtualhost listening on 443, all traffic reaches your IP address will be served by that virtualhost.
Create an SSL virtualhost for domain.com and put a simple redirect in it.
Or create a "catch all/default" SSL virtualhost, and check the HOST header and redirect regarding that, like:
if ($host !~* ^www\.doman\.com$) {
rewrite ^(.*)$ http://www.domain.com$1 permanent;
}
But it will show SSL certificate error on all FQDNs not included in your certificate!

Resources