Nginx - Upstream Configuration Issue - nginx

I noticed something on an nginx config. There are 2 upstream blocks configured that are exactly the same:
upstream test1.example.com {
server flaskapp.example.com:5000
}
server {
listen 443 ssl;
proxy_pass test1.example.com;
ssl_certificate /opt/certs/example1.com.crt;
ssl_certificate_key /opt/example1.com.key;
ssl_protocols TLSv1.2;
ssl ciphers "ECDHE-ECDSA-AES128-GCM-SHA256"
}
upstream test2.example.com {
server flaskapp.example.com:5000
}
server {
listen 443 ssl;
proxy_pass test2.test.com;
ssl_certificate /opt/certs/test.com.crt;
ssl_certificate_key /opt/test.com.key;
ssl_protocols TLSv1.2;
ssl ciphers "ECDHE-ECDSA-AES128-GCM-SHA256"
}
I have 2 server blocks listening on port 443. So I have the same server listening for 2 separate connections on the same block... if that makes sense.
My thought was that this would fail because the same server listening for incoming https connections to test1 and test2.example.com wouldn't know 'where' to route the requests too. But that's not what's happening.
If I go to https://test1.example.com I am routed to the correct app. And https works as expected.
If I go to https://test2.example.com I am routed to the correct app. But https does not work as expected. This is confusing because both certs are wildcard certs. I am unsure why 1 succeeded and one failed.
If I comment out the first upstream block:
# upstream test1.example.com { server flaskapp.example.com:5000 }
# server {proxy_pass test1.example.com; }
Something stranger happens. Connecting to https://test2.test.com gives me a 'failed to connect to server' error message in my web browser. And the logs show this as the error:
No "ssl_certificate" is defined in server listening on SSL port while SSL handshaking
This is for test1.example.com, and I know the wildcard cert works. I'm using it elsewhere. So I'm unsure why I'm getting a 'failed to connect to server' error when I go to test1.example.com in this manner.
A few things to note:
Both test1.example.com and test2.test.com point to the same nginx server.
If both upstream/server blocks are working then test1.example.com shows the site is ssl secure. That is expected. But test2.test.com shows the website is insecure. This leads me to believe that only the first server/upstream block is working as expected. And the 2nd server/upstream block is being ignored.
actually does make sense, in that a server shouldn't be listening for incoming connections to the same port, and route to different servers. The proxy doesn't know what to do with 1 of the connections (bad explanation on my part).
But that doesn't explain why the 2nd server/upstream block would outright fail. Even when test2.example.com is the only server/upstream block configured.
Any advice is appreciate, thank you for your time and consideration. This is something I've been struggling to understand and make heads/tails of.
bossrhino

I think you need to use server_name directive. Because your web server listens on same ip and the same port for two subdomains.
I guess this config file should work properly:
upstream test1.example.com {
server flaskapp.example.com:5000
}
server {
listen 443 ssl;
server_name test1.example.com;
proxy_pass test1.example.com;
ssl_certificate /opt/certs/example1.com.crt;
ssl_certificate_key /opt/example1.com.key;
ssl_protocols TLSv1.2;
ssl ciphers "ECDHE-ECDSA-AES128-GCM-SHA256"
}
upstream test2.example.com {
server flaskapp.example.com:5000
}
server {
listen 443 ssl;
server_name test2.example.com;
proxy_pass test2.test.com;
ssl_certificate /opt/certs/test.com.crt;
ssl_certificate_key /opt/test.com.key;
ssl_protocols TLSv1.2;
ssl ciphers "ECDHE-ECDSA-AES128-GCM-SHA256"
}

Related

Nginx changes url to backend url

i have 2 backend servers listening on 80 and 443 ports:
a.example.com
b.example.com
when i get http://a.example.com at 80 port, backend internal nginx redirect it to 443 port: https://a.example.com, but when i get https port it is not redirect it, opening normally. I have not permissions to change backend nginx configurations.
So, and i have 1 load balancer nginx server, witch route requests to upstreams (backends):
upstream backends {
server 172.20.1.2:443; #a.example.com
server 172.20.2.2:443; #b.example.com
}
server {
listen 80;
server_name a.example.com;
location / {
proxy_pass https://backends;
proxy_set_header HOST a.example.com;
}
}
when i get response from second backend (b.example.com) my URL in browser is changes to https://b.example.com, but i requested https://a.example.com
Q: How i can get always https://a.example.com url from both backends? For example, when a.example.com backend not responding, lb request to second backend (b.example.com), but response url must be a.example.com
Thx!
for routing of https(443) url you need to listen on 443 in nginx also. Eg.
server {
listen 443 ssl;
server_name a.example.com;
ssl_certificate a.example.com.crt;
ssl_certificate_key a.example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass https://backends;
proxy_set_header HOST a.example.com;
}
}
and for dynamic routing to any upstreams try this :
upstream backends {
least_conn;
server 172.20.1.2:443; #a.example.com
server 172.20.2.2:443; #b.example.com
}
Hope this will works for you.
Helpful Links :-
https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/

Bind SSL certificate to a port number -- Nginx

Sorry for the limited understanding of Nginx and SSL. I have a React and Django app deployed on a server running on Nginx.
The React app is accessible using "example.org"(name is faked for demo purpose) and for the Django app, I have configured it to be accessible with port 3000 ie "example.org:3000".
The domain has SSL certificates installed and certificates are seen in "example.org" but while accessing "example.org:3000", the certificates are not available to this port.
I have been trying to allow ssl certificates to the port as well but couldnt succeed. I changed nginx conf file with listen 3000 ssl without success.
Please help, is there a way or should we need to modify the ssl certificates?
Nginx config at the moment is:
server {
listen 80 default_server;
server_name example.org;
return 301 https://example.org;
}
server {
listen 443 ssl;
server_name example.org;
ssl_certificate /etc/nginx/ssl/ssl_bundle.crt;
ssl_certificate_key /etc/nginx/ssl/example.key;
location / {
root /home/ubuntu/example/build;
index index.html index.htm;
}
}
The Port has nothing to do with the certs OR TLS Termination in general. IN case my assumptions are correct and your Django app is exposing its port 3000 by itself you need a proxy configuration that terminates the TLS for you.
server {
listen 8080 ssl;
server_name example.org;
ssl_certificate /etc/nginx/ssl/ssl_bundle.crt;
ssl_certificate_key /etc/nginx/ssl/example.key;
location / {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host $host;
.....
}
}
This will terminate the TLS Session for you on Port 8080 and forwards the traffic to your Django app. There are other, more advanced options, proxying traffic to your appserver but this one will do it.
Note: In case you want to proxy the traffic through NGINX make sure Port 3000 is not exposed to the public anymore.

SSL certificate returned for multiple server blocks

I have an nginx configuration with multiple virtual hosts and subdomains. Each subdomain needs to have a different SSL certificate bound. Here is the configuration for my first subdomain:
server {
listen 443;
server_name a.website.com;
ssl on;
ssl_certificate /etc/nginx/ssl/a/a.crt;
ssl_certificate_key /etc/nginx/ssl/a/a.rsa;
.....
The configuration for my second:
server {
listen 443;
listen 3443;
server_name b.website.com;
ssl on;
ssl_certificate /etc/nginx/ssl/b/b.crt;
ssl_certificate_key /etc/nginx/ssl/b/b.key;
....
The problem is if I go to b.website.com, the SSL certificate for both a.website.com and b.website.com are returned when I expect only b.website.com to be bound. I validated this using ssllabs.
Any advice?
I didn't notice that in ssllabs the second certificate was only returned if SNI wasn't enabled which makes sense because both certs are on the same IP. Apparently the integration we're working with doesn't support SNI (crazy I know) so I guess I have to spin up another server.

Redirect https to http without causing client errors

I have developed an app which talks to a server over https.
I recently discovered that my certificate has expired, and now the app refuses to talk to the server.
NSURLConnection/CFURLConnection (kCFStreamErrorDomainSSL, -9814)
How can I do a quick fix so that my app will work (insecurely), until I can renew my certificate?
I tried the following, but the app still protests (as does browsers).
server {
ssl on;
ssl_certificate ssl/server.crt;
ssl_certificate_key ssl/server.key;
listen 443;
rewrite ^ http://$http_host$uri permanent; # temporary workaround
}
It is fundamentally impossible.
TLS handshake and all checks are done before any request will be sent. This is what "security" is about.
convert the ssl server to normal server and create a new ssl server that redirects all requests
server {
listen 443;
server_name whatever.com www.whatever.com;
return 301 http://$http_host$request_uri;
}
server {
listen 80;
server_name whatever.com www.whatever.com;
# old configurations from the ssl server
}

how not to ssl terminate at NginX load balacner

I want to know how to have NginX (load balancer) accept traffic on 443 and forward it to port 443 on the load balanced web server nodes.
I am using NginX as a load balancer where the SSL termination occurs at NginX level. And then NginX sends unencrypted traffic to my web serves at port 80.
This is my current ngnx configuration:
upstream appserver {
server 10.0.1.132;
server 10.0.1.243;
}
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/nginx/cert.pem;
ssl_certificate_key /etc/nginx/cert.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://appserver;
}
}
I have gone through: Nginx load balance with upstream SSL
My real issue is, If I want NginX to listen traffic on 443, then I need to configure the ssl termination on nignx. Else nginx service won't start and will complain about missing ssl cert/keys.
In short, I want Nginx to simply accept traffic on 443 and forward it to 443 on load balanced Web server nodes. Then let my webservers do the SSL work.
The best practice is to do SSL offloading at load balancer level but I want to do otherwise.
Thanks.
This requires Layer 4 snooping/routing on NGINX's part, which is apparently not entirely supported. NGINX seems to support SNI, but for some reason I could not prevent it from terminating the TLS connection.
I ended up using HAProxy.
For this you need to use stream instead of http.
It is possible but this requires an extra module namely ngx_stream_ssl_preread_module it is available as of Nginx 1.11.5
It allows access to the SNI from which you can extract server name found in the client's ClientHello message via the $ssl_preread_server_name variable based on that you can route a TCP ("stream") connection to another enpoint. The downside is that you can only rely on the hostname for routing.
The documentation for the module provides an example of how to do that.

Resources