How to configure NGINX SSL (SNI) - ssl

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.

Related

Reverse proxy in nginx for nextcloud?

How do I set a reverse proxy for nextcloud?
This is my current config but it doesn't work:
server {
listen 8000;
server_name cloud.prjctdesign.com;
return 301 https://$host$request_uri;
}
server {
listen 4430 ssl http2;
server_name cloud.prjctdesign.com;
ssl_certificate /certs/cloud.prjctdesign.com.crt;
ssl_certificate_key /certs/cloud.prjctdesign.com.key;
include /etc/nginx/conf/ssl_params.conf;
client_max_body_size 10G; # change this value it according to $UPLOAD_MAX_SIZE
location / {
proxy_pass http://192.168.178.32;
include /etc/nginx/conf/proxy_params;
}
}
Also I enabled SSL using a let's encrypt cert. I run Nextcloud in the official VM image provided by Nextcloud / Techandme
I believe there is something wrong with the HSTS but I have no idea how it works. Also I based my forwarding off of this
I figured it out.
The reference to the ssl certificate is incorrect. Either run NGINX on the same server you are running nextcloud and redirect nginx to the position of the .cert file as in these lines:
ssl_certificate /certs/cloud.prjctdesign.com.crt;
ssl_certificate_key /certs/cloud.prjctdesign.com.key;
or generate a new cert on the nginx server and point the config towards it.

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.

nginx proxy based on host when using https

I need to use Nginx as an SSL proxy, which forwards traffic to different back ends depending on the subdomain.
I have seem everywhere that I should define multiple "server {" sections but that doesn't work correctly for SSL. Doing that I would always have the SSL being processed in the first virtual host as the server name is unknown until you process the https traffic.
Scenario:
One IP address
One SSL wildcard wildcard
Multiple backends which needs to be accessed like the following:
https://one.mysite.com/ -> http://localhost:8080
https://two.mysite.com/ -> http://localhost:8090
Nginx says "if" is evil: http://wiki.nginx.org/IfIsEvil, but what else can I do?
I have tried this, but it doesn't work, I get an 500 error but nothing in the error logs.
server {
listen 443;
server_name *.mysite.com;
ssl on;
ssl_certificate ssl/mysite.com.crt;
ssl_certificate_key ssl/mysite.com.key;
location / {
if ($server_name ~ "one.mysite.com") {
proxy_pass http://localhost:8080;
}
if ($server_name ~ "two.mysite.com") {
proxy_pass http://localhost:8090;
}
}
Has anyone managed to accomplish this with Nginx? Any help/alternatives, link, would be much appreciated.
I found the solution which is basically to define the SSL options and the SSL certificate outside the "server" block:
ssl_certificate ssl/mysite.com.crt;
ssl_certificate_key ssl/mysite.com.key;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+EXP;
ssl_prefer_server_ciphers on;
server {
listen 80;
server_name *.mysite.com;
rewrite ^ https://$host$request_uri? permanent;
}
server {
listen 443 ssl;
server_name one.mysite.com;
ssl on;
location / {
proxy_pass http://localhost:8080;
}
}
server {
listen 443 ssl;
server_name two.mysite.com;
ssl on;
location / {
proxy_pass http://localhost:8090;
}
}
Key things:
"ssl on;" is the only thing that needs to be within the "server" blocks that listen in https, you can put it outside too, but what will make the "server" blocks that listen in port 80 to use https protocol and not the expected http.
Because the "ssl_certificate", "ssl_ciphers: and other "ssl_*" are outside the "server" block, Nginx does the SSL offloading without a server_name. Which is what it should do, as the SSL decryption cannot happen based on any host name, as at this stage the URL is encrypted.
JAVA and curl don't fail to work now. There is no server_name - host miss match.
The short answer is to use Server Name Indication. This should work by default in common browsers and cURL.
according to http://www.informit.com/articles/article.aspx?p=1994795, you should indeed have two "server" sections, with two different server names.
In each one, you should include your ssl_* directives.

Multiple IPs+domains+SSL certs for one web site

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.

Why does listen `443 default_server ssl` work for multiple server names in nginx?

I run nginx for static content and as a proxy to Apache/mod_wsgi serving django. I have example.com and test.example.com as proxy to Apache/Django and static.example.com which serves all static files directly through nginx. I have a wildcard SSL cert so that each of these sub-domains can use SSL (and I only have one IP).
Why is it that when using listen 443 default_server ssl; in either test.example.com or example.com, SSL works for both yet I have to explicitly listen to 443 for static.example.com?
ssl_certificate /etc/ssl/certs/example.chained.crt;
ssl_certificate_key /etc/ssl/private/example.key;
server {
listen 80;
listen 443;
server_name static.example.com;
# ... serves content ...
}
server {
listen 80;
listen 443 default_server ssl;
server_name example.com;
# ... proxy pass to http://example.com:8080 (apache) ...
}
server {
listen 80;
# why don't I need `listen 443;` here?
server_name test.example.com;
# ... proxy pass to http://test.example.com:8080 (apache) ...
}
The SSL protocol by itself (without the SNI extension) uses the ip address of the server to request the SSL certificate. With SNI it also passes the hostname (doesn't work for Win XP), but that should't be relevant here.
Server directives are not an exact match. It's the "closest" match. It may appear "work", but it may be ending up in the wrong server directive. It's hard to tell without any more information, like the server root.
The point is something will always work since you appear to be using a single ip address.