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.
Related
I have this NGINX configuration as follows:
# jelastic is a wildcard certificate for *.shared-hosting.xyz
server {
listen 443;
server_name _;
ssl on;
ssl_certificate /var/lib/jelastic/SSL/jelastic.chain;
ssl_certificate_key /var/lib/jelastic/SSL/jelastic.key;
}
# fullchain2 is a certificate for custom domain
server {
listen 443 ssl;
server_name my-custom-domain-demo.xyz www.my-custom-domain-demo.com;
ssl_certificate /var/lib/nginx/ssl/my-custom-domain-demo.xyz/fullchain2.pem;
ssl_certificate_key /var/lib/nginx/ssl/my-custom-domain-demo.xyz/privkey2.pem;
}
# additional configuration for other custom domains follows
The NGINX server receives requests with host having a pattern like of *.shared-hosting.xyz, e.g. website1.shared-hosting.xyz, website2.shared-hosting.xyz
and also with variable hosts having different domains like my-custom-domain-demo.xyz or another-custom-domain-demo.xyz etc.
Now the problem is the lower server NGINX configuration overrides the upper configuration. Having it, the upper does not work anymore,
and accessing *.shared-hosting.xyz returns certificate error, and browser is telling the certificate is for my-custom-domain-demo.xyz only.
What can be done with this such that the lower NGINX config triggers for *.shared-hosting.xyz domains and every other additional server configuration will not trigger
when host is in the pattern of *.shared-hosting.xyz?
The server_name _; is irrelevant (and is not required in modern versions of nginx). If a server with a matching listen and server_name cannot be found, nginx will use the default server.
In the absence of a default_server suffix to the listen directive, nginx will use the first server block with a matching listen.
If your configurations are spread across multiple files, there evaluation order will be ambiguous, so you need to mark the default server explicitly.
Try this for the jelastic server block:
server {
listen 443 ssl default_server;
ssl_certificate /var/lib/jelastic/SSL/jelastic.chain;
ssl_certificate_key /var/lib/jelastic/SSL/jelastic.key;
...
}
See this document for more.
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.
I am about to use different ssl certificates for different virtual hosts, so I started by moving the existing ssl directives from the http block into one of the server blocks, before I start to add other ssl certificate directives into other server blocks. But as soon as I did this, the web server involved cannot be accessed anymore. Chrome reported connection closed and Nginx's error log read like this:
2016/01/08 20:13:32 [error] 16968#0: *364 no "ssl_certificate" is defined in server listening on SSL port while SSL handshaking, client: x.x.x.x, server: 0.0.0.0:443
The ssl directives I moved include:
ssl_certificate
ssl_certificate_key
ssl_protocols
ssl_dhparam
ssl_prefer_server_ciphers
ssl_ciphers
What could possibly go wrong when moving these directives from http block to server block?
Make sure you haven't a global server configured to listen to 443.
Because you moved the ssl_certificate and ssl_certificate_key within a specific virtual host, that means the default configuration is missing the certificate and key. This is not allowed by Nginx. Each virtual host that is configured to listen on 443, regardless it's the default or not, must be configured to serve a certificate.
The default_server should only be processed when other virtual host listening on 443 is not selected, so why lacking ssl certificates on the default_server could impact access to other virtual hosts?
That's the point. Nginx reject the configuration because, if this scenario should happen, it would not be able to process the request because of the lacking of the ssl_certificate. Therefore, the configuration is invalid.
First of all my problem is different.
I have used listen 443 default ssl; also listen 443 ssl; and commenting out # but seems nothing is working. Port 80 works fine but on port 443 I get this error.
Currently this is the default file for nginx.
server {
listen 80;
listen 443 ssl;
#listen 443 default ssl;
server_name .******.org;
keepalive_timeout 70;
#ssl on;
ssl_certificate /etc/ssl/private/lol/www.*******.crt;
ssl_certificate_key /etc/ssl/private/lol/www.********.key;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers RC4:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
On ssl_protocols I also tried to only use SSLv3 TLSv1 but its same. My nginx version is 1.2.1.
I have gone through many online sites even here but I think my problem is not being solved with any of those methods mentioned by different geeks.
So finally I am here.
Any suggestions?
P.S: I am using cloudflare, but there I have turned Universal SSL Off as I want to use other ssl.
You should write two server blocks one for http and one for https like:
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/public/;
index index.html;
#other settings
}
server {
listen 443;
server_name localhost;
root /var/www/public/test/;
index index.html;
ssl on;
ssl_certificate /etc/nginx/certs/wss.pem;
ssl_certificate_key /etc/nginx/certs/wss.pem;
#other settings
}
I have tried it with the default nginx settings and both ports work fine.
If you are experiencing this issue with Google Compute Engine / Google HTTP loadbalancer... Ensure you have your instance group setup with separate named ports for http: 80 and https: 443.
Or it will randomly select a port.
This came about in my case due to originally setting up the HTTP loadbalancer when it was still in beta. Then when I added another loadbalancer it refreshed the settings and started randomly failing.
It was failing 50% of the time, because I only had Nginx setup with a vhost for port 80, and it was trying to push HTTP requests to port 80 on the web boxes.
The error you get is most likely, because you send a unencrypted HTTP-request to the SSL-port.
Something like
wget http://example.com:443/
This is a client problem (the server just tells you that it refuses to answer non-encrypted messages on to-be-encrypted channels)
It is client problem.
I was having the same issue. Turns out the https prefix was being dropped in the URL.
In the browser inspect the network traffic to verify that the browser is sending an http request, not https. Issue found!
Manually type in the wanted URL with https to retrieve the page successfully.
Now you can go about applying a focused fix to your client.
I would like to have two domains, each with their own SSL cert, each SSL cert has its own IP of course, to point to the same web site on one physical server. The server will have to have two IPs too of course. What is this called? How is this done with nginx? OS is Linux. Thanks!
Create two server entries with different listen and ssl_certificate(_key) directives using the different IP addresses but the same root where your shared web pages are stored. For example:
server {
listen 1.2.3.4:443;
server_name first-domain.example;
root /srv/html/shared_domain_data;
ssl on;
ssl_certificate /etc/nginx/ssl/first_domain.pem;
ssl_certificate_key /etc/nginx/ssl/first_domain_key.pem;
}
server {
listen 9.8.7.6:443;
server_name second-domain.example;
root /srv/html/shared_domain_data;
ssl on;
ssl_certificate /etc/nginx/ssl/second_domain.pem;
ssl_certificate_key /etc/nginx/ssl/second_domain_key.pem;
}
It's called nothing special.