Nginx server_name & listen matches specified patterns - nginx

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!

Related

Configuring Nginx - routing traffic from HTTP to HTTPS and BAD REQUEST error (local host, no domain)

I'm trying to configure my Nginx in a way so that all HTTP requests are redirected to HTTPS. This is a testing environment and I don't have the domain, hence, I'm not sure whether the redirect can function properly. The host part is simply 127.0.0.1. This is the current configuration:
server {
listen 80;
listen [::]:80;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name _;
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
...
I also tried:
removing server_name _;
putting the return 301 in a location block;
adding further ssl settings, such as ssl_session_timeout, ssl_protocols, ssl_prefer_server_ciphers.
ssl on has been removed.
The syntax has been tested, nginx reloaded, the ports have been tested with nmap (both 80 and 443 are open).
When I curl -k (since the certificate is self-signed) 127.0.0.1 I get this message:
301 Moved Permanently
nginx/1.14.0 (Ubuntu)
When I curl -k 127.0.0.1:443 I get this message:
400 The plain HTTP request was sent to HTTPS port 400 Bad Request The
plain HTTP request was sent to HTTPS port nginx/1.14.0 (Ubuntu)
Could someone help me to understand what am I doing wrong? I'd be happy to provide more information. Thank you so much!!
So here is an nginx config that is working for me.
upstream app {
server app:8080;
}
server {
listen 80;
listen [::]:80;
server_name webprojects-dev.co.uk;
return 301 https://webprojects-dev.co.uk$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 http2;
server_name webprojects-dev.co.uk;
include /etc/nginx/common.conf;
include /etc/nginx/ssl.conf;
location / {
proxy_pass http://app;
include /etc/nginx/common_location.conf;
}
}
In this instance nginx is running in a stack of docker containers networked with docker compose but that shouldnt have any bearing on how it works.
The upstream is the app container (and port) for a reverse proxy.
The first server block is forwarding on requests to https. As you can see the main difference between mine and yours is the server_name is the domain name and is also included in the return 301 statement.
The second server block is for https. Again server_name is a domain but other than that the only other difference I can see is I don't have ssl on the line listen [::]:443.
Disclaimer: Not an expert on nginx. I just hacked away till I had a reverse proxy config that works for me and now I just copy and paste it for everything.

Want to https://www.example.org to https://example.org in Nginx

I want to redirect https://www.example.com to https://example.com in Nginx.
I tried to do this using with below code, but I have to redirect multiple domains so can't mention specific "example.com" in the return line. I have around 30 different domains for which this need to be done.
I have gone through many suggested solutions but all are with one domain which doesn't meet my requirement. Like if there are domains (example.com,example.com,xyz.com etc) all need to redirect to https://respectivedomain(non-www)
server {
listen 443 ssl http2;
server_name www.example.com;
# redirects www to non-www. wasn't work for me without this server block
return 301 $scheme://example.com$request_uri;
}
Update:
server {
server_name "www.(.+?\.\w+)" ;
return 301 https://$1$request_uri;
}
I tried the above code but still, there is an error "NET::ERR_CERT_COMMON_NAME_INVALID".
The site is working with below
example.com
http://example.com
https://example.com
but not with adding www to a domain, SSL certificate is issued to non-www domain
You can redirect using configuration below.
Single domain
server {
listen 443 ssl http2;
server_name www.example.com;
return 301 $scheme://example.com$request_uri;
}
Multiple domains
server {
listen 443 ssl http2;
server_name "~^www\.(.*)$" ;
return 301 $scheme://$1$request_uri;
}
source

Nginx - Generic redirect all www to non-www

Is it possible to make a generic HTTP -> HTTPS and WWW -> non-WWW redirect in Nginx which impact all domains. Or do I need to set it up for every single domain?
I've made the HTTP->HTTPS as follows:
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
You should use two server blocks for this:
server { # redirect http/https www.example.com to https://example.com
listen 80;
listen 443 ssl;
server_name www.example.com;
ssl_certificate <path_to_ssl_cert_for_domain_www.example.com>;
ssl_certificate_key <path_to_key_for_ssl_cert_above>;
# other ssl parameters here if needed
return 301 https://example.com$request_uri;
}
server { # redirect http://example.com to https://example.com
listen 80;
server_name example.com;
return 301 https://example.com$request_uri;
}
server { # main site config
listen 443 ssl;
server_name example.com;
# rest of your configuration here
...
}
Usually paid SSL certificates already includes both domain name with www prefix and without it. If you're using Lets Encrypt service, you can generate certificate for both example.com and www.example.com by yourself.

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

Nginx redirecting to the wrong site; poorly formed server_name directive

The Problem
When you type example.com into the address bar of a browser WITHOUT entering the scheme, i.e. http:// or https://, Nginx redirects the user to https://api.example.com instead of https://example.com as intended. I'm pretty sure there's something wrong with my Nginx config, but I'm not sure what.
Details
I'm hosting two websites on the same server, with the same IP. The relevant bits from the DNS zone file looks something like (domain and IP anonymized here):
example.com. 1800 IN A xxx.xxx.xxx.xxx
www.example.com. 1800 IN CNAME example.com.
api.example.com. 1800 IN CNAME example.com.
I have two SSL certs installed (provided by letsencrypt), one for each site, and both sites are configured to redirect to HTTPS. I have two vhost config files, one for each site, as follows:
/etc/nginx/sites-available/api
/etc/nginx/sites-available/default
Both are symlinked into /etc/nginx/sites-enabled/. The relevant bits from the two config files are as follows:
# /etc/nginx/sites-available/api
server {
listen 80;
listen [::]:80 ipv6only=on;
server_name api.example.com;
return 301 https://api.example.com$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
include snippets/api-ssl-params.conf; # ssl config info
server_name api.example.com;
# ... the rest of the site config ...
}
and:
# /etc/nginx/sites-available/default
server {
listen 80;
listen [::]:80;
server_name www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 default_server ipv6only=on;
include snippets/ssl-params.conf; # ssl config info
server_name example.com;
# ... the rest of the site config ...
}
I don't understand why just entering example.com into the address bar would redirect to https://api.example.com because:
just plain example.com doesn't appear in the api config file anywhere
example.com shouldn't match the server_name directive api.example.com
the server blocks in default are marked as default_server so shouldn't that take precedence when an ambiguous domain name was typed in?
Thanks!!!
Duh. Figured it out in the process of writing the question. The problem is that just plain example.com doesn't appear in the server_name directive for either of the sites listening on port 80. Since that causes ambiguity, nginx picks the first site in alphabetic order.
I updated the config file for the default site as follows:
# /etc/nginx/sites-available/default
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com; # <-- CHANGED THIS LINE
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 default_server ipv6only=on;
include snippets/ssl-params.conf; # ssl config info
server_name example.com;
# ... the rest of the site config ...
}
And all was right with the universe.

Resources