Nginx non HTTPS websites redirect to other HTTPS websites - ssl

I'm using nginx for hosting multiple websites on a ubuntu server. Basically my setup is as follows.
My first domain example1.com (SSL enabled) can be accessed from http://example1.com as well as from https://example1.com. This working fine.
But my 2nd domain example2.com, I don't have SSL enabled - but when I type https://example2.com the url redirects to the first domain https://example1.com - Which is wrong
Now currently I have added this server block if someone type in the URL with https:// it will redirect back to http:// on the same domain. But this is not the right way to handle this issue. Does anyone has some better ideas?
server {
listen 443 ssl;
server_name example2.com www.example2.com;
rewrite ^ http://$server_name$request_uri? permanent;
}

The problem here is that you’re only using a single IP address (server-side) and rely on the TLS Server Name Indication extension (client-side). Nginx will always use your default HTTPS server if nothing else is available to handle the request.
Your solution looks quite right to me, although it will produce an error on the client-side if you have no valid certificate. The only other possibility would be to create a default invalid HTTPS server that simply drops the connection attempt. But I guess that’s not what you want.
server {
listen 443 ssl;
server_name example2.com *.example2.com;
return 301 http://$server_name$request_uri;
}
Always use return if you redirect at such a point.
A default invalid catch all configuration could look like the following:
server {
listen 443 ssl;
server_name _;
ssl_certificate blank.crt;
ssl_certificate_key blank.key;
return 403;
}
As I said, it will simply drop any connection attempt that doesn't contain a valid HTTP Host in the submitted headers or if the submitted HTTP Host in the header is not valid.

Having the following will listen on 443 (SSL), and because you don't have a SSL certificate for this domain, nginx will use the first or default SSL certificate, which will throw invalid domain error. Simply remove it, so that it doesn't listen on 443 (SSL).
server {
listen 443 ssl;
server_name example2.com www.example2.com;
rewrite ^ http://$server_name$request_uri? permanent;
}

Related

Nginx Reverse proxy not redirecting to HTTPS

So i have a Nginx server working as a reverse proxy with this configuration
http {
server {
listen 80;
listen [::]:80;
server_name www.example.tdl;
access_log logs/reverse-access.log;
error_log logs/reverse-error.log;
location / {
proxy_pass https://127.0.0.1:443;
}
}
}
My only problem is that when i connect to example.tdl it redirects correctly, but not with HTTPS. But its redirecting to the https port of my Apache server so i dont know where is the problem.
I never used nginx before so this is probably a configuration error.
How can i make that nginx redirects to that port with https?
This may sound dumb but what you've got is that nginx is working as a proxy for you. You connect to nginx via HTTP, nginx forwards your request to apache via HTTPS, then gets the answer back and transmit it to you using HTTP.
You need to make nginx listen for HTTPS with listen 443 ssl; and supply it with a certificate (ssl_certificate <path>;) and a key (ssl_certificate_key <path>;). After that add the following piece of code to the server block:
if ($scheme != "https") {
return 301 https://$host$request_uri;
}
This will redirect everything to HTTPS.

NGINX Reverse Proxy redirecting instead of proxying

i have a NGINX server running as a reverse proxy. Proxy works for windows hosts however i have a owncloud server and the proxy will instead re wright the url to the internal host name or IP address. ex(I type cloud.example.com and my url bar will change to 10.1.1.19 which is unresolvable over wan
i have checked DNS records and made sure NGINX can resolve host name. also tried just forwarding http traffic to cloud server to make sure using domain name was not the issue.
server {
listen 80;
listen [::]:80;
server_name example.com;
location / {
proxy_pass http://10.1.1.16:80/;
}
}
server {
listen 80;
listen [::]:80;
server_name cloud.example.com;
location / {
proxy_pass http://10.1.1.19:80/;
}
}
server {
listen 80;
listen [::]:80;
server_name remote.example.com;
location / {
proxy_pass http://10.1.1.17:80/;
}
}
i just need NGINX to run as a proxy for "cloud.example.com" instead of rewriting URL
I found a partial answer to this -- Why is my Nginx reverse proxy doing a 301 redirect instead of proxying?.
For me, it kept nginx from changing the hostname (i.e. from good-domain.com to 10.1.5.5:8080), but there doesn't appear to be a way to stop nginx from appending the port to the client's request URL.
So, in using the answer referenced above, I was able to go from http://10.1.5.5:8080 to http://good-domain:8080. It's still not where I want to be, but it definitely gets me closer.

Domain without ssl certificate redirecting to different ssl domain

I have two domains set up on a Digital Ocean droplet (with nginx). I've installed a SSL certificate in one of them (domain1) and everything is fine with that one. The second domain (domain2), does not require a SSL certificate but if I try to access https://domain2 is showing me the content of domain1 and giving me a certificate error (This page is not secure).
I understand the certificate error, but I don't want the contents of domain1 being displayed in https://domain2
Is it a configuration problem?
nginx always has a default server, the one that is used if the server_name does not match. If you only have one server block with listen 443, then that is the implicit default server for all https connections irrespective of server name.
You will need to set up an explicit catch-all server for https connections, or add listen 443 ssl to an existing server block to act as the catch-all server.
You can reuse the same certificate file and you will continue to get certificate errors if anyone attempts to use it, but at least your other domains will not be exposed.
For example:
ssl_certificate /path/to/crt;
ssl_certificate_key /path/to/key;
server {
listen 443 ssl;
server_name domain1;
...
}
server {
listen 443 ssl default_server;
return 403;
}
See this document and this document for more.

Setup HTTPS as default but allow HTTP?

I've an nginx vhost setup with both HTTP and HTTPS.
I'd like to make visitors which write in the address bar "www.example.com" to be directed to the HTTPS version of my website, but if they specify http://www.example.com then I'd like them to get the HTTP version.
I have tried setting the ssl listen as default_server but nothing seems different...
server {
listen *:80;
listen *:443 ssl spdy default_server;
ssl_certificate /etc/ssl/custom/www.example.com.crt;
ssl_certificate_key /etc/ssl/custom/www.example.com.key;
server_name example.com www.example.com;
}
Is there a way?
If the user specifies 'www.example.com' the browser simply assumes http://www.example.com. While you can redirect the http:// then to https:// there is no way to do this only if the access was caused by the browsers assumption, that is you cannot distinguish between the user entering http://... and the browser assuming http://...

Nginx serving SSL certificate of another site

I'm serving two sites with Nginx. First site (say A) has a SSL certificate and second site (say B) doesn't. Site A works fine when opening on https and B on http. But when I access site B on https, nginx serves the SSL cert and contents of site A with domain of B, which shouldn't happen.
Nginx config for site A is as follows. For site B, it's just a reverse proxy to a Flask app.
server {
listen 80;
server_name siteA.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name siteA.com;
ssl_certificate /path/to/cert.cert
ssl_certificate_key /path/to/cert_key.key;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:RC4-SHA:AES256-GCM-SHA384:AES256-SHA256:CAMELLIA256-SHA:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:CAMELLIA128-SHA;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
keepalive_timeout 70;
# and then the `location /` serving static files
}
I can't figure out what is wrong here.
Apparently I need a dedicated IP for site A.
Quoting from What exactly does "every SSL certificate requires a dedicated IP" mean?
When securing some connection with TLS, you usually use the certificate to authenticate the server (and sometimes the client). There's one server per IP/Port, so usually there's no problem for the server to choose what certificate to use. HTTPS is the exception -- several different domain names can refer to one IP and the client (usually a browser) connects to the same server for different domain names. The domain name is passed to the server in the request, which goes after TLS handshake. Here's where the problem arises - the web server doesn't know which certificate to present. To address this a new extension has been added to TLS, named SNI (Server Name Indication). However, not all clients support it. So in general it's a good idea to have a dedicated server per IP/Port per domain. In other words, each domain, to which the client can connect using HTTPS, should have its own IP address (or different port, but that's not usual).
Nginx was listening on port 443 and when request for site B went on https, the TLS handshake took place and the certificate of site A was presented before serving the content.
The ssl_certificate parameter should be closed with ; to get expected output.
Also make sure that you have followed the correct syntax in all the config file parameters by using following command and then restart or reload the service:
sudo nginx -t
NGINX supports SNI, so it's possible to serve different domains with different certificates from the same IP address. This can be done with multiple server blocks. NGINX has documented this in
http://nginx.org/en/docs/http/configuring_https_servers.html
For me HTTP2 and IPv6 are important, so I to listen to [::] and set ipv6only=off. Apparently this option should only be set for the first server block, otherwise NGINX will not start.
duplicate listen options for [::]:443
These server blocks
server {
listen [::]:443 ssl http2 ipv6only=off;
server_name siteA.com www.siteA.com;
ssl_certificate /path/to/certA.cert
ssl_certificate_key /path/to/certA_key.key;
}
server {
listen [::]:443 ssl http2;
server_name siteB.com www.siteB.com;
ssl_certificate /path/to/certB.cert
ssl_certificate_key /path/to/certB_key.key;
}
If you host multiple sites in you server and in one Nginx config if you have listen 443 ssl http2 default_server;
The default_server will give the same cert to all domains. removing it will fix the problem.
While following this tutorial I total missed this part:
Note: You may only have one listen directive that includes the default_server modifier for each IP version and port combination. If you have other server blocks enabled for these ports that have default_server set, you must remove the modifier from one of the blocks.