Force https for all server blocks in https context - docker

I'm trying nginx for first time, and I do it with docker.
Basically I want to achieve the following architecture
https://example.com (business webiste`)
https://app.example.com (progressive web / single page app)
https://app.example.com/api (to avoid preflight requests, a proxy to https://api.example.com is needed)
https://api.example.com (restful api)
Every http request to be redirected to https
I'm generating the /etc/nginx/conf.d/default.conf file with some environment variables on start up. That file is then included inside the http context of the default.conf file, thus bringing some limitation to what I can configure. (related issue)
You can see my current nginx.conf file here (file is quite large to embed here).
And you can see the docker-compose.yml file here.
The problem:
400 Bad Request The plain HTTP request was sent to HTTPS port
I can't actually make that any call to http://(app/api).example.com to be redirected to its https version, I've tried with this without success: (see the the above linked file)
server {
listen 80 ssl;
listen 443 ssl;
listen [::]:80 ssl;
listen [::]:443 ssl;
server_name api.dev.local;
if ($http_x_forwarded_proto = "http") {
return 301 https://$server_name$request_uri;
}
# more code...
}
Any recommendations regarding to the my actual configs are more than welcome in the comments sections! I'm just starting to use nginx and thus reading tons of artciles that provide code snippets that I simply copy and paste after reading what are they needed for.

The https protocol is an extension to http, so they are different protocols to an extent. At the moment your server does not expect http on :80, it rather expects https due to the setting listen 80 ssl. This causes the error.
You need to separate handling of http requests on :80, which should be redirected to https on :443, from handling https on :443, which should be handled normally.
This can be done by splitting out another server configuration block for http on :80:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
...and removing listening on :80 from the current block:
server {
listen 443 ssl;
listen [::]:443 ssl;
# more code...
}
The following blog article gives more details if needed https://bjornjohansen.no/redirect-to-https-with-nginx

Related

Serving LetsEncrypt HTTP challenge when all http traffic is redirected to https

I want to perform the http validation for LetsEncrypt, which requires http only (port 80). I have a Rails Application running nginx, and has all traffic redirected to HTTPS via the following configuration:
server {
listen 80;
listen [::]:80;
return 301 https://$host$request_uri;
}
my two questions:
Is there a dynamic way (such as an API) to add the file path to my nginx file to serve the challenge file?
Is it possible to serve this challenge file when all traffic is being redirected to https?

nginx: http to https not working on chrome

I've got this nginx configuration to redirect http to https:
# http redirects to https
server {
listen 80 default_server;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
...
}
It works properly on firefox. If I add in /etc/hosts entry like:
127.0.0.1 my-custom-domain.com to make sure I have domain that was never used, in firefox if I enter my-custom-domain.com, I get this:
Works as expected, it redirects to https.
But if I do the same on chrome, I get this:
Chrome only opens https one if I explicitly enter https://my-custom-domain.com.. Not sure why it behaves differently on chrome.
P.S. I read some people say that server_name must not be _ and have specific name, but it works the same even if I enter sever_name my-custom-domain.com;
P.S.S I'm using 1.23.0-alpine nginx docker image.
Update
It looks like this issue is related with nginx docker image. I was not able to reproduce this with nginx installed locally. Though nginx images with tags nginx:1.18.0, nginx:1.23.0, nginx:1.23.0-alpine all had same issue.

NTLM Kerberos support for Identity server which set behind nginx server (not working for IE)

I have Identity server 4 which reside behind ngnix proxy. and it support Azure AD. now if I SSO on https then it is not working for IE browser but work properly in other browser due to IWA/NTLM/Kerberos .
So change need to do in ngnix to support that.
we have default setting in nginx like this :
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
Then I have removed http2
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
so IE has issue with SSL + http2

How to force exact match of subdomains with NGINX?

I am using Nginx as a reverse proxy. It is running as a containerized service in a Swarm cluster.
A while ago I discovered this weird behavior and I'm trying to wrap my head around it.
On my host I have three subdomains set up:
one.domain.com
two.domain.com
three.domain.com
In my Nginx server config I am specifying that the server_name I am targeting is three.domain.com, so I am expecting Nginx to only respond to requests targeting that subdomain.
events { worker_connections 1024; }
http {
upstream service {
server node:3000;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name three.domain.com;
[...... ssl settings here.......]
location / {
proxy_pass http://service;
proxy_set_header Host $host;
}
}
}
What happens instead of only responding to requests sent to three.domain.com, it responds to one.domain.com and two.domain.com as well. (it routes them to three.domain.com)
If I add multiple server blocks specifically targeting subdomains one and two, it works as expected, it routes the requests where they belong.
That being said, the ideal behavior would be to only respond to subdomains which are listed in the server_name section of a server block.
Nginx tests the request’s header field “Host” (or SNI hostname in case of https) to determine which server the request should be routed to. If its value does not match any server name, or the request does not contain this header field at all, then nginx will route the request to the default server for this port. In your configuration above, the default server is the first (and only) one — which is nginx’s standard default behaviour. If there are multiple server blocks, it can also be set explicitly which server should be default, with the default_server parameter in the listen directive
So, you need to add another server block:
server {
listen 443 ssl default_server;
server_name default.example.net;
...
return 444;
}

ssl certificate or nginx proxy server not working

I have created a domain(domain.com) and subdomain (abc.domain.com), and also generated SSL certificates for both by using letsencrypt. Both the Django projects are hosted on AWS EC2 and created proxy server for them which is as follow:
server {
listen 443 ssl;
server_name example.com;
location / {
proxy_pass https://1.2.3.4:444;
proxy_ssl_server_name on;
proxy_ssl_verify on;
proxy_ssl_certificate /home/domain/fullchain.pem;
proxy_ssl_certificate_key /home/domain/privkey.pem;
}
}
server {
listen 443 ssl;
server_name abc.example.com;
location / {
proxy_pass https://1.2.3.4:445;
proxy_ssl_server_name on;
proxy_ssl_verify on;
proxy_ssl_certificate /home/subdomain/fullchain.pem;
proxy_ssl_certificate_key /home/subdomain/privkey.pem;
}
}
I strats the proxy server and both the projects, starting not giving any problem the problem is that when i enter https://example.com on the browser it is not showing the page, but when i pull domain with port no. https://example.com:444, it starts showing the page. I do not know what I am missing.
In order to make https://example.com work you need to correctly configure Nginx with SSL configuration which include using ssl_certificate and ssl_certificate_key directives as it does not seem that you are using them.
Using proxy_ssl_certificate is for using HTTPS connection between Nginx and the Proxied Server which in your case the django application.
Using ssl_certificate is for using HTTPS connection between the user's browser and Nginx which you need to make https://example.com works as expected
For more details check configuring HTTPS servers

Resources