NGINX, ALPN and HTTP/2 on CentOS7
HTTP/2 ON CENTOS7 WITH NGINX
You’ve probably heard about the fancy new lightning fast HTTP/2 protocol, right? Fortunately, the latest versions of NGINX support HTTP/2. Unfortunately, most distributions are still stuck on OpenSSL < 1.0.2.
Versions of OpenSSL below 1.0.2 don’t support the new Application-Layer Protocol Negotition standard (ALPN) which means browsers must use Next Protocol Negotiation (NPN) to upgrade the connection to HTTP/2.
BUT WHAT DOES THIS MEAN? WHY DOES IT MATTER?
This matters because Google Chrome will fall back to HTTP/1.1 if ALPN is not supported. Since most Linux distributions don’t officially support a version of OpenSSL that implements ALPN that means something must be done to if we want to implement HTTP/2 properly.
The official NGINX Blog has a great entry about this exact topic which happens to be where I began this journey. They list which distros support ALPN (at the time of the writing) and which don’t. CentOS7 is in the don’t column.
Our options from here are switch to Ubuntu 16.x, use third party OpenSSL packages, or compile NGINX against a version of OpenSSL that implements ALPN. While compiling your own packages is a bit old school and generally frowned upon for security reasons (any update requires a recompile and that can become a chore) this particular case is pretty easy and low maintenance.
We can compile NGINX against a newer version of OpenSSL without updating the version the rest of the system uses. In fact, we don’t even have to compile openssl. However, please, for the love of all that is holy, make sure you keep your nginx up to date. Any security updates for nginx or openssl means you need to repeat this process with the updated versions.
If you decide to go this route please take security seriously, and keep your software up to date. After you’ve gone through this once updating shouldn’t take more than ten minutes. If you get lazy with security you will eventually regret it. If you aren’t comfortable doing this use a distro that can officially support ALPN.
Here we go.
COMPILING NGINX AGAINST OPENSSL 1.1.0C
I chose to use OpenSSL 1.1.0c because it’s the newest version. Make sure to get the most recent version of 1.1.0 or 1.0.2 depending on which version you decide to use. OpenSSL is updated frequently with security updates.
We also need to have the “Development Tools” group installed on our system.
# change dir to where we compile NGINX and OpenSSL cd /usr/local/src/ # install required packages sudo yum install wget pcre-devel sudo yum groupinstall "Development Tools" # download nginx and openssl sources sudo wget http://nginx.org/download/nginx-1.11.7.tar.gz sudo wget https://www.openssl.org/source/openssl-1.1.0c.tar.gz # extract nginx and openssl sources sudo tar xf nginx-1.11.7.tar.gz sudo tar xf openssl-1.1.0c.tar.gz # compile nginx cd nginx-1.11.7 sudo ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic' --with-openssl=/usr/local/src/openssl-1.1.0c/ sudo make sudo make install
We can verify that nginx is now compiled against openssl-1.1.0c by running the command
$ nginx -V nginx version: nginx/1.11.7 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) built with OpenSSL 1.1.0c 10 Nov 2016 TLS SNI support enabled
Now we need an init script. There is a sample script provided on nginx.com. Save this as
/etc/init.d/nginx and then make it executable. If you want nginx to start with the system you’ll need to enable it using systemctl also. Finally, you need to allow ports 80 (http) and 443 (https) through the system firewall.
# make /etc/init.d/nginx executable sudo chmod +x /etc/init.d/nginx # start nginx when the system boots sudo systemctl enable nginx # permanently allow http and https through firewall sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-service=https # start nginx now sudo systemctl start nginx