5209R: HTTP/2 via Nginx SSL Proxy

Posted by: mstauber Category: General

A new major update for BlueOnyx 5209R is ready for release and is currently in the 'BlueOnyx-Testing' YUM repository.

BlueOnyx 5209R - by default - uses the Apache webserver. This is the unmodified Apache 2.4.6 as provided by CentOS. It's compiled against OpenSSL 1.0.2k as provided by CentOS.

While it generally does a good job at serving webpages and allows us to use all the Apache related extras that are in high demand (such as .htaccess, mod_rewrite, suPHP, mod_ruid2 and others) it has some shortcomings when it comes to serving HTTPS pages.

The key problem is the age of the Apache itself and the combination of the older OpenSSL that it is compiled against. What's worse: RedHat deliberately has stripped down OpenSSL to remove certain encryption ciphers for "patent reasons". Other ciphers that we'd like to have (such as ChaCha or Poly1305) were only introduced in later OpenSSL versions.

In a nutshell this means that RedHat/CentOS are deprieving us of some "nice to have" ciphers and we're also not getting HTTP/2 support due to the old age of Apache and OpenSSL. HTTP/2 is a major revision of the HTTP network protocol and allows the server to supply data it knows a web browser will need to render a web page, without waiting for the browser to examine the first response. Thus HTTP/2 generally serves webpages much faster than HTTP/1.1. Which is why we would love to have it in BlueOnyx.

This is where Nginx enters.

Nginx as SSL-Proxy

Nginx ( /ˌɛnɪnˈɛks/ EN-jin-EKS) (stylized as NGINX, NGiИX or nginx) is a web server which can also be used as a reverse proxy, load balancer and HTTP cache. Nginx uses an asynchronous event-driven approach to handling requests. Nginx's modular event-driven architecture can provide more predictable performance under high loads.

Nginx and Apache follow different design philosophies. Wheras Apache is a Swiss Army knife that can do everything out of the box, Nginx is lean, mean and lightweight, but carries a heavy punch. Out of the box Nginx only serves static webpages and you have to manually configure in all the features you might want. But then it can do a hell of a lot pretty well.

However: We can't use Nginx as a straight Apache replacement without loosing some features. Which is why we took a different approach that doesn't take any features away, but uses Nginx to add features.

New features:

  • HTTP/2 support via TLS/SSL
  • HSTS on a per Vsite basis
  • OpenSSL-1.1.0h
  • All ciphers available that a stock OpenSSL-1.1.0h provides
  • Ability to customize protocols and ciphers yourself via single config file edit

How it works:

Once you have the updates installed which add this feature you will see that "Network Services" / "Web" now has two tabs. One for "Apache" and a new one for "Nginx".

This is where you can activate Nginx as SSL Proxy. When you do so, the GUI will modify the Apache config files to remove Apache's ability to bind to the SSL port ("443"). It will also configure Nginx as SSL-Proxy and will create Nginx config files for all Vsites that have SSL enabled.

Here is an example of how the directory structure of the Nginx config files looks:

/etc/nginx/
|-- conf
|   `-- 00-default.conf
|-- conf.d
|   `-- default.conf
|-- fastcgi_params
|-- headers.d
|   |-- https_headers.conf
|   `-- security.conf
|-- koi-utf
|-- koi-win
|-- mime.types
|-- modules -> ../../usr/lib64/nginx/modules
|-- nginx.conf
|-- scgi_params
|-- ssl_defaults.conf
|-- ssl_proto_chiffres.conf
|-- uwsgi_params
|-- vsites
|   |-- site1
|   |-- site2
|   `-- site5
`-- win-utf

As you can see /etc/nginx/vsites/ (in this example) now contains the config files to provide an SSL Proxy for "site1", "site2" and "site5". Which will look more or less like this:

# Do NOT edit this file. The GUI will replace this file on edits.
server {

    listen              [::]:443 ssl http2;
    listen              443 ssl http2;
    server_name         test.blueonyx.it;

    include /etc/nginx/headers.d/*.conf;

    ssl_certificate         /home/.sites/143/site2/certs/nginx_cert_ca_combined;
    ssl_certificate_key     /home/.sites/143/site2/certs/key;
    ssl_trusted_certificate /home/.sites/143/site2/certs/nginx_cert_ca_combined;

    # Insert external protocols and chiffres for SSL:
    include /etc/nginx/ssl_proto_chiffres.conf;

    # Insert external SSL Session cfg, resolver and OSCP-Stapling:
    include /etc/nginx/ssl_defaults.conf;

    error_page 502 /502-bad-gateway.html;
    location = /502-bad-gateway.html {
        internal;
        root  /var/www/html/error/;
    }

    # Special provisions for /libImage/ for error page gfx:
    location ~ ^/libImage/*.*$ {
        root   /usr/sausalito/ui/web/;
    }

    location / {
      proxy_http_version   1.1;
      proxy_set_header     Connection "";
      proxy_set_header     Host $host;
      proxy_set_header     X-Real-IP $remote_addr;
      proxy_set_header     X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header     X-Forwarded-Proto $scheme;
      proxy_pass           http://test.blueonyx.it:80/;
      proxy_read_timeout   90;
    }
}

As you can see: There is not much in it. No PHP-, Perl- or SSI-provisions, because this is nothing but a proxy. If a browser connects via HTTPS, Nginx will accept the connection securely and then makes a local connection to port 80 to fetch the web content from Apache. It then encrypts this (so far) unencrypted datastream and sends it securely to the browser. If the browser supports HTTP/2, then HTTP/2 will be used.

If you're a tinkerer and would like to play with the protocols and chiffres that Nginx uses, then please feel free to edit the file /etc/nginx/ssl_proto_chiffres.conf, which (by default) looks like this:

    ssl_protocols TLSv1.2;
    ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:AES256+EECDH:AES256+EDH:AES128+EECDH:AES128+EDH:!aNULL:!eNULL:!NULL:!EXPORT:!IDEA:!3DES:!DES:!MD5:!PSK:!RC4:@STRENGTH;
    ssl_prefer_server_ciphers on;

Neither the GUI nor future updates will overwrite this config file if you make any edits to it. Once you edit it, a simple "systemctl restart nginx" will activate your changes and all Vsites (with SSL enabled) will use the new settings.

HSTS Support on a per Vsite basis:

HSTS is a method with which we can tell browsers that our website(s) should preferably be visited via HTTPS and not HTTP. The browser then takes note of that and (for a configurable period of time) will always try to use HTTPS - for future visits as well.

Apache supports HSTS, but in a brutish fashion: It's either on for ALL Vsites, or off for all Vsites. As our users often host a mixed batch of Vsites with and without SSL they mostly cannot use HSTS. Not even for the few Vsites where they actually might want it.

Enter Nginx: With Nginx it is now possible to selectively turn on HSTS for individual Vsites - or the whole server. The choice is yours. If Nginx is used as SSL proxy, then under "SSL" of each Vsite you find a new chebox called "Nginx HSTS" as shown below:

However: This implementation has a catch.

Recall we're still using Apache for HTTP? And (if enabled) Nginx is only used for HTTPS? If you have a Vsite where you selectively enable Nginx's HSTS support and a visitor only ever visits your page via HTTP, then he will never see the HSTS header. HSTS will then only kick in if the visitor loads at least one resource (webpage, script or image) via HTTPS.

So as a work around (if you plan to use HSTS selectively) you should make sure that your webpage loads at least one resource via HTTPS. This can be an image that's used in the webpage template or a stylesheet. That would then be sufficient to make sure HSTS kicks in for all visitors.

More complications, more troubleshooting?

Now you might say: "Great! Another service that I have to watch out for!" This is only partially true. The GUI will take care of it. There is nothing in Nginx that you need to mess with. There are no config files to edit (unless you want to!) and we're just doing really simple proxying. ActiveMonitor will watch Nginx closely when the service is enabled:

Should it really ever fail, you can simply restart Nginx like you restart any other service: "systemctl restart nginx". Should something be wrong, it'll then tell you on the command line. And - if need be - you can simply untick the checkbox in the GUI and can revert back to let Apache serve HTTPS again.

If you're wondering how Nginx as a HTTPS proxy holds up in practice? We're using it on this very domain. The load time for resource hungry pages has drastically dropped and the server load (even at peak times) didn't go up in a noticeable fashion. All in all HTTP/2 feels significantly faster.


Return
General
Apr 15, 2018 Category: General Posted by: mstauber
Previous page: API Documentation Next page: Downloads