How to enable h2c in Nginx? - nginx

Is there a way to enable h2c aka HTTP2 cleartext in Nginx 1.9.5 onward?
I've tried using h2 over TLs in https://chronic101.xyz and it works, however I would like to implement h2c on port 80 as well.
Thanks,
chrone

It should be as simple as adding http2 in the end of your listen directive.
Example:
server {
listen 80 http2;
However, keep in mind that most browsers do not support unencrypted HTTP/2, and so will still serve content as HTTP/1.1.

Related

How to use SNI correctly? (Two Different Nginx SNI Writing Style)

What's the difference between these two different SNI writing styles? Could someone judge their differences from principle, performance, and so on?
Style1
stream{
map $ssl_preread_server_name $backend_name{
A.example.com A;
B.example.com B;
}
upsteam A{
server 127.0.0.1:10086
}
upsteam B{
server 127.0.0.1:10087
}
}
http{
server{
listen 10086 ssl http2;
server_name A.example.com
...
}
}
Style2
server {
listen 127.0.0.1:443 ssl;
server_name A.example.com;
...
}
server {
listen 127.0.0.1:443 ssl;
server_name B.example.com;
...
}
It seems from the question that you're trying to listen on 443 port for different hostnames. Requests coming with hostname A.example.com should get forwarded to 127.0.0.1:10086 while with hostname B.example.com would go to 127.0.0.1:10087. Let me explain what's happening behind the scenes in both styles.
Style 1
stream block lets you load balance over TCP/UDP. The ngx_stream_ssl_preread_module module lets you extract information from the request without ssl/tls termination. You're using map so connections coming as A.exammple.com set A in the variable $backend_name while those coming as B.example.com set B in the variable $backend_name. Based upon your upstream blocks the requests either get forwarded to 127.0.0.1:10086 or 127.0.0.1:10087. Since there is an http block with server blocks listening on port 10086 and 10087 respectively, it creates a new connection every time fulfilling those requests. The ssl termination is also happening inside the http block.
Style 2
Both server block are listening over 443 and depending on the hostname of the request it either goes through one of the server blocks. The ssl termination is happening before the request goes to ports where the application is actually running.
Both styles are good to achieve this but personally I'd prefer Style 2 as the ssl termination is handled before the forwarding of the requests. Additionally, in Style 1 there's an extra connection created which is a slight performance overhead, in my opinion.

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

How to config Nginx Only Support HTTP2 for No ALPN Clients

Here is the situation:
Our client wants to back support some old ios mac systems, which the network lib it used does not support ALPN. Our Server is set up only to accept gRPC requests, so there is no need for the server to accept HTTP1.1 requests.
So how do I disable Nginx to accept HTTP1.1 request and only enable HTTP2 support and skip the ALPN?
I tried to make Nginx defaults to support http2 but it still involves the ALPN process.
it seems nginx is do http2 based on ALPN so there is no walkaround for that.
Our customer request http2 only service because other product they use are using gRPC with envoy proxy. Envoy seems to have the ability to provide http2 only service without alpn, but it is subject to find out why ( as the document does not specify it clearly)

nginx server use HTTP/2 protocol version by default?

I have various nginx server and recently I note that by default response these servers responses using the HTTP/2 version of protocol.
I don't have configured the http2 parameter in nginx.conf.
Is this the right behavior?
No, that is not the default.
If you observe HTTP2 despite not configuring it in NGINX, you likely have a CDN in front of it, e.g. Cloudflare.

How to use server_name in Nginx under HTTP/2?

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.

Resources