For now more and more servers are starting using HTTP/2 which is faster and more secure.
This post is about how to enable HTTP/2 on FreeBSD servers.
Nginx Stable 1.8.* doesn’t support HTTP/2. So we need to install nginx-devel (version 1.9.*) first. If you have already installed Nginx stable, you need to uninstall it first.
And before you install nginx-devel, you need to install openssl from port first. Otherwise nginx will use system based openssl library, and you can’t enable ALPN for http/2. That’s because ALPN requires openssl 1.0.2*, and the system based openssl is version 0.98
So the first step is:
cd /usr/ports/security/openssl make install
And then add below line into your make.conf to make sure that you’ll use the latest openssl library to build nginx.
cd /usr/ports/security/openssl WITH_OpeNSSL_PORTS=yes
Then you can install nginx-devel
cd /usr/ports/www/nginx-devel make config
Make sure that you select HTTP_SSL and HTTPV2. Please be aware that SPDY is no longer supported by nginx 1.9.*.
Then install it.
make install
Go back to your nginx.conf, and modify it as following:
server { listen 443 accept_filter=dataready ssl http2; ssl on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_certificate /usr/local/etc/nginx/yourcert.crt; ssl_certificate_key /usr/local/etc/nginx/yourcert.key; ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:50m; ssl_session_timeout 1d; ssl_session_tickets on; ssl_stapling on; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 10s; ssl_trusted_certificate /usr/local/etc/nginx/ca-certs.crt; ssl_stapling_verify on; add_header Strict-Transport-Security "max-age=15552000; includeSubdomains; preload"; .... }
I’d like to explain a little bit for this configuration.
listen 443 accept_filter=dataready ssl http2;
This is about to enable HTTP/2 and SSL.
You may notice that here I’m using accept_filter=dataready instead of accept_filter=httpready. There are currently two filters in FreeBSD: “dataready” and “httpready” which need to started at boot by adding accf_data_load=”YES” and accf_http_load=”YES” to /boot/loader.conf. dataready waits for the first properly formed packet to arrive from the client before passing the request to nginx. httpready waits not only for the packets, but also for the end of the HTTP header before passing the request onto nginx. Keep in mind “httpready” filter breaks support for ancient HTTP/0.9 because v0.9 does not have any headers. HTTP/0.9 is so old we are not going to worry about support it and since a HTTP/0.9 would not have the newer SSL ciphers anyways.
To configure nginx to use the accept filters in FreeBSD we need to add the arguments to the listen directive. Since http (port 80) is unencrypted we can use the “accept_filter=httpready” accept filter. This is because FreeBSD will need to look at the packet and parse the complete http header. SSL (https port 443) is encrypted so FreeBSD can not parse the packets so we need to use the “accept_filter=dataready” accept filter. Both accept filter examples can be found in the configuration below. To use FreeBSD accept filters you must enable them in /boot/loader.conf to load on boot.
And someone may use the nginx 1.9.* new feature reuseport. I have to say, unfortunately, this new feature doesn’t support FreeBSD. I made several test on my server, it seems if you enable “reuseport” on your server, then all your traffic will be handled by your first worker! The OS can’t balance the workers’ workload. It means if your server is very busy, with reuseport on FreeBSD will significantly slow down your server. You’ll find that your first worker is taking up 100% CPU and the rest are idle! So, at this moment, do not enable “reuseport” on FreeBSD Nginx.
ssl on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_certificate /usr/local/etc/nginx/yourcert.crt; ssl_certificate_key /usr/local/etc/nginx/yourcert.key;
This part is just enable SSL. It’s pretty easy. There is only one thing you need to take care, that is for yourcert.crt, there is no need to put Root certificate into it. Just put your server certificate and intermediate certificate into it to reduce the size of your certificate to reduce the connection time.
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on;
These SSL ciphers are recommended by cloudflare. It can support most browsers. But IE6 is not supported.
ssl_session_cache shared:SSL:5m; ssl_session_timeout 180m; ssl_session_tickets on;
NGINX caches the session parameters used to create the SSL/TLS connection. This cache, shared among all workers when you include the shared parameter, drastically improves response time for subsequent requests because the connection setup information is already known. Assign a name to the cache and set its size (a 1-MB shared cache accommodates approximately 4,000 sessions).The ssl_session_timeout directive controls how long the session information remains in the cache. The default value is 5 minutes; increasing it to several hours (as in the following example) improves performance but requires a larger cache. Session tickets store information about specific SSL/TLS sessions. When a client resumes interaction with an application, the session ticket is used to resume the session without renegotiation. Session IDs are an alternative; an MD5 hash is used to map to a specific session stored in the cache created by the ssl_session_cache directive.
ssl_stapling on; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 10s; ssl_trusted_certificate /usr/local/etc/nginx/ca-certs.crt; ssl_stapling_verify on;
OCSP stapling, can decreases the time of the SSL/TLS handshake. Traditionally, when a user connects to your application or website via HTTPS, his or her browser validates the SSL certificate against a certificate revocation list (CRL) or uses an Online Certificate Status Protocol (OCSP) record from a certificate authority (CA). These requests add latency and the CAs can be unreliable. With NGINX you can cache the OCSP response to your server and eliminate costly overhead.
At this step you need to create your ssl_trusted_certificate. Please note that for OCSP certificate (ssl_trusted_certificate /usr/local/etc/nginx/ca-certs.crt), you need to put your root certificate and intermediate certificate into it, and no server certificate. And the right order is root certificate first, then intermediate certificate, then second intermediate certificate.
add_header Strict-Transport-Security "max-age=15552000; includeSubdomains; preload";
Enable HSTS for your server. Please be aware that if you added this into your configure, then you can’t remove it and go back to http again. Otherwise end users can’t access your website because they will always redirect to https site.
Now, you can go to http://www.ssllabs.com to test your website. You should be able to get score A+
Truly useful info and really strong techy article, first of all, many thanks for your time!
Got a question here, you’ve stated “And someone may use the nginx 1.9.* new feature reuseport. I have to say, unfortunately, this new feature doesn’t support FreeBSD”, while the article is written in 2016, it’s 2020 and I have FreeBSD 12.1 around here together with nginx 1.19.3, (got worker_processes set to 12 in nginx.conf) is it STILL the same fact that all the traffic will be handled by the first worker, in such use? I thought that might prolly be changed recent years.. Maybe.
Thank you!