Using EFF’s CertBot with Apache 2.2 and CentOS 6

EFF has created a wonderful tool called CertBot to automate the retrieval and installation of letsencrypt certificates. The documentation is really good but it did require a little trial and error to get things working. Here’s a walkthrough with some of the gotcha’s I encountered.

Why do I need CertBot?

Letsencrypt certificates are only valid for 90 days. The verification and update process is a tedious process to complete manually. CertBot automates the retrieval and renewing certificates, it has a built-in webserver which can stand-in during the verification step, and it can modify your web server config and install the certificates if you happen to be using nginx or apache 2.4

Install:

Before you start, you should apply all software updates for your OS and restart. One of the updates overwrote a config file I customized which made the web server fail to start.

I was using CentOS 6 which doesn’t have a built-in package of CertBot. EFF also provides a version which can install its own dependencies called “CertBot Auto”.

Here’s how to install that:

[email protected]:~$ wget https://dl.eff.org/certbot-auto
[email protected]:~$ chmod a=rx ./certbot-auto
[email protected]:~$ ./certbot-auto --help

I’d also recommend moving “certbot-auto” into “/usr/local/bin” so it’s available to other users or cron scripts.

[email protected]:~$ mv ./certbot-auto /usr/local/bin/certbot

Usage:

The docs are great. Have a look. https://certbot.eff.org/docs/using.html

My site redirects all traffic to https which breaks the verification process which needs to happen over http. The “standalone” mode solves this. It requires that you stop the web server and cert-bot will then answer on port 80 to complete the registration process. The CLI also defines pre-update and post-update “hooks” which can be used to stop and start your web server automatically to minimise down time.

For my domain this looked something like:

[email protected]:~$ certbot certonly --standalone -d www.your.site --pre-hook "service httpd stop" --post-hook "service httpd start"

If you’re setup includes both http and https, you can use apache to serve the verification files.

sudo certbot-auto certonly --webroot -w /var/www/vhosts/default/html -d www.your.site -d your.site

You can include up to 10 domains on each certificate.

Where does your certificate get stored?

Good question. On CentOS, certbot creates a /etc/letsencrypt folder. Each certificate you generate will have a folder in the “live” folder. The commands above created a /etc/letsencrypt/live/www.your.site with your certificates files.

Here’s what you’ll need to add to your httpd.conf or virtual host to use this new certificate.

#Using letsencrypt certificates.
SSLCertificateFile /etc/letsencrypt/live/www.your.site/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.your.site/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/www.your.site/chain.pem

Renewal

The last thing to setup is cron task to automate renewal of our certificate(s).
“certbot renew -n” attempts to renew any certificates expiring in less than 30 days. The -n makes it non-interactive which is ideal cron task.
And that’s it. You’re all setup to take advantage of a letsencrypt certificate with centos and apache 2.2.
It was much easier than I though and after a lot of poking through the documentation I was able to piece together what needed to be done. Hopefully this saves you a few hours and a couple of server alerts.

Just one more thing. Ever heard of CCA?

One more wrinkle here is CCA checking. These freely available certificates mean that it’s not that hard to create a certificate which appears valid for a popular website. CCA checking adds a DNS record which informs certbot and other clients which authorities are allowed to register certificates for a given domain. All letsencrypt CAs will require this step after Sept. 2017. Because this requires a new DNS record type, not every host or registry is ready for this. I’m using namescheap for my .site address and it’s currently unsupported. Check with your domain registrar or whoever is providing your DNS service if they support CCA records. You might have to choose a new DNS provider if your registrar doesn’t if you want to continue using letsencrypt certificates.

Vagrant + Apache Defaults = Corrupted Files

Problem: You just started using vagrant as a development environment and now your getting errors in your javascript files like 'Illegal Character' appended to the file you just edited.
Restoring the edited file from git fixes the error.

Solution: Your problably being hosed by the 'EnableSendfile' directive.
Disable it by adding "EnableSendfile Off" to your apache config file.

Sendfile allows apache to send data from a file without doing a seperate read and send operation. It however doesn't work well with NFS shares.
While I'm not sure how the shared folder in vagrant works, it appears to be impacted by this setting. Here are the apache 2.2 docs for this module.

Thanks to the folks of the virtualbox forums for discussing this issue and possible solutions and preventing me from wasting another day on this issue.

Open Webalizer DNS cache with PHP

Problem:

Webalizer produces a cache file for DNS to speed up the process for resolving addresses to names but no utilities exist to browse this kind of file.

Background:

Webalizer is a log file analyser which can provide basic site usage stats by processing your apache log files. Its a standard utility in a RHEL envirnment. One feature of it is caching DNS information to speed up resolving addresses for reporting purposes. It uses a Berkeley DB to store these key/value pairs for quick lookup. Unfortunatly there really arn’t an gui tools for getting a look at this data. On my machine, its a 70MB file and I’d really like to get a look at that data.

So there are a couple of ways to do this.
MySQL comes with a bdb storage engine which can read this kind of file.

Or, you could use PHP and its driver to load this information.
I chose the latter.

Environment:
I’m starting with a base install of ubuntu 11 and zend server.
Using zend server makes the process more complicated but makes the process more standardized.  ZS uses the same paths for files on every OS it installs on.

Install dependent software.

Zend doesn’t come with this module by default, so we’ll need to compile it.
Make sure you’ve got the basics needed to compile under ubuntu installed.


aptitude install install build-essential checkinstall autoconf

Next we need to make sure that libdb4 is installed so we can reference it in php.

aptitude install libdb4.8-dev db4.8-util db4.8-doc libdb4.8

And finaly, we need the header files for zend server’s php.

sudo aptitude install php-5.3-source-zend-server

Sanity check – Lets make sure that the module isn’t installed.


php --ri dba
Extension 'dba' not present.

Great. Lets build it.


cd /usr/local/zend/share/php-source/php-5.3.9/ext/dba/
/usr/local/zend/bin/phpize
./configure --with-php-config=/usr/local/zend/bin/php-config --with-db4
make
make install
echo "extension=dba.so" > /usr/local/zend/etc/conf.d/dba.ini

lets check that again


php --ri dba
dba

DBA support => enabled
Supported handlers => gdbm cdb cdb_make db4 inifile flatfile

Directive => Local Value => Master Value
dba.default_handler => flatfile => flatfile

Done. We can now access the dba functions from the command line.
They’ll also get picked up by apache the next time you restart.

Build a quick script to read the dns cache and output it as a comma separated list.


<?php
/**
* Requires the dba module be enabled with db4 support.
*/
$path = dirname(__FILE__) . '/dns_cache.db';
$logPath = $path . '.txt';
echo 'Loading ' . $path . chr(10);

$row = 0;
$h = dba_open($path,'r','db4');
$fh = fopen($logPath,'w+');

if(!$h){
echo 'Failed to open db';
die();
}

echo "Exporting Key/Values pairs...\n";
$key = dba_firstkey($h);
$value = dba_fetch($key,$h);
$value = filter_var($value,FILTER_SANITIZE_URL);
$key = filter_var($key,FILTER_SANITIZE_URL);
fwrite($fh, "$key,$value\n");
$row++;

while($key = dba_nextkey($h)){
$value = dba_fetch($key,$h);
$value = filter_var($value,FILTER_SANITIZE_URL);
$key = filter_var($key,FILTER_SANITIZE_URL);
fwrite($fh, "$key,$value\n");
$row++;
}
echo "Printed $row key/value pairs." . chr(10);
echo 'Done' . chr(10);
dba_close($h);

I called my script test.php.
Then run it from the command line.


php -r ./test.php

Loading /home/{MASKED}/dns_cache.db
Exporting Key/Values pairs...
Printed 703268 key/value pairs.
Done

Not sure if this is the best way to get at this data but its the route I chose and it worked.
Your mileage may vary.

Serving Office 2007 documents to IE Users with Apache

If the file your serving doesn’t have a matching mime type, then you get nothing.

I encountered an issue downloading Office 2007 documents with IE. When downloaded IE would download them as ZIP files instead.

In reality, these are zip files. Our users need them to open in the correct application.

The solution was adding the new mime types to apache.
I was unaware that apache provides mime type info for each file served or that IE actually used that information.

Adding the following my apache config fixed the problem:

1
2
3
4
5
    #Types for the new office documents
    AddType application/vnd.openxmlformats-officedocument.wordprocessingml.document .docx
    AddType application/vnd.openxmlformats-officedocument.presentationml.presentation .pptx
    AddType application/vnd.openxmlformats-officedocument.spreadsheetml.sheet .xlsx
    AddType application/vnd.ms-xpsdocument .xps

References:
http://blogs.msdn.com/dmahugh/archive/2006/08/08/692600.aspx
http://httpd.apache.org/docs/2.2/mod/mod_mime.html#addtype