NGINX TLS Time To First Byte

Ilya Grigorik on optimizing NGINX TLS time to first byte (TTTFB):

let’s now turn to the practical matter of picking and tuning the server to deliver the best results. One would hope that the default “out of the box” experience for most servers would do a good job… unfortunately, that is not the case. Let’s take a closer look nginx

In the simplest terms, TLS involves more work. The current realities of securing communications means we don’t have a good way to avoid doing that additional work, indeed we will be doing it more often than we ever have before. The end result is that we need to spend more time thinking about how to optimize the HTTPS experience for all users.

Listen for SSL and SSH on the Same Port

Many corporate firewalls will limit outgoing connections to ports 80 and 443 in a vain effort to restrict access to non-web services. You could run SSH on port 80 or 443 on a VPS or dedicated server, but if you have one of those you are probably already using it to host a small web site. Wouldn’t it be nice if your server could listen for both SSH and HTTP/S on port 80 and 443? That is where sslh comes in:

sslh accepts connections on specified ports, and forwards them further based on tests performed on the first data packet sent by the remote client.

Probes for HTTP, SSL, SSH, OpenVPN, tinc, XMPP are implemented, and any other protocol that can be tested using a regular expression, can be recognised. A typical use case is to allow serving several services on port 443 (e.g. to connect to ssh from inside a corporate firewall, which almost never block port 443) while still serving HTTPS on that port.

Hence sslh acts as a protocol demultiplexer, or a switchboard. Its name comes from its original function to serve SSH and HTTPS on the same port.

Source code is available at

For small uses cases this may come in handy. If you were constantly needing to SSH to port 80 or 443 then I’d recommend just spending a few dollars a month to get a VPS dedicated to that task.

If you are stuck in a limited corporate network another tool you may find useful is corkscrew, which tunnels SSH connections through HTTP proxies.

Google APIs and SSL

Google has announced the move for several of their APIs to require SSL when making requests. This is a good thing.

If you aren’t planning on it already, now is a good time to expect new APIs to require SSL from the start. This is likely going to make TLS Server Name Indication an even bigger deal, as demand for SSL services increases and IP addresses become more expensive.

Nginx, Redirect non-SSL Requests

Since I managed to do this incorrectly a couple of times I figured it was worth noting here.

You already have a working site setup in Nginx that uses SSL. Now you want to make sure that any non-SSL requests to the site get redirected. Turns out to be very simple:

server {
  listen 80;
  rewrite ^(.*) https://$server_name$1 permanent;

This sends back an HTTP/1.1 301 Moved Permanently response for non-SSL requests for

Three short and easy to read lines, I like it.

HTTP Basic Authentication, A Tale of AtomPub, WordPress, PHP, Apache, CGI and SSL/TLS

I’ve been really enjoying working with Tim Bray, Pete Lacey, Elias Torres and Sam Ruby on improving AtomPub in WordPress. This work is in WordPress 2.3, which will be released later this month. You can try it out right now by downloading the beta. Sam has also started some documentation on AtomPub in WordPress at

There is a lot of ground to cover in the post so to start with I want to distinguish between two topics that are closely related, but for our purposes today are also separate and distinct from each other. The first is authentication, specifically HTTP Basic Authentication. The second is security, which will focus on SSL/TLS (i.e. using https:// URLs).

To start with, the AtomPub spec has a section on Securing the Atom Publishing Protocol that deals with authentication. In general, you can use nothing or what ever you want, but HTTP Basic Authentication with TLS needs to be able to work. Think of it as HTTP Basic Authentication being the lowest common denominator that AtomPub clients and servers have to support, along with TLS if you’d like.

In WordPress there are actually two ways that a user could be authenticated when using AtomPub, HTTP basic and cookies. The cookie mechanism just looks to see if you sent along an authenticated WordPress cookie with your request. Since we’d been using Tim’s Atom Protocol Exerciser (APE) for testing, all authentication was being done via HTTP basic. Which worked fine, most of the time.

I started running APE against WordPress running under different situations and I ran into a problem with authentication when PHP was being run as a CGI under Apache. When running as a server module (mod_php) PHP takes care of decoding HTTP basic for you (see HTTP basic authentication in PHP). When a using HTTP basic PHP will automatically populate $_SERVER[‘PHP_AUTH_USER’] and $_SERVER[‘PHP_AUTH_PW’] variables with the username and password that were provided. IF and ONLY IF PHP is being run as a server module (like mod_php). If you are running PHP as a CGI then those two variables won’t get created at all, ever, even when using HTTP basic authentication. And since you can’t do anything in WordPress via AtomPub without authenticating you are dead in the water. Well, not exactly.

PHP not supporting HTTP basic auth when being run as a CGI is a known issue, so folks have come up with clever work ways to work around this. One common work around is to use mod_rewrite to add HTTP basic auth into $_SERVER[‘HTTP_AUTHORIZATION’]:

RewriteEngine on
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]

The idea here is that mod_rewrite watches for an HTTP basic auth attempt and then injects the HTTP header in to the PHP environment as HTTP_AUTHORIZATION. From there is it an easy job of parsing and decoding the HTTP header and manually populating $_SERVER[‘PHP_AUTH_USER’] and $_SERVER[‘PHP_AUTH_PW’] yourself. This is currently being done in the WordPress AtomPub code, so if you are on a host that runs PHP as a CGI and you have access to .htaccess and mod_rewrite then you can try it out.

Unfortunately I’ve seen times where this doesn’t work either. A modified version of this that I’ve had better success with is to pass the authentication back in via GET. Here’s an example from a test WordPress blog that redirects AtomPub authentication:

RewriteEngine on
RewriteBase /test/atompub/
RewriteCond %{HTTP:Authorization}  !^$
RewriteRule wp-app.php wp-app.php?HTTP_AUTHORIZATION=%{HTTP:Authorization} [QSA,L]

Instead of parsing and decoding from $_SERVER[‘HTTP_AUTHORIZATION’] you would do it from $_GET[‘HTTP_AUTHORIZATION’]. This isn’t exactly ideal either, but I’ve had better luck getting it to work in PHP as a CGI environments. Code to support this isn’t in WordPress AtomPub yet, but we might add it.

The four of us went back and forth on this a bit then Tim Bray asked the elephant in the room question: why doesn’t PHP support HTTP basic when running as a CGI? I didn’t have a good answer for him, so I went hunting on Google. It turns out that this has nothing to do with PHP, it is how Apache works. Apache does not pass the HTTP basic headers to CGI applications, so they never see them. This has been mentioned in several places, for brevity I’ll only quote one, from Jon Udell talking about CGI and mod_perl:

HTTP Authentication

“Note that such a module has complete access to the HTTP headers sent by the client. If you write a CGI script to enforce a security policy, à la the ByteCal example above, that script will normally see only the user’s name (HTTP_REMOTE_USER) and not the full credentials (HTTP_AUTHORIZATION).

That’s because Apache, as a security measure, withholds the Authorization header from CGI scripts. (If you really want to build a CGI-based access-control script, you can tweak Apache to make it send this header.) But an Apache/Perl authentication module, running inside the server, knows everything that Apache knows about a request.”

So far I’ve used WordPress and AtomPub as an example, but this problem is not specific to either. This is an issue with CGI applications being able to use HTTP basic authentication, and the ways people have worked around it. While there are ways to deal with this (like the two I mentioned above), they aren’t ideal and only work if you can use .htaccess and mod_rewrite.

There have been lots of alternatives to authentication that get around this issue. Lots of people have looked at this, hopefully we’ll have a generalized way of dealing with this at some point. Until then it looks like we’ll see API specific variations of authentication.

Ok, I also mentioned that we’d talk about security. This one is more to the point, if you aren’t using SSL/TLS then your communications aren’t secure. Although HTTP basic doesn’t send your plain text password and username, it is the next best thing (base64 encoded). So anyone with access to your traffic (wireless network sniffing anyone?) can easily grab your username and password. So how do you secure this authentication process? By doing it over SSL/TLS. If your web traffic isn’t using SSL/TLS it isn’t secure.

In the context of WordPress there is a trade off here. We can’t guarantee that every WordPress install is going to support SSL/TLS, so we can’t make it a requirement. That said, there is nothing in WordPress (or the APIs: AtomPub and XML-RPC) that prevent you being able to use SSL/TLS. This leaves it up the person running the WordPress blog to decide what level of security is needed.

On we support TLS/SSL. You can point your XML-RPC client at https://<your_blog_here> and it will encrypt the data back and forth between your computer and servers. Same for AtomPub, only the URL would look like https://<your_blog_here>

Hopefully everyone takes away two things from this. One, you can’t depend on HTTP basic authentication working. Two, if you aren’t using SSL/TLS then your traffic isn’t secure.