How to use server_name in Nginx under HTTP/2? - nginx

I want to use 2 server blocks.
The first is:
server {
listen 443 ssl http2 fastopen=3 reuseport;
server_name a.example.xyz;
include server_safe.conf;
root /home/www/blog/;
}
The second is:
server {
listen 443 ssl http2;
server_name b.example.xyz;
include server_safe.conf;
}
What I want:
I want the server_name to be valid, that is , if I use a c.example.xyz to visit my website, both a.example.xyz,b.example.xyz,c.example.xyz is the same IP , the server should block the c.example.xyz request because it is not in the server_name.
However, if I enter https://c.example.xyz, the Nginx will still receive the request and reponse as a.example.xyz
I know HTTP/2 has no host in its header, it has a :authority instead.
My question is that : How can I reject any other request? I only want to accept the request under(with) the host(:authority) = a(b).example.xyz

The problem is the first Server block is used by default if no other name matches.
Therefore to achieve what you want, you need to create a default block, before the other two, and have it block or redirect, or show an error page.
The downsides of this are:
Unless you have HTTPS certificates that all the domain names (or use a wildcard cert that covers this), then they will get an error when going to https version of your site and use this default config. Though this would happen under your current set up anyway. There is no way AFAIK to send a block message before the HTTPS negotiation happens.
Older clients that don't support SNI (primarily Windows XP) will go to default config, whereas previously they would have gotten through for Server A as it was the default (though not for server B).
The alternative is to write a redirect rule based on the hostname provided. Not 100% sure how to do this on nginx to be honest but if not possible by default then is possible with ModSecurity. Again it will only take effect after the HTTPS negotiation has happened so still leaves you with a potential incorrect cert problem.

Related

Is it possible to redirect HTTPS to HTTPS with nginx?

I have the following issue.
I created this danish website flaatinfo.dk that is also accessible by flåtinfo.dk.
The domain manager gave me a certificate for flaatinfo.dk but said that they could not generate one for flåtinfo.dk because it contains a special character.
Is there a way (in nginx setup) that I can redirect all HTTPS requests from flåtinfo.dk to flaatinfo.dk??
HTTP redirects seem to work fine but if I try to redirect HTTPS like this I get cert error in browser:
server {
listen 443 ssl;
server_name flåtinfo.dk www.flåtinfo.dk;
return 301 https://flaatinfo.dk$request_uri;
}
www.flåtinfo.dk is an internationalized domain name (IDN).
According to NGINX documentation for internationalized names:
domain names (IDNs) should be specified using an ASCII (Punycode)
representation in the server_name directive
So you should specify it in NGINX configuration as xn--fltinfo-fxa.dk.
As for why your plain HTTP redirect worked anyway, it's probably because it didn't match any other domain so NGINX had to eventually choose it as default.
I get cert error in browser
Naturally, since you don't have a TLS certificate for your IDN, browsers will issue warnings. You need to get a TLS certificate for IDN to get rid of the warning. Let's Encrypt supports issuing certs for IDNs and is free of charge.

Nginx server block that serves http2 without other http and without https

I am trying to host a website that only allow user to enter the website http://website.com:1234 using direct http2, and do not allow any users to enter via http0.9, http1.0, http1.1 or upgrade from either one of them. Additionally, I do not want my website to be able to serve https.
I have tried to configure using:
server {
listen 1234 ssl http2
listen [::]:1234 ssl http2
etc
etc
}
as well as
server {
listen 1234 http2
listen [::]:1234 http2
etc
etc
}
It does not work like how I wanted to, could anyone be able to help me?
Sorry but this is not technically possible.
No browsers currently support http2 without encryption and unencrypted http2 connections require an upgrade from http 1.1 according to the spec
See here and here for more info

Nginx uWSGI link server_name to domain for flask application

I have written a Flask website which I hosted with waitress on a Ubuntu 20.04 VM server at port 5000, but now I'd like to do it more properly with uWSGI/Nginx.
To learn uWSGI/Nginx I am following this tutorial: https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-uwsgi-and-nginx-on-ubuntu-20-04
Here in step 6 it tells my to configure Nginx as follows:
server {
listen 80;
server_name my_domain www.my_domain;
location / {
include uwsgi_params;
uwsgi_pass unix:/home/sammy/myproject/myproject.sock;
}
}
However if I now request the webpage for my domain, it only returns the default Nginx page.
But if I "hardcode" the public IP address of my server to the server_name:
server_name: my_domain www.my_domain MY_IP
Then it does show the correct page. I however have a feeling this is not the intended way to configure the server.
When I used the old waitress server i had told my DNS server redirect to http://MY_IP:5000/, but it is now set to redirect to http://MY_IP/. (with redirect mode 302)
So my question is, how should I set up my Domain name redirect or Nginx config so that it works without a "hardcoded" ip? Or is this something where I just need to wait the 48 hours for the DNS update to propagate?
Also an auxiliary related question, how do I make the browser url bar show the domain name instead of an IP address?
Thanks in advance!
You can go through my answer, hope it helps you as well
Regarding your question for URL name in browser, it will be there once DNS name is propagating properly and it shouldn't take more than 5-10 minutes.
Remove the IP from server name, its not supposed to be entered there.

Logging the request protocol in nginx?

I was surprised to find that I couldn't find any information on logging the request protocol in an nginx access log. I usually share a server block for both HTTP (80) and HTTPS (443) traffic, and use a combined access log for both. I'd like to indicate in each line in the access log if the request was over HTTP or HTTPS.
Is this possible, or do I need to use a separate server block for HTTPS and specify a separate access log for SSL?
It's a bit hidden in the docs, but you can use any of the common variables. This includes $scheme.
You can combine server blocks like:
server {
listen 80;
listen 443 default_server ssl;
# other directives
}
> nginx http/https config docs
For customizing the log file output you can use the "log_format" directive to define your own access log setup.
> nginx access_log docs

How to configure nginx for Amazon ec2

I saw example configurations of nginx, most of them use example.com as a server_name and uwsgi_pass similar to unix:/var/www/run/blog.sock; or in combination with ip/port address. but what should I use in case of amazon ec2 instance, since it has long public name, ip is private and if I restart my instance it gets different public name and ip. I need shutdown instances sometime. I want to configure it for using uwsgi+django, but I am totally beginner in web area and servers.
The server_name directive is useful in cases where you want to host different sites on the same server, and handling them differently depending on the "Host" header field (ex: mysite1.com => a PHP website, mysite2.com => a django website,...)
It's actually a virtual server (see also [the server directive])1.
From this article :
[...] nginx tests only the request’s header field
“Host” [against the server_name directive] 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.
If I understood, you don't want that. So you can use the underscore character (in the Miscellaneous Names section).
When I don't need to handle specific domains, I generally use "localhost". To be honest I couldn't find any explanation on what it does. I just found examples with this value, and it seems to work exactly as the underscore character.
So I'd go with
server_name _;
or
server_name localhost;

Resources