Louis-Philippe Véronneau - apachehttps://veronneau.org/2018-12-22T00:00:00-05:00A Tale of HTTP/22018-12-22T00:00:00-05:002018-12-22T00:00:00-05:00Louis-Philippe Véronneautag:veronneau.org,2018-12-22:/a-tale-of-http2.html<p>Around a month ago, someone mentioned the existence of <a href="https://en.wikipedia.org/wiki/HTTP/2">HTTP/2</a> in an IRC
channel I lurk in. For some reason, I had never heard of it and some of the
features of this new protocol (like mutiplexing requests without having to open
multiple TCP connections) seemed cool.</p>
<p>To be …</p><p>Around a month ago, someone mentioned the existence of <a href="https://en.wikipedia.org/wiki/HTTP/2">HTTP/2</a> in an IRC
channel I lurk in. For some reason, I had never heard of it and some of the
features of this new protocol (like mutiplexing requests without having to open
multiple TCP connections) seemed cool.</p>
<p>To be honest, I had just finished re-writing the Puppet code that manages our
backup procedures and enabling HTTP/2 seemed like a productive way to
procrastinate before moving on to an another large project. How hard could this
be?</p>
<p>Turns out it took me around 25 hours of work... Sit back and put on comfortable
slippers, for this is a tale of HTTP/2!</p>
<p><a href="https://commons.wikimedia.org/wiki/File:The_Yule_Log.jpg"><img src="/media/blog/2018-12-22/yule_log.jpg" title="The Yule Log" alt="The Yule Log" height="80%" width="80%" style="margin-left: 10%;"></a></p>
<h2>Cursed Be the HTTP/1.1</h2>
<p>When I first looked up how to enable HTTP/2 on Apache it seemed a pretty simple
task. The documentation mentioned loading the <code>http2</code> module and making sure to
prioritise the new protocol via a configuration file like this one:</p>
<div class="highlight"><pre><span></span><code><span class="nb">Protocols</span><span class="w"> </span>h2<span class="w"> </span>h2c<span class="w"> </span>http/1.1
<span class="nb">H2Push</span><span class="w"> </span><span class="k">on</span>
<span class="nb">H2PushPriority</span><span class="w"> </span>*<span class="w"> </span>after
<span class="nb">H2PushPriority</span><span class="w"> </span>text/css<span class="w"> </span>before
<span class="nb">H2PushPriority</span><span class="w"> </span>image/jpeg<span class="w"> </span>after<span class="w"> </span><span class="m">32</span>
<span class="nb">H2PushPriority</span><span class="w"> </span>image/png<span class="w"> </span>after<span class="w"> </span><span class="m">32</span>
<span class="nb">H2PushPriority</span><span class="w"> </span>application/javascript<span class="w"> </span>interleaved
</code></pre></div>
<p>This would of course have been too easy. Even if everything in Apache was set up
properly, websites kept being served as HTTP/1.1. I was obviously doing
something right though, since my websites were now sending a new HTTP header:
<code>Upgrade: h2, h2c</code>.</p>
<p>After wasting a good deal of time debugging TLS ciphers (HTTP/2 is <a href="https://http2.github.io/http2-spec/#TLSUsage">incompatible
with TLS 1.1</a>), I finally found out the problem was that we weren't
using the right multi-processing module for Apache.</p>
<p>Turns out Apache won't let you serve HTTP/2 while using <code>mpm_prefork</code> (the
default MPM), as it is not supported by <code>mod_http2</code>. Even though there are
two other MPM you can use with Apache, only <code>mpm_prefork</code> supports <code>mod_php</code>.
Suddenly, adding support for HTTP/2 meant switching all our webapps built in
PHP to PHP-FPM...</p>
<h2>Down the Rabbit Hole</h2>
<p><img src="/media/blog/2018-12-22/mod_php.gif" title="A clip from Alice in Wonderlands" alt="A clip from Alice in Wonderlands" height="30%" width="30%" style="float:right;"></p>
<p>For the longest time, a close friend has been trying to convince me of the
virtues of <a href="https://wiki.apache.org/httpd/PHP-FPM">PHP-FPM</a>. As great as it looked on paper, I never really
did anything about it. It seemed so ... complicated. Regular ol' <code>mod_php</code> did
the trick just fine and other things required my attention.</p>
<p>This whole HTTP/2 thing turned out to be the perfect excuse for me to dive into
it after all. Once I understood how FPM pools worked, it was actually
pretty easy to set up. Since I had to rewrite the Puppet profiles we're using to
deploy websites, also I took that opportunity to harden a bunch of things left
and right.</p>
<p>PHP-FPM let's you run websites under different Unix users for added separation.
On top of that, I decided it was time for PHP code on our servers to be ran in
read-only mode and had to tweak a bunch of things for our Wordpress, Nextcloud,
KanBoard and Drupal instances to stop complaining about it.</p>
<p>After too much time passed automating tasks in Puppet, I finally was able to
turn off <code>mod_php</code> and <code>mpm_prefork</code> everywhere and to enable <code>mpm_event</code> and
<code>mod_http2</code>. The speed bonus offered by PHP-FPM and HTTP/2 is nice, but more
than anything I'm happy this whole ordeal forced me to harden the way our
Apache servers deal with PHP.</p>
<p><img src="/media/blog/2018-12-22/victory.png" title="Victory!" alt="Victory!" height="80%" width="80%" style="margin-left: 10%;"></p>