Possible bug http2 module

Hello,

I am running a WordPress multisite install and recently turned off http2
on the domain in order to use a third party module which evidently
doesn’t play nicely with http2 (echo module). In testing I noticed that
the site was still being served with http2 enabled according to both
Chrome and Firefox. I confirmed with curl.

I recompiled nginx without any third party modules:

nginx -V

nginx version: nginx/1.9.10
built with OpenSSL 1.0.2f 28 Jan 2016
TLS SNI support enabled
configure arguments: --prefix=/usr/local/etc/nginx --with-cc-opt=‘-I
/usr/local/include’ --with-ld-opt=‘-L /usr/local/lib’
–conf-path=/usr/local/etc/nginx/nginx.conf
–sbin-path=/usr/local/sbin/nginx --pid-path=/var/run/nginx.pid
–error-log-path=/var/log/nginx-error.log --user=www --group=www
–with-file-aio --with-ipv6
–http-client-body-temp-path=/var/tmp/nginx/client_body_temp
–http-fastcgi-temp-path=/var/tmp/nginx/fastcgi_temp
–http-proxy-temp-path=/var/tmp/nginx/proxy_temp
–http-scgi-temp-path=/var/tmp/nginx/scgi_temp
–http-uwsgi-temp-path=/var/tmp/nginx/uwsgi_temp
–http-log-path=/var/log/nginx-access.log --with-http_stub_status_module
–with-pcre --with-http_v2_module --with-http_ssl_module

I then adjusted the config files so as not to reference any third party
modules and performed a binary “upgrade”.

I still see that http2 is in use on both Chrome and Firefox, and also
via curl.

curl -I -k https://my.ip4.add.ress/

HTTP/2.0 302
server:nginx/1.9.10
date:Sat, 06 Feb 2016 16:49:44 GMT
content-type:text/html; charset=UTF-8

curl -I https:/mydomain.net/

HTTP/2.0 200
server:nginx/1.9.10
date:Sat, 06 Feb 2016 16:50:41 GMT
content-type:text/html; charset=UTF-8

There are other domains on that IPv4 which use http2. Disabling http2 on
all of them resulted in the expected behavior in the browsers and in
curl:

curl -I -k https:///my.ip4.add.ress/

HTTP/1.1 302 Moved Temporarily
Server: nginx/1.9.10
Date: Sat, 06 Feb 2016 17:03:39 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive

curl -I https://mydomain.net/

HTTP/1.1 200 OK
Server: nginx/1.9.10
Date: Sat, 06 Feb 2016 17:05:05 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive

I don’t see any reference to this at
Module ngx_http_v2_module so I am guessing
this is unintended.

Obvious workaround is to place this domain on an IPv4 in which there are
no http2 sites.

More permanent solution should be considered.


Jim O.

“Never argue with a fool, onlookers may not be able to tell the
difference.” - Mark Twain

On Saturday 06 February 2016 12:13:52 Jim O. wrote:

nginx -V

–http-fastcgi-temp-path=/var/tmp/nginx/fastcgi_temp
I still see that http2 is in use on both Chrome and Firefox, and also
server:nginx/1.9.10
Content-Type: text/html; charset=UTF-8
Module ngx_http_v2_module so I am guessing
this is unintended.

[…]

A quote from the documentation:

| The http2 parameter (1.9.5) configures the port to accept HTTP/2
| connections.

http://nginx.org/en/docs/http/ngx_http_core_module.html#listen

wbr, Valentin V. Bartenev

On 2/6/16 12:22 PM, Валентин Бартенев wrote:

–http-client-body-temp-path=/var/tmp/nginx/client_body_temp

HTTP/2.0 200
Date: Sat, 06 Feb 2016 17:03:39 GMT
I don’t see any reference to this at
Module ngx_http_core_module
Ahh. That’s not in the http2 module documentation, where I looked and
where it should perhaps also be mentioned, and it’s not clear that the
above applies to every server.

So if I write:

listen 443 ssl http2;

in a server directive anywhere as dosumneted in
Module ngx_http_v2_module, then
http2 is enabled in all servers on all IP’s even if it’s not
specifically enabled in a listen directive in a particular server? That
seems wrong, intuitively. There are (more and more) times when shared
IPv4’s are necessary, and dictating this behavior for all servers on a
given IPv4 is probably less than optimal. If it’s technically a
necessity it could perhaps be more explicitly documented.


Jim O.

“Never argue with a fool, onlookers may not be able to tell the
difference.” - Mark Twain

On Saturday 06 February 2016 12:44:08 Jim O. wrote:

I recompiled nginx without any third party modules:
–with-file-aio --with-ipv6
modules and performed a binary “upgrade”.

curl -I https:/mydomain.net/

HTTP/1.1 302 Moved Temporarily
Connection: keep-alive

in a server directive anywhere as dosumneted in
Module ngx_http_v2_module, then
http2 is enabled in all servers on all IP’s even if it’s not
specifically enabled in a listen directive in a particular server? That
seems wrong, intuitively. There are (more and more) times when shared
IPv4’s are necessary, and dictating this behavior for all servers on a
given IPv4 is probably less than optimal. If it’s technically a
necessity it could perhaps be more explicitly documented.

It’s pretty much the same as “ssl” parameter works.

Ones connected an HTTP/2 client is able to request any host over the
HTTP/2
connection, and in fact browsers do. So there’s no proper way to
disable
HTTP/2 for one virtual server while keeping enable for others.

Could you suggest a good phrase to improve the docs?

wbr, Valentin V. Bartenev

On 2/6/16 1:00 PM, Валентин Бартенев wrote:

[snip]

So if I write:

necessity it could perhaps be more explicitly documented.

It’s pretty much the same as “ssl” parameter works.

I thought of that but there’s a fundamental difference from the point of
view of the server admin. If I enable SSL on one or more vhosts sharing
an IP address and choose not to use SSL in another vhost sharing that
same IP, I simply do not write an ssl server configuration for that
vhost. There’s no certificate for it so pretty much any client will
throw an error if a request is made for that vhost on 443. The user then
can use http instead of https or s/he can choose to use an incorrect
certificate. Most choose the former. With the advent of free certificate
services like Letsencrypt, StartSSL and Wotan, I, like many server
admins, am shifting more and more to https (and http2). But as we’ve
seen, there are times when http2 cannot be used (or is undesirable) but
we still prefer SSL, or we’ve long ago enabled HSTS and pretty much can
no longer back out, at least not without significant disruption.

In my use case, the server in question is a FreeBSD KVM in a large Linux
machine that hosts many other KVM’s and LXC’s. Each of my customers
needs at least one IPv4 and most want more than one. The host will only
provide me with a finite number of IPv4 addresses per physical server.
If IPv6 were ubiquitous I would not have a problem as I have a /64 on
each machine. I try to limit my own use of IPv4’s so as to have them
available. With SNI that really isn’t a problem. I no longer worry
whether my sites support ancient clients, so I host many SSL domains on
the same IP. If I want to use http2 on all but one, and I cannot use
http2 on that one, then I cannot use http2 on any, as I have come to
find out.

Ones connected an HTTP/2 client is able to request any host over the HTTP/2
connection, and in fact browsers do. So there’s no proper way to disable
HTTP/2 for one virtual server while keeping enable for others.

The most elegant solution (if it’s possible - my programming skills
start and end with shell scripts) would be a programmatic one where a
directive is optionally turned on in the http context of the nginx
configuation file. Something like:

check_http2 (on|off);

with a default of “off”. Such a directive could check for explicit http2
enabling in a vhost where SSL is also enabled, and downgrade connections
to those where it is not enabled. Of course this would probably violate
half a dozen RFC’s, but it would be helpful in the use case I just
described, which is in fact a real world situation. A server admin who
does not want to spend the CPU cycles on such a check simply does not
enable it, but one who needs it can use it.

Could you suggest a good phrase to improve the docs?

Something like the following in the http2 and core module documentation:

NOTE: Enabling http2 globally (via “listen 443 ssl http2;” in ANY server
block), or on any single IP (via “listen 1.2.3.4:443 ssl http2;”),
enables http2 on ALL vhosts using SSL, either globally or on that
specific IP. If this is not the desired behavior use one IP for vhosts
using http2 and a different IP for vhosts using SSL but for which you do
not want to enable http2. Enable http2 only for the IP’s where it is
desired.


Jim O.

“Never argue with a fool, onlookers may not be able to tell the
difference.” - Mark Twain