< Back to blog
Maryna YanulJavaScript Developer

KeenEthics Experience-Sharing: From Meteor App to HTTP/2

http/2

Did you hear about HTTP/2? What do you know about its benefits?

I do not want to quote Wikipedia or RFC, so I will just say that it is a powerful turbocharger for a website, which increases loading speed. And who does not want their website to load fast?

To setup HTTP/2 on a website, you would need:

  1. Nginx  –  fast and useful web server that has HTTP/2 support;

  2. Letsencrypt to generate TSL certificate that is required for HTTP/2.

So, let’s start.

Install Nginx

Nginx supports HTTP/2 starting with 1.9.5, but some distributions have older versions in official repositories. To install newer version, you can visit Nginx website and select method that works best for you.

If you are using Ubuntu 14.04, you can install nginx from official ppa:

add-apt-repository ppa:nginx/stable apt-get update apt-get install nginx

Install Letsencrypt and Generate Certificate

Clone Letsencrypt repo as a first step.

git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt

Then make a temporary Nginx configuration for getting a certificate.

server { listen 80; listen [::]:80 ipv6only=on; server_name example.com; # your domain root /usr/share/nginx/html; location ~ /.well-known { # needed for Letsencrypt allow all; } }

Letsencrypt will place files in .well-known folder to check your owning of domain, so you have to allow the service to get those files. To apply any changes in Nginx configurations, you will need to restart it:

nginx -s reload

Then you can generate certificates.

/opt/letsecrypt/letsencrypt-auto certonly -a webroot --webroot-path=/usr/share/nginx/html -d example.com

You probably understood that you have to replace example.com with your domain. You can specify more than one domain/subdomain by adding additional -d arguments:

/opt/letsecrypt/letsencrypt-auto certonly -a webroot --webroot-path=/usr/share/nginx/html -d example.com -d www.example.com

This command will create folder in /etc/letsencrypt/ , which will contain certificate fullchain.pem and private key privkey.pem.

Redeploy Meteor Application

If your application is using port 80, you have to change it by changing value of PORT enviroment variable. For example, I used mup and changed it in env section of mup.json.

Setup Nginx

This is an example of nginx server configuration. HTTP server just redirects user to HTTPS, that has HTTP/2 support. Value of ssl_ciphers property, is very important since it is optimal for many browsers.

server { listen 80; listen [::]:80 ipv6only=on; server_name example.com; # your domain return 301 https://$host$request_uri; # just redirect to https } server { listen 443 ssl http2; #enable HTTP2 server_name example.com; root /usr/share/nginx/html; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:8000$request_uri; } ssl_session_timeout 1h; ssl_session_cache shared:SSL:16m; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.4.4 8.8.8.8 valid=300s; resolver_timeout 10s; ssl_protocols TLSv1 TLSv1.1 TLSv1.2;ssl_ciphers ‘ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:!RC4:!aNULL:!eNULL:!MD5:!EXPORT:!EXP:!LOW:!SEED:!CAMELLIA:!IDEA:!PSK:!SRP:!SSLv:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA’; ssl_prefer_server_ciphers on; }

Value of proxy_pass must be address of your meteor application plus $request_uri.

Restart Nginx again to apply last changes.

nginx -s reload

If you do not get any errors ,  congratulations, your website just got HTTP/2 support.

Static Content

Now, nginx is proxying all the requests to our meteor application. But there is one more thing to improve. Meteor is not that good in serving static content (compiled scripts and styles, images and fonts), and we could improve website performance even more by using nginx for it!

To do it we must setup special locations in nginx.conf before root location:

location ~ ^/(images|fonts)/.*(png|jpg|svg|jpeg|ttf|otf|woff|woff2|eot)$ { root /opt/yoursitedir/app/programs/web.browser/app; access_log off; expires max; } location ~ \.(css|js|json|html|ttf|otf|woff|woff2|eot)$ { root /opt/yoursitedir/app/programs/web.browser; access_log off; expires max; }

In builded meteor application, we have compiled JS and CSS in web.browser/ folder; fonts and other public data now are in web.browser/app. You can disable access log for static data and set maximum expires time for cache of these.

Websockets

By default, nginx does not proxy websockets. But you can change it by adding manually some headers to request of proxy:

location / { proxy_pass http://127.0.0.1:8000$request_uri; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; }

Results

Our site’s download time has decreased from 411ms to 123ms for primary content (main html, js, and css) and from 7s to 5s for secondary content added by JavaScript. This result may be improved if the server-side rendering is used.

Do you have an idea?

Let's schedule an intro call and discuss your business idea!