Phusion white papers Phusion overview

Use Nginx + SPDY, without compiling Nginx and without a recent OpenSSL

By Hongli Lai on August 21st, 2013

google-spdy

We use the SPDY network protocol extensively to improve the performance of our websites. SPDY — pronounced “speedy” — is a new-ish protocol from Google with the goal of reducing latency, improving throughput and improving pipelining. Many articles have been written about the advantages of SPDY. We have observed 20%-30% better loading time on www.phusionpassenger.com by switching from plain HTTP to SPDY, mostly because of the better pipelining that SPDY offers over plain HTTP.

SPDY is built on top of TLS. Nginx has supported SPDY through external patches for a while. Since version 1.4.0, Nginx has SPDY support builtin, with two caveats:

  1. SPDY support must be enabled by compiling Nginx with --with-http_spdy_module.
  2. It requires OpenSSL 1.0.1+, because SPDY requires the Next Protocol Negotiation TLS extension.

Many users prefer to use the Nginx binary provided by their distribution. But not all of the currently widely used distributions provide OpenSSL 1.0.1, and of those that do, very few of them have Nginx with SPDY enabled.

We started providing prebuilt Nginx binaries since Phusion Passenger 4.0.13 (learn more at “No more compiling Phusion Passenger”). These Nginx binaries not only have Phusion Passenger support enabled, but also SPDY support! Furthermore, we’ve spent great effort on ensuring that these binaries are compatible with a wide range of Linux distributions, whether they’re running on x86 or x86_64. Best of all: you can use these Nginx binaries without Phusion Passenger, and as a drop-in replacement for your distribution’s Nginx binary! This means:

  • You install Nginx using your distribution’s preferred method (e.g. apt-get install nginx).
  • You overwrite the Nginx binary with the one that we provide.
  • You get to keep all the nice things that your distribution package offers, such as init scripts, conf.d directories, etc.
  • No compilation is necessary.

Getting started on Debian or Ubuntu

This guide is taylored for Debian and Ubuntu. The instructions may also work on other distributions, but the paths may be different, and the init script format may also be different. You can use this guide as a starting point for figuring out how to achieve the same for your specific distribution.

Install Nginx using apt:

sudo apt-get install nginx

Next, download our Nginx binary. There are multiple versions of Nginx and of Phusion Passenger. You can find all available versions at the Phusion download server, indexed by Phusion Passenger version. At the time of writing, Nginx 1.4.2 and Phusion Passenger 4.0.13 are the most recent versions:

# 32-bit systems
curl -O https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.13/nginx-1.4.2-x86-linux.tar.gz
# 64-bit systems
curl -O https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.13/nginx-1.4.2-x86_64-linux.tar.gz

Extract the downloaded tarball:

tar xzvf nginx-*.tar.gz

Update April 9 2014: the tarball and the binary have been renamed. It’s called “webhelper” now. So if you want Nginx 1.4.7 from Phusion Passenger 4.0.41, run:

# 32-bit systems
curl -O https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.41/webhelper-1.4.2-x86-linux.tar.gz
# 64-bit systems
curl -O https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.41/webhelper-1.4.2-x86_64-linux.tar.gz

# Then rename the tarball and the binary:
tar xzvf webhelper-*.tar.gz
mv PassengerWebHelper nginx

The next steps are a little more complicated, although not difficult. The Nginx binary that we provide is compiled with the prefix /tmp. This is because Nginx requires several data directories (e.g. client_body_temp_path) to properly operate. Since our Nginx binary is designed to be portable, we can’t assume any specific directory structure, which is why we use the /tmp prefix.

Luckily, there is a way to tell the Nginx binary during runtime to a different directory structure, and that’s exactly what we’re going to do.

Overwrite the original Nginx binary and create a bunch of symlinks:

sudo cp nginx /usr/sbin/
sudo ln -s /etc/nginx /var/lib/nginx/conf
sudo ln -s /var/log/nginx /var/lib/nginx/logs

Then edit /etc/default/nginx and add:

DAEMON_OPTS="$DAEMON_OPTS -p /var/lib/nginx"

Next, edit /etc/nginx/nginx.conf, and set the following options:

pid /var/run/nginx.pid;
lock_file /var/lock/nginx.lock;

Finally, restart Nginx using your distribution’s Nginx init script:

sudo /etc/init.d/nginx restart

Testing SPDY

To test SPDY, you need an SSL certificate for your domain name. There are many cheap SSL certificate providers our there, which you can easily find through Google. Once you have an SSL certificate, create a virtual host entry:

sudo tee /etc/nginx/conf.d/spdy_test.conf <<EOF
server {
    listen 443 ssl spdy;
    server_name your_domain_name.com;
    ssl on;
    ssl_certificate /path-to-your-cert.crt;
    ssl_certificate_key /path-to-your-key.key;
    root /tmp/spdy_test;
}
EOF

Then create a web directory with a test document:

mkdir /tmp/spdy_test
echo it works > /tmp/spdy_test/index.html

Restart Nginx:

sudo /etc/init.d/nginx restart

Finally, use SPDYCheck to check your website at https://your_domain_name.com.

Distribution updates

Whenever the distribution has an update for Nginx, you must replace the Nginx binary after the distribution’s update tool has installed the update. For example, suppose that Ubuntu releases Nginx 1.4.3 tomorrow:

$ sudo apt-get upgrade
[some error messages will appear during restarting of Nginx]

apt-get upgrade will probably fail to restart Nginx, but this is normal! This is because you will probably have SPDY-specific configuration options, but the distribution’s Nginx doesn’t support that.

Ignore the error, and download the latest version of the Phusion Nginx binary from the Phusion download server:

curl -O https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/<SOME VERSION>/nginx-1.4.3-<SOME ARCHITECTURE>-linux.tar.gz

Next, extract the Nginx binary and overwrite the distribution’s binary:

tar xzvf nginx-*.tar.gz
sudo cp nginx /usr/sbin/

Finally, finalize the apt-get upgrade and restart Nginx:

sudo apt-get upgrade
sudo /etc/init.d/nginx restart

What about security?

Downloading random binaries from the Internet is very dangerous. If an attacker intercepts and modifies the communication channel, anything goes. To combat this problem, we’ve employed two security measures:

  • All our binaries are hosted on HTTPS.
  • All our binaries are signed with PGP. The PGP key is Phusion Automated Software Signing (software-signing@phusion.nl), fingerprint 1637 8A33 A6EF 1676 2922 526E 561F 9B9C AC40 B2F7.

Reinstalling Nginx if something goes wrong

If our binary doesn’t work for some reason, then reverting to the original Nginx binary is easy:

sudo apt-get remove nginx
sudo apt-get install nginx

Conclusion

Installing Nginx with SPDY support through our prebuilt binaries is quite easy and requires just a few config file changes. We’ve love to know whether it works well for you. Please leave feedback at the comment form below. Thank you for reading.

  • http://lightyearsoftware.com/ Steve Madsen

    There have been several recent announcements about changes to the Passenger installation process. SPDY support is the only reason I’ve been building my own Nginx. Is this custom binary integrated into the Passenger install process? If not, are there plans to automate it? Manual steps make me nervous. They’re exactly the things most likely to be forgotten or done wrong during an upgrade.

  • http://www.phusion.nl/ Hongli Lai

    Currently, this custom binary is used by Phusion Passenger Standalone. Although Phusion Passenger Standalone has no builtin support for SSL or SPDY, you can edit the Phusion Passenger Standalone Nginx config template (`passenger-config –root`/resources/templates/standalone/config.erb) and put SSL/SPDY directives there.

    The installer for Phusion Passenger for Nginx (passenger-install-nginx-module) does currently not use our custom binaries, although we’re working on that.

  • http://www.manybots.com/ Niko Roberts

    Has anything changed since this blog post?

  • http://www.phusion.nl/ Hongli Lai

    Passenger Standalone now has builtin support for SSL but not (yet) SPDY.

  • Andy Wenk

    Thanks a lot for the tutorial. Are you planning to integrate spdy/3 ?

  • http://www.phusion.nl/ Hongli Lai

    That depends on Nginx.

  • Andreas Wenk

    Yesterday was day zero with the heartbleed bug. I tested various sites and found, that they were affected. So I upgraded openssl and tested again. Still affected. So I thought it’s the nginx binary. But there is no binary for the latest available version here: https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.41/

    Why is this? Do I miss sth?

    Thanks

    Andy

  • http://www.phusion.nl/ Hongli Lai

    The binary is called “webhelper” now.

  • Andreas Wenk

    Hongli – wow thanks for the quick reply. I downloaded it already but thought its wrong because of the name “PassengerWebHelper” (in the tar). So how to follow the process above then? Shall I rename it to nginx and put it into /usr/sbin/ ? Or do I have to place it somewhere else?

    Thanks again for the info.

  • http://www.phusion.nl/ Hongli Lai

    Yes. Just rename it to Nginx.

  • Andreas Wenk

    thanks a lot – works like a charm!

  • http://www.manybots.com/ Niko Roberts

    When I try to update swap out the nginx binaries I get

    nginx: [emerg] open() “/tmp/conf/nginx.conf” failed (2: No such file or directory)

    Before, nginx was loading fine, after doing the cp PassengerWebHelper to /usr/sbin/nginx this starts happening.

    My fix was to make a symlink to the nginx.conf but having that in /tmp/conf/ doesn’t seem make a lot of sense… Your instructions in this post suggest this should be in /var/lib/nginx

    Also the IPv6 directive on the default nginx site config throws an error
    nginx: [emerg] the INET6 sockets are not supported on this platform in “[::]:80″ of the “listen” directive in /etc/nginx/sites-enabled/default:22