Nginx - Only enable SSL if SSL Certificates Exist - ssl

I have an issue wherein I am building an nginx reverse proxy for directing to multiple microservices at different url paths.
The system is entirely docker based and as a result the same environment is used for development and production. This has caused an issue for me when installing SSL as the SSL certs will only be available in production so when I configure NGINX with SSL the development environment no longer works as the ssl certs are not present.
Here is the relevant part of my conf file -
server {
listen 80;
listen 443 default_server ssl;
server_name atvcap.server.com;
ssl_certificate /etc/nginx/certs/atvcap_cabundle.crt;
ssl_certificate_key /etc/nginx/certs/atvcap.key;
...
}
But this throws the following when running my application in development mode -
nginx: [emerg] BIO_new_file("/etc/nginx/certs/atvcap_cabundle.crt") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/etc/nginx/certs/atvcap_cabundle.crt','r') error:2006D080:BIO routines:BIO_new_file:no such file)
Is it possible to only turn on SSL if the "/etc/nginx/certs/atvcap_cabundle.crt" is available?
I had tried something like the following -
if (-f /etc/nginx/certs/atvcap_cabundle.crt) {
ssl_certificate /etc/nginx/certs/atvcap_cabundle.crt;
ssl_certificate_key /etc/nginx/certs/atvcap.key;
}
But that threw the following error -
nginx: [emerg] "ssl_certificate" directive is not allowed here in
/etc/nginx/conf.d/default.conf:7
Any one have any ideas on how to achieve something like this?
Thanks

You can create an additional file ssl.conf and put here ssl configs:
ssl_certificate /etc/nginx/certs/atvcap_cabundle.crt;
ssl_certificate_key /etc/nginx/certs/atvcap.key;
Then include from the main config:
server_name atvcap.server.com;
include /somepath/ssl.conf*;
Make sure to include * symbol - this will not break when the file does not exist at development mode.

The answer of #super_p is correct. But to answer to #AbdolHosein comment I add my answer here if it's not clear.
You need to include your ssl_certificate directive in the included file.
# sample nginx config
http {
server {
listen 80 deferred;
server_name _;
include /ssl/ssl.conf*;
client_body_timeout 5s;
client_header_timeout 5s;
root /code;
}
}
Then in your /ssl/ssl.conf you can do whatever you want, such as enabling HTTPS:
# this is the /ssl/ssl.conf file
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /ssl/cert.cer;
ssl_certificate_key /ssl/key.key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
The trick is that we don't look if the certificate exists but we check if the /ssl/ssl.conf exists. This is thanks to the * in the include /ssl/ssl.conf*; directory as stated by #super_p

Related

Configuring nginx with ssl certificate

I'm having trouble configuring ssl with nginx; I followed the instructions here step by step (without step 4) but it didn't work and i got error 524 from cloudflare.
This is my configuration file for nginx located in /etc/nginx/sites-enabled/project
server {
listen 443;
server_name <domainname>.org;
ssl on;
ssl_certificate /etc/nginx/ssl/<domainname>_org/ssl-bundle.crt;
ssl_certificate_key /etc/nginx/ssl/<domainname>_org/<domainname>_org.key;
ssl_prefer_server_ciphers on;
location /static {
alias <path/to/static>;
}
location / {
proxy_pass <python/listener>;
include /etc/nginx/proxy_params;
proxy_redirect off;
}
}
Note that if i changed the configuration to:
server {
listen 80;
server_name <domainname>.org;
...
}
then I can reach the server normally with http and every thing will be working fine.
Note
I already opened the port in the firewall so that's not the problem and nginx is listening on port 443 when i check using netstat.

How to install a letsencrypt cert with nginx?

I've used letsencrypt to install an SSL cert for the latest nginx on ubuntu.
The setup is fine and works great with the exception of:
I don't know enough about SSL to know what's going on but I have a suspicion:
I installed the SSL cert for Apache a while back and just now moved to Nginx for it's http/2 support. As the nginx plugin is not stable yet I had to install the cert myself and this is what I did:
In my nginx config (/etc/nginx/conf/default.conf) I added:
server {
listen 80;
server_name [domain];
return 301 https://$host$request_uri;
}
server {
listen 443 http2;
listen [::]:443 http2;
server_name [domain];
ssl on;
ssl_certificate /etc/letsencrypt/live/[domain]/cert.pem;
ssl_certificate_key /etc/letsencrypt/live/[domain]/privkey.pem;
}
Is it possible that this breaks the chain somehow? What is the proper way here?
Thanks guys
1) For strong Diffie-Hellman and avoid Logjam attacks see this great manual.
You need extend your nginx config with these directives (after you will generate dhparams.pem file):
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/ssl/dhparams.pem;
2) For correct certificate chain use fullchain.pem, not cert.pem, see this great tutorial for details.
And you will get A grade :)
3) and as bonus try this great service:
"Generate Mozilla Security Recommended Web Server Configuration Files".

SSL configuration on nginx 1.6

I'm tryng to configure nginx 1.6 on a VM to accept https connection.
I have created a self signed certificate following this tutorial. and then I have added a configuration file like this
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
The problem is that when I access the https url from the browser I have no results but this error
Error code: ERR_CONNECTION_RESET
I think that port 443 is open
netstat -tulpn | grep 443
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 8603/nginx.conf
Moreover, I can wget the index.html:
wget -–no-check-certificate https://<server_url>
Now, I suppose that the problem is the untrusted certificate because wget gives error if -–no-check-certificate is omitted but in this case I expect browser (Chrome or Firefox) to give some kind of warning and maybe let me see the untrusted certificate instead of reset connection.
What am I doing wrong? Thanks in advance
EDIT:
Firefox gives "200 Connection Established" but no content or warning is shown. It only says that connection has been canceled
The problem might be with the certificate. You can see tutorial to create *.pem certificate instead of *.crt and add as:
ssl_certificate /etc/nginx/ssl/nginx.pem;
Issue was on my side renamed my.host.com to localhost and it worked.
server_name localhost;

Installing SSL in nginx problems

So I'm having trouble getting my ssl cert working properly in a rails app with nginx. Do I need to use the sites-available folder, or can I just stick all my cert info in the /opt/nginx/conf/nginx.conf file? Currently, my nginx.conf file looks like this, but when I try to access the site using https it doesn't work. Before this, I have another server block that listens on port 80, and that works for http, but this one for https doesn't work. Any ideas?
server {
listen 443;
server_name www.mysite.com;
#localhost;
ssl on;
ssl_certificate reference to my pem file
ssl_certificate_key reference to my key file
root reference to app in /var/www
# ssl on;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_timeout 5m;
# ssl_protocols SSLv2 SSLv3 TLSv1;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
}
I spent a lot of time today setting up SSL on nginx. First thing I would suggest checking is that port 443 is open from something like www.checkmyports.net
Also, do you get an error when you restart nginx?

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.