Recent changes to this wiki:

Comment moderation
diff --git a/posts/setting-up-raid-on-existing/comment_15_ea7bf9dd2aaddafefc2ca34aebd387a4._comment b/posts/setting-up-raid-on-existing/comment_15_ea7bf9dd2aaddafefc2ca34aebd387a4._comment
new file mode 100644
index 0000000..14281bc
--- /dev/null
+++ b/posts/setting-up-raid-on-existing/comment_15_ea7bf9dd2aaddafefc2ca34aebd387a4._comment
@@ -0,0 +1,21 @@
+[[!comment format=mdwn
+ ip="83.208.32.87"
+ claimedauthor="TyNyT"
+ subject="Proper Grub approach"
+ date="2017-06-25T18:33:53Z"
+ content="""
+Hi, I found the Grub reconfig too complex and not working well in case the /boot is on a separate partition, failing to rescue mode.
+
+Instead of fiddling with the grub console, one can fix the issue before reboot - just to chroot into the mounted md partitions (be aware, CHOOSE TO INSTALL GRUB TO MD-ENABLED DRIVE _ONLY_, just not to touch the \"source\" drive):
+
+    mount -t proc /proc /mnt/mntroot/proc
+    mount --rbind /sys /mnt/mntroot/sys
+    mount --make-rslave /mnt/mntroot/sys
+    mount --rbind /dev /mnt/mntroot/dev
+    mount --make-rslave /mnt/mntroot/dev
+    chroot /mnt/mntroot /bin/bash
+    source /etc/profile
+    dpkg-reconfigure grub-pc  
+
+I consider this approach to be much cleaner.
+"""]]

Remove haveged
This was removed from BetterCrypto.org:
https://github.com/BetterCrypto/Applied-Crypto-Hardening/commit/cf7cef7a870c1b77089b1bd6209ded6525b5a4e0
https://lists.cert.at/pipermail/ach/2017-May/thread.html#2255
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index 4638aa6..722d134 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -212,7 +212,7 @@ before reloading these settings using `sysctl -p`.
 
 # Entropy and timekeeping
 
-    apt install haveged rng-tools ntp
+    apt install rng-tools ntp
 
 To keep the system clock accurate and increase the amount of entropy
 available to the server, I install the above packages and add the `tpm_rng`

Remove the recommendation to increase log verbosity
Newer (jessie+) versions of ssh already include the pubkey fingerprints in
the accepted connection messages.
diff --git a/posts/hardening-ssh-servers.mdwn b/posts/hardening-ssh-servers.mdwn
index f9c889a..9351138 100644
--- a/posts/hardening-ssh-servers.mdwn
+++ b/posts/hardening-ssh-servers.mdwn
@@ -108,23 +108,11 @@ You may also want to include the following options to each entry:
 
 # Increasing the amount of logging
 
-The first thing I'd recommend is to increase the level of verbosity in
-`/etc/ssh/sshd_config`:
-
-    LogLevel VERBOSE
-
-which will, amongst other things, log the fingerprints of keys used to login:
-
-    sshd: Connection from 192.0.2.2 port 39671
-    sshd: Found matching RSA key: de:ad:be:ef:ca:fe
-    sshd: Postponed publickey for francois from 192.0.2.2 port 39671 ssh2 [preauth]
-    sshd: Accepted publickey for francois from 192.0.2.2 port 39671 ssh2 
-
-Secondly, if you run [logcheck](https://packages.debian.org/stable/logcheck)
+Ff you run [logcheck](https://packages.debian.org/stable/logcheck)
 and would like to whitelist the "Accepted publickey" messages on your
 server, you'll have to start by deleting the first line of
 `/etc/logcheck/ignore.d.server/sshd`. Then you can add an entry for all of
-the usernames and IP addresses that you expect to see.
+the usernames, IP addresses and ssh keys that you expect to see.
 
 Finally, it is also possible to
 [log all commands issued by a specific user over ssh](http://beardyjay.co.uk/logging-all-ssh-commands/logging-ssh)

Mention healthchecks.io
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index a82cac8..4638aa6 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -311,6 +311,12 @@ to ensure that email doesn't accumulate unmonitored on this box.
 Finally, set reverse DNS for the server's IPv4 and IPv6 addresses and then
 test the whole setup using `mail root`.
 
+To monitor that mail never stops flowing, add this machine to a free
+[healthchecks.io](https://healthchecks.io) account and create a
+`/etc/cron.d/healthchecks-io` cronjob:
+
+    0 1 * * * root echo "ping" | mail xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx@hchk.io
+
 # Network tuning
 
 To [reduce the server's contribution to

Add Django 400 Bad Request post
diff --git a/posts/mysterious-400-bad-request-error-django-debug.mdwn b/posts/mysterious-400-bad-request-error-django-debug.mdwn
new file mode 100644
index 0000000..2c48fd7
--- /dev/null
+++ b/posts/mysterious-400-bad-request-error-django-debug.mdwn
@@ -0,0 +1,71 @@
+[[!meta title="Mysterious 400 Bad Request in Django debug mode"]]
+[[!meta date="2017-06-10T17:20:00:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+While upgrading [Libravatar](https://www.libravatar.org) to a more recent
+version of [Django](https://www.djangoproject.com/), I ran into a
+mysterious 400 error.
+
+In debug mode, my site was working fine, but with `DEBUG = False`, I would
+only a page containing this error:
+
+    Bad Request (400)
+
+with no extra details in the web server logs.
+
+# Turning on extra error logging
+
+To see the full error message, I [configured logging to a
+file](https://docs.djangoproject.com/en/1.11/topics/logging/#examples) by
+adding this to `settings.py`:
+
+```
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': False,
+    'handlers': {
+        'file': {
+            'level': 'DEBUG',
+            'class': 'logging.FileHandler',
+            'filename': '/tmp/debug.log',
+        },
+    },
+    'loggers': {
+        'django': {
+            'handlers': ['file'],
+            'level': 'DEBUG',
+            'propagate': True,
+        },
+    },
+}
+```
+
+Then I got the following error message:
+
+    Invalid HTTP_HOST header: 'www.example.com'. You may need to add u'www.example.com' to ALLOWED_HOSTS.
+
+# Temporary hack
+
+Sure enough, putting this in `settings.py` would make it work outside of debug mode:
+
+    ALLOWED_HOSTS = ['*']
+
+which means that there's a mismatch between the HTTP_HOST from Apache and
+[the one that Django expects](https://docs.djangoproject.com/en/1.11/topics/security/#host-headers-virtual-hosting).
+
+# Root cause
+
+The underlying problem was that the
+[Libravatar config file was missing the square brackets](https://git.launchpad.net/~libravatar/libravatar/commit/?id=a8c1002a39e7a1ef7d0ed7e5fb2ecf536ad4eede)
+around the
+[`ALLOWED_HOSTS` setting](https://docs.djangoproject.com/en/1.11/ref/settings/#allowed-hosts).
+
+I had this:
+
+    ALLOWED_HOSTS = 'www.example.com'
+
+instead of:
+
+    ALLOWED_HOSTS = ['www.example.com']
+
+[[!tag django]] [[!tag nzoss]] [[!tag debian]] [[!tag libravatar]]

Commit the new ejabberd key
diff --git a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
index 0f8da88..5fd7dbc 100644
--- a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
+++ b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
@@ -16,7 +16,7 @@ Instead, this is the script I put in `/etc/cron.daily/certbot-renew`:
     /usr/bin/certbot renew --quiet --pre-hook "/bin/systemctl stop apache2.service" --post-hook "/bin/systemctl start apache2.service"
 
     pushd /etc/ > /dev/null
-    /usr/bin/git add letsencrypt
+    /usr/bin/git add letsencrypt ejabberd
     DIFFSTAT="$(/usr/bin/git diff --cached --stat)"
     if [ -n "$DIFFSTAT" ] ; then
         /usr/bin/git commit --quiet -m "Renewed letsencrypt certs"

Emphasize that both cdn and seccdn need to be removed
diff --git a/posts/server-migration-plan.mdwn b/posts/server-migration-plan.mdwn
index 4b64cf1..cb2358e 100644
--- a/posts/server-migration-plan.mdwn
+++ b/posts/server-migration-plan.mdwn
@@ -13,7 +13,7 @@ go through a similar process.
 # Prepare DNS
 
 * Change the TTL on the DNS entry for `libravatar.org` to 3600 seconds.
-* Remove the mirrors I don't control from the DNS load balancer (`cdn` and `seccdn`).
+* Remove the mirrors I don't control from the DNS load balancer (`cdn` **and** `seccdn`).
 * Remove the main server from `cdn` and `seccdn` in DNS.
 
 # Preparing the new server

Add a note about defaulting to a UTF-8 locale
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index bbfda33..a82cac8 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -64,6 +64,10 @@ the list of generated locales:
 
     dpkg-reconfigure locales
 
+Make sure the default locale is **using the UTF-8** encoding since that will
+ensure that things like Postgres default to the One True Encoding when you
+install/bootstrap them.
+
 Other than that, I [harden the ssh configuration](http://feeding.cloud.geek.nz/posts/hardening-ssh-servers/)
 and end up with the following settings in `/etc/ssh/sshd_config` (jessie):
 

Expand on how to copy the data files in /var/lib/libravatar/
diff --git a/posts/server-migration-plan.mdwn b/posts/server-migration-plan.mdwn
index a4c5597..4b64cf1 100644
--- a/posts/server-migration-plan.mdwn
+++ b/posts/server-migration-plan.mdwn
@@ -95,9 +95,25 @@ go through a similar process.
 * [Tweet](https://twitter.com/libravatar/status/364659172983308288) and [dent](https://identi.ca/libravatar/note/UFBI9ne8SsOftkYlSKPHQQ) about the upcoming migration.
 
 * Enable the static file config on the old server (disabling the Django app).
-
-* Copy the database from the old server and restore it on the new server.
+* Disable pgbouncer to ensure that Django cannot access postgres anymore.
+* Copy the database from the old server and restore it on the new server **making sure it's in the UTF8 encoding**.
 * Copy `/var/lib/libravatar` from the old server to the new one.
+  * On the new server:
+
+        chmod a+w /var/lib/libravatar/avatar
+        chmod a+w /var/lib/libravatar/user
+
+  * From laptop:
+
+        rsync -a -H -v husavik.libravatar.org:/var/lib/libravatar/avatar .
+        rsync -a -H -v husavik.libravatar.org:/var/lib/libravatar/user .
+        rsync -a -H -v avatar/* selfoss.libravatar.org:/var/lib/libravatar/avatar/
+        rsync -a -H -v user/* selfoss.libravatar.org:/var/lib/libravatar/avatar/
+
+  * On the new server:
+
+        chmod go-w /var/lib/libravatar/avatar
+        chmod go-w /var/lib/libravatar/user
 
 # Disable mirror sync
 

Use the HTTPS version of identi.ca
diff --git a/posts/server-migration-plan.mdwn b/posts/server-migration-plan.mdwn
index a2a2d13..a4c5597 100644
--- a/posts/server-migration-plan.mdwn
+++ b/posts/server-migration-plan.mdwn
@@ -57,7 +57,7 @@ go through a similar process.
       <html>
       <body>
       <p>We are migrating to a new server. See you soon!</p>
-      <p>- <a href="http://identi.ca/libravatar">@libravatar</a></p>
+      <p>- <a href="https://identi.ca/libravatar">@libravatar</a></p>
       </body>
       </html>
 

Update Apache configs for Apache 2.4
diff --git a/posts/server-migration-plan.mdwn b/posts/server-migration-plan.mdwn
index 0cdf022..a2a2d13 100644
--- a/posts/server-migration-plan.mdwn
+++ b/posts/server-migration-plan.mdwn
@@ -29,7 +29,7 @@ go through a similar process.
 
 # Preparing the old server
 
-* Prepare a static "under migration" Apache config in `/etc/apache2/sites-enables.static/`:
+* Prepare a static "under migration" Apache config in `/etc/apache2/sites-enabled.static/default.conf`:
 
       <VirtualHost *:80>
           RewriteEngine On
@@ -38,24 +38,21 @@ go through a similar process.
 
       <VirtualHost *:443>
           SSLEngine on
-          SSLProtocol TLSv1
-          SSLHonorCipherOrder On
-          SSLCipherSuite RC4-SHA:HIGH:!kEDH
       
           SSLCertificateFile /etc/libravatar/www.crt
           SSLCertificateKeyFile /etc/libravatar/www.pem
           SSLCertificateChainFile /etc/libravatar/www-chain.pem
       
           RewriteEngine On
-          RewriteRule ^ /var/www/migration.html [last]
+          RewriteRule ^ /var/www/html/migration.html [last]
       
-          <Directory /var/www>
+          <Directory /var/www/html>
               Allow from all
               Options -Indexes
           </Directory>
       </VirtualHost>
 
-* Put this static file in /var/www/migration.html:
+* Put this static file in /var/www/html/migration.html:
 
       <html>
       <body>
@@ -68,7 +65,7 @@ go through a similar process.
 
       a2enmod rewrite
 
-* Prepare an Apache config proxying to the new server in `/etc/apache2/sites-enabled.proxy/`:
+* Prepare an Apache config proxying to the new server in `/etc/apache2/sites-enabled.proxy/default.conf`:
 
       <VirtualHost *:80>
           RewriteEngine On
@@ -77,9 +74,6 @@ go through a similar process.
       
       <VirtualHost *:443>
           SSLEngine on
-          SSLProtocol TLSv1
-          SSLHonorCipherOrder On
-          SSLCipherSuite RC4-SHA:HIGH:!kEDH
       
           SSLCertificateFile /etc/libravatar/www.crt
           SSLCertificateKeyFile /etc/libravatar/www.pem

Remove exim4 config files after replacing it with postfix
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index 123b394..bbfda33 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -274,6 +274,7 @@ and then run:
 # Mail
 
     apt install postfix
+    apt purge exim4-base exim4-daemon-light exim4-config
 
 Configuring mail properly is tricky but the following has worked for me.
 

Remove more old wheezy notes
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index 97a0cd2..123b394 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -85,14 +85,6 @@ and end up with the following settings in `/etc/ssh/sshd_config` (jessie):
     LogLevel VERBOSE
     AllowGroups sshuser
 
-or the following for wheezy servers:
-
-    HostKey /etc/ssh/ssh_host_rsa_key
-    HostKey /etc/ssh/ssh_host_ecdsa_key
-    KexAlgorithms ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
-    Ciphers aes256-ctr,aes192-ctr,aes128-ctr
-    MACs hmac-sha2-512,hmac-sha2-256
-
 On those servers where I need [duplicity/paramiko to
 work](https://github.com/paramiko/paramiko/issues/509), I also add the following:
 
@@ -228,31 +220,21 @@ module to `/etc/modules`.
 
 The above packages are all about catching mistakes (such as
 [accidental deletions](http://feeding.cloud.geek.nz/posts/preventing-accidental-deletion-of/)).
-However, in order to extend the molly-guard protection to mosh sessions, one needs to
-manually [apply a patch](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=705397).
 
 # Package updates
 
-    apt install apticron unattended-upgrades deborphan debfoster apt-listchanges update-notifier-common aptitude popularity-contest needrestart
+    apt install apticron unattended-upgrades deborphan debfoster apt-listchanges reboot-notifier popularity-contest needrestart
 
 These tools help me keep packages up to date and remove unnecessary or
 obsolete packages from servers. On Rackspace servers, a small [configuration
 change](http://feeding.cloud.geek.nz/posts/using-unattended-upgrades-on-rackspace-debian-ubuntu-servers/)
 is needed to automatically update the monitoring tools.
 
-In addition to this, I use the `update-notifier-common` package along with
-the following cronjob in `/etc/cron.daily/reboot-required`:
-
-    #!/bin/sh
-    cat /var/run/reboot-required 2> /dev/null || true
-
+On jessie or later, I install
+[reboot-notifier](http://feeding.cloud.geek.nz/posts/introducing-reboot-notifier/)
 to send me a notification whenever a kernel update requires a reboot to take
 effect.
 
-If you're on jessie or later, simply install
-[reboot-notifier](http://feeding.cloud.geek.nz/posts/introducing-reboot-notifier/)
-instead of `update-notifier-common` and you're done!
-
 In addition to knowing when you need to reboot your machine, the
 `needrestart` package will let you know (and offer to do it for you) when
 you need to restart a daemon using an obsolete library.
@@ -266,7 +248,8 @@ enabling data collection in `/etc/default/sysstat` to be useful.
 
 # Apache configuration
 
-    apt install apache2-mpm-event
+    apt install apache2
+    a2enmod mpm_event
 
 While configuring apache is often specific to each server and the services
 that will be running on it, there are a few common changes I make.
@@ -280,18 +263,6 @@ I enable these in `/etc/apache2/conf-enabled/security.conf`:
     ServerTokens Prod
     ServerSignature Off
 
-or `/etc/apache2/conf.d/security` on wheezy):
-
-    <Directory />
-        AllowOverride None
-        Order Deny,Allow
-        Deny from all
-    </Directory>
-    ServerTokens Prod
-    ServerSignature Off
-
-and remove cgi-bin directives from `/etc/apache2/sites-enabled/000-default`.
-
 I also create a new `/etc/apache2/conf-available/servername.conf` which contains:
 
     ServerName machine_hostname

Remove obsolete harden-* packages
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index 79dd8e8..97a0cd2 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -189,7 +189,7 @@ and these to `/etc/rkhunter.conf.local`:
 
 # General hardening
 
-    apt install harden-clients harden-environment harden-servers apparmor apparmor-profiles apparmor-profiles-extra libpam-tmpdir
+    apt install apparmor apparmor-profiles apparmor-profiles-extra libpam-tmpdir
 
 While the harden packages are configuration-free, AppArmor must be [manually enabled](https://wiki.debian.org/AppArmor/HowToUse#Enable_AppArmor):
 

Use `apt` instead of `apt-get`
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index 9088b95..79dd8e8 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -9,7 +9,7 @@ how I customize recent releases of Debian on those servers.
 
 # Hardware tests
 
-    apt-get install memtest86+ smartmontools e2fsprogs
+    apt install memtest86+ smartmontools e2fsprogs
 
 Prior to spending any time configuring a new physical server, I like to
 ensure that the hardware is fine.
@@ -24,7 +24,7 @@ Then I check the hard drives using:
 
 # Configuration
 
-    apt-get install etckeeper git sudo vim
+    apt install etckeeper git sudo vim
 
 To keep track of the configuration changes I make in `/etc/`, I use etckeeper
 to keep that directory in a git repository and make the following changes to
@@ -52,7 +52,7 @@ following to `/etc/vim/vimrc.local`:
 
 # ssh
 
-    apt-get install openssh-server mosh fail2ban
+    apt install openssh-server mosh fail2ban
 
 Since most of my servers are set to UTC time, I like to [use my local
 timezone](http://petereisentraut.blogspot.com/2012/04/setting-time-zone-on-remote-ssh-hosts.html)
@@ -121,8 +121,8 @@ and add a timeout for root sessions by putting this in `/root/.bash_profile`:
 
 # Security checks
 
-    apt-get install logcheck logcheck-database fcheck tiger debsums corekeeper mcelog rkhunter
-    apt-get remove --purge john john-data rpcbind tripwire unhide unhide.rb
+    apt install logcheck logcheck-database fcheck tiger debsums corekeeper mcelog rkhunter
+    apt remove --purge john john-data rpcbind tripwire unhide unhide.rb
 
 Logcheck is the main tool I use to keep an eye on log files, which is why I
 add a few additional log files to the default list in
@@ -189,7 +189,7 @@ and these to `/etc/rkhunter.conf.local`:
 
 # General hardening
 
-    apt-get install harden-clients harden-environment harden-servers apparmor apparmor-profiles apparmor-profiles-extra libpam-tmpdir
+    apt install harden-clients harden-environment harden-servers apparmor apparmor-profiles apparmor-profiles-extra libpam-tmpdir
 
 While the harden packages are configuration-free, AppArmor must be [manually enabled](https://wiki.debian.org/AppArmor/HowToUse#Enable_AppArmor):
 
@@ -216,7 +216,7 @@ before reloading these settings using `sysctl -p`.
 
 # Entropy and timekeeping
 
-    apt-get install haveged rng-tools ntp
+    apt install haveged rng-tools ntp
 
 To keep the system clock accurate and increase the amount of entropy
 available to the server, I install the above packages and add the `tpm_rng`
@@ -224,7 +224,7 @@ module to `/etc/modules`.
 
 # Preventing mistakes
 
-    apt-get install molly-guard safe-rm sl
+    apt install molly-guard safe-rm sl
 
 The above packages are all about catching mistakes (such as
 [accidental deletions](http://feeding.cloud.geek.nz/posts/preventing-accidental-deletion-of/)).
@@ -233,7 +233,7 @@ manually [apply a patch](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=705397
 
 # Package updates
 
-    apt-get install apticron unattended-upgrades deborphan debfoster apt-listchanges update-notifier-common aptitude popularity-contest needrestart
+    apt install apticron unattended-upgrades deborphan debfoster apt-listchanges update-notifier-common aptitude popularity-contest needrestart
 
 These tools help me keep packages up to date and remove unnecessary or
 obsolete packages from servers. On Rackspace servers, a small [configuration
@@ -259,14 +259,14 @@ you need to restart a daemon using an obsolete library.
 
 # Handy utilities
 
-    apt-get install renameutils atool iotop sysstat lsof mtr-tiny mc
+    apt install renameutils atool iotop sysstat lsof mtr-tiny mc
 
 Most of these tools are configuration-free, except for sysstat, which requires
 enabling data collection in `/etc/default/sysstat` to be useful.
 
 # Apache configuration
 
-    apt-get install apache2-mpm-event
+    apt install apache2-mpm-event
 
 While configuring apache is often specific to each server and the services
 that will be running on it, there are a few common changes I make.
@@ -302,7 +302,7 @@ and then run:
 
 # Mail
 
-    apt-get install postfix
+    apt install postfix
 
 Configuring mail properly is tricky but the following has worked for me.
 

Suggest whitelisting your own IP addresses
diff --git a/posts/hardening-ssh-servers.mdwn b/posts/hardening-ssh-servers.mdwn
index a0643ef..f9c889a 100644
--- a/posts/hardening-ssh-servers.mdwn
+++ b/posts/hardening-ssh-servers.mdwn
@@ -57,6 +57,12 @@ install the [fail2ban](http://www.fail2ban.org/wiki/index.php/Main_Page)
 package. It keeps an eye on the ssh log file (`/var/log/auth.log`) and
 temporarily blocks IP addresses after a number of failed login attempts.
 
+To prevent your own IP addresses from being blocked, add them to
+`/etc/fail2ban/jail.conf`:
+
+    [DEFAULT]
+    ignoreip = 127.0.0.1/8 1.2.3.4
+
 Another approach is to hide the ssh service using
 [Single-Packet Authentication](http://en.wikipedia.org/wiki/Single_Packet_Authorization). I
 have [fwknop](http://www.cipherdyne.org/fwknop/) installed on some of my
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index 70a3473..9088b95 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -99,6 +99,13 @@ work](https://github.com/paramiko/paramiko/issues/509), I also add the following
     KexAlgorithms ...,diffie-hellman-group-exchange-sha1
     MACs ...,hmac-sha1
 
+Since [fail2ban](http://www.fail2ban.org/) is used to rate-limit attempts to
+brute-force ssh connections, you may want to whitelist your own IP addresses
+by adding them to `/etc/fail2ban/jail.conf`:
+
+    [DEFAULT]
+    ignoreip = 127.0.0.1/8 1.2.3.4
+
 Then I remove the "Accepted" filter in `/etc/logcheck/ignore.d.server/ssh`
 (first line) to get a notification whenever anybody successfully logs into
 my server.

Remove duplicate Flattr meta directive from homepage
Adding it to the template in 615caebf7e603e7b2cc3c7fdf6a0ab1da0a5be4b also
adds it to the homepage.
diff --git a/index.mdwn b/index.mdwn
index ef3117a..d08446d 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -6,5 +6,3 @@
 
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
-
-[[!meta name="flattr:id" content="4j6y0v"]]

Add Flattr meta tag to the page template
diff --git a/templates/page.tmpl b/templates/page.tmpl
new file mode 100644
index 0000000..3688f11
--- /dev/null
+++ b/templates/page.tmpl
@@ -0,0 +1,223 @@
+<!DOCTYPE html>
+<TMPL_IF HTML_LANG_CODE><html lang="<TMPL_VAR HTML_LANG_CODE>" dir="<TMPL_VAR HTML_LANG_DIR>" xmlns="http://www.w3.org/1999/xhtml"><TMPL_ELSE><html xmlns="http://www.w3.org/1999/xhtml"></TMPL_IF>
+<head>
+<TMPL_IF DYNAMIC>
+<TMPL_IF FORCEBASEURL><base href="<TMPL_VAR FORCEBASEURL>" /><TMPL_ELSE>
+<TMPL_IF BASEURL><base href="<TMPL_VAR BASEURL>" /></TMPL_IF>
+</TMPL_IF>
+</TMPL_IF>
+<TMPL_IF HTML5><meta charset="utf-8" /><TMPL_ELSE><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></TMPL_IF>
+<title><TMPL_VAR TITLE></title>
+<TMPL_IF RESPONSIVE_LAYOUT><meta name="viewport" content="width=device-width, initial-scale=1" /></TMPL_IF>
+<TMPL_IF FAVICON>
+<link rel="icon" href="<TMPL_VAR BASEURL><TMPL_VAR FAVICON>" type="image/x-icon" />
+</TMPL_IF>
+<link rel="stylesheet" href="<TMPL_VAR BASEURL>style.css" type="text/css" />
+<TMPL_IF LOCAL_CSS>
+<link rel="stylesheet" href="<TMPL_VAR BASEURL><TMPL_VAR LOCAL_CSS>" type="text/css" />
+<TMPL_ELSE>
+<link rel="stylesheet" href="<TMPL_VAR BASEURL>local.css" type="text/css" />
+</TMPL_IF>
+
+<TMPL_UNLESS DYNAMIC>
+<TMPL_IF EDITURL>
+<link rel="alternate" type="application/x-wiki" title="Edit this page" href="<TMPL_VAR EDITURL>" />
+</TMPL_IF>
+<TMPL_IF FEEDLINKS><TMPL_VAR FEEDLINKS></TMPL_IF>
+<TMPL_IF RELVCS><TMPL_VAR RELVCS></TMPL_IF>
+<TMPL_IF META><TMPL_VAR META></TMPL_IF>
+<TMPL_LOOP TRAILLOOP>
+<TMPL_IF PREVPAGE>
+<link rel="prev" href="<TMPL_VAR PREVURL>" title="<TMPL_VAR PREVTITLE>" />
+</TMPL_IF>
+<link rel="up" href="<TMPL_VAR TRAILURL>" title="<TMPL_VAR TRAILTITLE>" />
+<TMPL_IF NEXTPAGE>
+<link rel="next" href="<TMPL_VAR NEXTURL>" title="<TMPL_VAR NEXTTITLE>" />
+</TMPL_IF>
+</TMPL_LOOP>
+</TMPL_UNLESS>
+
+<meta name="flattr:id" content="4j6y0v">
+</head>
+<body>
+
+<TMPL_IF HTML5><article class="page"><TMPL_ELSE><div class="page"></TMPL_IF>
+
+<TMPL_IF HTML5><section class="pageheader"><TMPL_ELSE><div class="pageheader"></TMPL_IF>
+<TMPL_IF HTML5><header class="header"><TMPL_ELSE><div class="header"></TMPL_IF>
+<span>
+<span class="parentlinks">
+<TMPL_LOOP PARENTLINKS>
+<a href="<TMPL_VAR URL>"><TMPL_VAR PAGE></a>/ 
+</TMPL_LOOP>
+</span>
+<span class="title">
+<TMPL_VAR TITLE>
+<TMPL_IF ISTRANSLATION>
+&nbsp;(<TMPL_VAR PERCENTTRANSLATED>%)
+</TMPL_IF>
+</span>
+</span>
+<TMPL_UNLESS DYNAMIC>
+<TMPL_IF SEARCHFORM>
+<TMPL_VAR SEARCHFORM>
+</TMPL_IF>
+</TMPL_UNLESS>
+<TMPL_IF HTML5></header><TMPL_ELSE></div></TMPL_IF>
+
+<TMPL_IF HAVE_ACTIONS>
+<TMPL_IF HTML5><nav class="actions"><TMPL_ELSE><div class="actions"></TMPL_IF>
+<ul>
+<TMPL_IF EDITURL>
+<li><a href="<TMPL_VAR EDITURL>" rel="nofollow">Edit</a></li>
+</TMPL_IF>
+<TMPL_IF RECENTCHANGESURL>
+<li><a href="<TMPL_VAR RECENTCHANGESURL>">RecentChanges</a></li>
+</TMPL_IF>
+<TMPL_IF HISTORYURL>
+<li><a rel="nofollow" href="<TMPL_VAR HISTORYURL>">History</a></li>
+</TMPL_IF>
+<TMPL_IF GETSOURCEURL>
+<li><a rel="nofollow" href="<TMPL_VAR GETSOURCEURL>">Source</a></li>
+</TMPL_IF>
+<TMPL_IF PREFSURL>
+<li><a rel="nofollow" href="<TMPL_VAR PREFSURL>">Preferences</a></li>
+</TMPL_IF>
+<TMPL_IF ACTIONS>
+<TMPL_LOOP ACTIONS>
+<li><TMPL_VAR ACTION></li>
+</TMPL_LOOP>
+</TMPL_IF>
+<TMPL_IF COMMENTSLINK>
+<li><TMPL_VAR COMMENTSLINK></li>
+<TMPL_ELSE>
+<TMPL_IF DISCUSSIONLINK>
+<li><TMPL_VAR DISCUSSIONLINK></li>
+</TMPL_IF>
+</TMPL_IF>
+</ul>
+<TMPL_IF HTML5></nav><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+
+<TMPL_IF OTHERLANGUAGES>
+<TMPL_IF HTML5><nav id="otherlanguages"><TMPL_ELSE><div id="otherlanguages"></TMPL_IF>
+<ul>
+<TMPL_LOOP OTHERLANGUAGES>
+<li>
+<a href="<TMPL_VAR URL>"><TMPL_VAR LANGUAGE></a>
+<TMPL_IF MASTER>
+(master)
+<TMPL_ELSE>
+&nbsp;(<TMPL_VAR PERCENT>%)
+</TMPL_IF>
+</li>
+</TMPL_LOOP>
+</ul>
+<TMPL_IF HTML5></nav><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+
+<TMPL_UNLESS DYNAMIC>
+<TMPL_VAR TRAILS>
+</TMPL_UNLESS>
+
+<TMPL_IF HTML5></section><TMPL_ELSE></div></TMPL_IF>
+
+<TMPL_UNLESS DYNAMIC>
+<TMPL_IF SIDEBAR>
+<TMPL_IF HTML5><aside class="sidebar"><TMPL_ELSE><div class="sidebar"></TMPL_IF>
+<TMPL_VAR SIDEBAR>
+<TMPL_IF HTML5></aside><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+</TMPL_UNLESS>
+
+<div id="pagebody">
+
+<TMPL_IF HTML5><section<TMPL_ELSE><div</TMPL_IF> id="content" role="main">
+<TMPL_VAR CONTENT>
+<TMPL_IF HTML5></section><TMPL_ELSE></div></TMPL_IF>
+
+<TMPL_IF ENCLOSURE>
+<TMPL_IF HTML5><section id="enclosure"><TMPL_ELSE><div id="enclosure"></TMPL_IF>
+<a href="<TMPL_VAR ENCLOSURE>">Download</a>
+<TMPL_IF HTML5></section><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+
+<TMPL_UNLESS DYNAMIC>
+<TMPL_IF COMMENTS>
+<TMPL_IF HTML5><section<TMPL_ELSE><div</TMPL_IF> id="comments" role="complementary">
+<TMPL_VAR COMMENTS>
+<TMPL_IF ADDCOMMENTURL>
+<div class="addcomment">
+<a rel="nofollow" href="<TMPL_VAR ADDCOMMENTURL>">Add a comment</a>
+</div>
+<TMPL_ELSE>
+<div class="addcomment">Comments on this page are closed.</div>
+</TMPL_IF>
+<TMPL_IF HTML5></section><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+</TMPL_UNLESS>
+
+</div>
+
+<TMPL_IF HTML5><footer<TMPL_ELSE><div</TMPL_IF> id="footer" class="pagefooter" role="contentinfo">
+<TMPL_UNLESS DYNAMIC>
+<TMPL_IF HTML5><nav id="pageinfo"><TMPL_ELSE><div id="pageinfo"></TMPL_IF>
+
+<TMPL_VAR TRAILS>
+
+<TMPL_IF TAGS>
+<TMPL_IF HTML5><nav class="tags"><TMPL_ELSE><div class="tags"></TMPL_IF>
+Tags:
+<TMPL_LOOP TAGS>
+<TMPL_VAR LINK>
+</TMPL_LOOP>
+<TMPL_IF HTML5></nav><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+
+<TMPL_IF BACKLINKS>
+<TMPL_IF HTML5><nav id="backlinks"><TMPL_ELSE><div id="backlinks"></TMPL_IF>
+Links:
+<TMPL_LOOP BACKLINKS>
+<a href="<TMPL_VAR URL>"><TMPL_VAR PAGE></a>
+</TMPL_LOOP>
+<TMPL_IF MORE_BACKLINKS>
+<span class="popup">...
+<span class="balloon">
+<TMPL_LOOP MORE_BACKLINKS>
+<a href="<TMPL_VAR URL>"><TMPL_VAR PAGE></a>
+</TMPL_LOOP>
+</span>
+</span>
+</TMPL_IF>
+<TMPL_IF HTML5></nav><TMPL_ELSE></div></TMPL_IF>
+</TMPL_IF>
+

(Diff truncated)
Revert "Move Flattr meta directive to the sidebar"
This reverts commit 0587adcf82d0ccf71bd80c6ae6a2ca064614b086.
It doesn't work from the sidebar apparently.
diff --git a/index.mdwn b/index.mdwn
index d08446d..ef3117a 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -6,3 +6,5 @@
 
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
+
+[[!meta name="flattr:id" content="4j6y0v"]]
diff --git a/sidebar.mdwn b/sidebar.mdwn
index 209a4a0..463ac41 100644
--- a/sidebar.mdwn
+++ b/sidebar.mdwn
@@ -1,5 +1,3 @@
-[[!meta name="flattr:id" content="4j6y0v"]]
-
 # Subscribe to this blog
 
 <a href="https://feeding.cloud.geek.nz/index.rss"><img src="/feed-icon.png" height="32" width="32" align="left">Subscribe in a reader</a>

Move Flattr meta directive to the sidebar
Hopefully it will show up on every page now, not just the homepage.
diff --git a/index.mdwn b/index.mdwn
index ef3117a..d08446d 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -6,5 +6,3 @@
 
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
-
-[[!meta name="flattr:id" content="4j6y0v"]]
diff --git a/sidebar.mdwn b/sidebar.mdwn
index 463ac41..209a4a0 100644
--- a/sidebar.mdwn
+++ b/sidebar.mdwn
@@ -1,3 +1,5 @@
+[[!meta name="flattr:id" content="4j6y0v"]]
+
 # Subscribe to this blog
 
 <a href="https://feeding.cloud.geek.nz/index.rss"><img src="/feed-icon.png" height="32" width="32" align="left">Subscribe in a reader</a>

Fix Flattr meta directive
https://ikiwiki.info/bugs/It__39__s_not_possible_to_add_the_new_Flattr_meta_tag_using_the_meta_directive/
diff --git a/index.mdwn b/index.mdwn
index ac02da5..ef3117a 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -7,4 +7,4 @@
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
 
-[[!meta flattr:id="4j6y0v"]]
+[[!meta name="flattr:id" content="4j6y0v"]]

Leave the meta directive in the format that should work
diff --git a/index.mdwn b/index.mdwn
index ef4872c..ac02da5 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -7,4 +7,4 @@
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
 
-[[!meta flattr\:id="4j6y0v"]]
+[[!meta flattr:id="4j6y0v"]]

Another attempt at parsing the correct value
diff --git a/index.mdwn b/index.mdwn
index 26d9aa5..ef4872c 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -7,4 +7,4 @@
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
 
-[[!meta flattr:id = 4j6y0v]]
+[[!meta flattr\:id="4j6y0v"]]

Trying to work around the parsing of the meta directive
diff --git a/index.mdwn b/index.mdwn
index 26bc9e0..26d9aa5 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -7,4 +7,4 @@
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
 
-[[!meta flattr:id=4j6y0v]]
+[[!meta flattr:id = 4j6y0v]]

Yet another attempt
diff --git a/index.mdwn b/index.mdwn
index cf96357..26bc9e0 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -7,4 +7,4 @@
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
 
-[[!meta "flattr:id"="4j6y0v"]]
+[[!meta flattr:id=4j6y0v]]

Another attempt at fixing the meta directive
diff --git a/index.mdwn b/index.mdwn
index a50db9e..cf96357 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -7,4 +7,4 @@
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
 
-[[!meta flattr:id param="4j6y0v"]]
+[[!meta "flattr:id"="4j6y0v"]]

Another attempt at fixing the use of the meta directive
diff --git a/index.mdwn b/index.mdwn
index ac02da5..a50db9e 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -7,4 +7,4 @@
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
 
-[[!meta flattr:id="4j6y0v"]]
+[[!meta flattr:id param="4j6y0v"]]

Fix use of meta directive for Flattr ID
diff --git a/index.mdwn b/index.mdwn
index 1b5254e..ac02da5 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -7,4 +7,4 @@
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
 
-[[!meta  field="flattr:id" param="4j6y0v"]]
+[[!meta flattr:id="4j6y0v"]]

Add Flattr ID
diff --git a/index.mdwn b/index.mdwn
index d08446d..1b5254e 100644
--- a/index.mdwn
+++ b/index.mdwn
@@ -6,3 +6,5 @@
 
 [[!inline pages="page(./posts/*) and !*/Discussion" show="10"
 actions=yes rootpage="posts"]]
+
+[[!meta  field="flattr:id" param="4j6y0v"]]

creating tag page tags/lvm
diff --git a/tags/lvm.mdwn b/tags/lvm.mdwn
new file mode 100644
index 0000000..148c5e5
--- /dev/null
+++ b/tags/lvm.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged lvm"]]
+
+[[!inline pages="tagged(lvm)" actions="no" archive="yes"
+feedshow=10]]

Add ejabberd and znc certs to my script
diff --git a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
index cc0c5b1..0f8da88 100644
--- a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
+++ b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
@@ -24,6 +24,12 @@ Instead, this is the script I put in `/etc/cron.daily/certbot-renew`:
     fi
     popd > /dev/null
 
+    # Generate the right certs for ejabberd and znc
+    if test /etc/letsencrypt/live/jabber-gw.fmarier.org/privkey.pem -nt /etc/ejabberd/ejabberd.pem ; then
+        cat /etc/letsencrypt/live/jabber-gw.fmarier.org/privkey.pem /etc/letsencrypt/live/jabber-gw.fmarier.org/fullchain.pem > /etc/ejabberd/ejabberd.pem
+    fi
+    cat /etc/letsencrypt/live/irc.fmarier.org/privkey.pem /etc/letsencrypt/live/irc.fmarier.org/fullchain.pem > /home/francois/.znc/znc.pem
+
 It temporarily disables my [Apache](https://httpd.apache.org/) webserver while it renews the
 certificates and then only outputs something to STDOUT (since my cronjob
 will email me any output) if certs have been renewed.
@@ -32,6 +38,17 @@ Since I'm using [etckeeper](https://etckeeper.branchable.com/) to keep track of
 servers, my renewal script also commits to the repository if any certs have
 changed.
 
+Finally, since my
+[XMPP server](https://feeding.cloud.geek.nz/posts/running-your-own-xmpp-server-debian-ubuntu/)
+and
+[IRC bouncer](https://feeding.cloud.geek.nz/posts/hiding-network-disconnections-using-irc-bouncer/)
+need the private key and the full certificate chain to be in the same file,
+so I regenerate these files at the end of the script. In the case of
+ejabberd, I only do so if the certificates have actually changed since
+overwriting `ejabberd.pem` changes its timestamp and triggers an
+[fcheck](https://packages.debian.org/stable/fcheck) notification (since it
+watches all files under `/etc`).
+
 # External Monitoring
 
 In order to catch mistakes or oversights, I use

Add post about LUKS and LVM on Ubuntu
diff --git a/posts/recovering-from-unbootable-ubuntu-encrypted-lvm-root-partition.mdwn b/posts/recovering-from-unbootable-ubuntu-encrypted-lvm-root-partition.mdwn
new file mode 100644
index 0000000..471bd2a
--- /dev/null
+++ b/posts/recovering-from-unbootable-ubuntu-encrypted-lvm-root-partition.mdwn
@@ -0,0 +1,93 @@
+[[!meta title="Recovering from an unbootable Ubuntu encrypted LVM root partition"]]
+[[!meta date="2017-05-15T21:10:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+A laptop that was installed using the default Ubuntu 16.10 (xenial)
+[full-disk encryption](https://www.eff.org/deeplinks/2012/11/privacy-ubuntu-1210-full-disk-encryption)
+option stopped booting after receiving a
+kernel update somewhere on the way to Ubuntu 17.04 (zesty).
+
+After showing the boot screen for about 30 seconds, a busybox shell pops up:
+
+    BusyBox v.1.21.1 (Ubuntu 1:1.21.1-1ubuntu1) built-in shell (ash)
+    Enter 'help' for list of built-in commands.
+    
+    (initramfs)
+
+Typing `exit` will display more information about the failure before
+bringing us back to the same busybox shell:
+
+    Gave up waiting for root device. Common problems:
+      - Boot args (cat /proc/cmdline)
+        - Check rootdelay= (did the system wait long enough?)
+        - Check root= (did the system wait for the right device?)
+      - Missing modules (cat /proc/modules; ls /dev)
+    ALERT! /dev/mapper/ubuntu--vg-root does not exist. Dropping to a shell! 
+    
+    BusyBox v.1.21.1 (Ubuntu 1:1.21.1-1ubuntu1) built-in shell (ash)   
+    Enter 'help' for list of built-in commands.  
+    
+    (initramfs)
+
+which now complains that the `/dev/mapper/ubuntu--vg-root` root partition
+(which uses
+[LUKS](https://gitlab.com/cryptsetup/cryptsetup/blob/master/README.md) and
+[LVM](https://www.sourceware.org/lvm2/)) cannot be found.
+
+There is some [comprehensive advice out there](https://askubuntu.com/questions/567730/gave-up-waiting-for-root-device-ubuntu-vg-root-doesnt-exist#567897)
+but it didn't quite work for me. This is how I ended up resolving the problem.
+
+# Boot using a USB installation disk
+
+First, create bootable USB disk using the latest Ubuntu installer:
+
+1. [Download an desktop image](https://www.ubuntu.com/download/desktop).
+2. Copy the ISO directly on the USB stick (overwriting it in the process):
+
+        dd if=ubuntu.iso of=/dev/sdc1
+
+and boot the system using that USB stick ([hold the `option` key during boot on Apple hardware](https://support.apple.com/en-us/HT201255)).
+
+# Mount the encrypted partition
+
+Assuming a drive which is partitioned this way:
+
+- `/dev/sda1`: EFI partition
+- `/dev/sda2`: unencrypted boot partition
+- `/dev/sda3`: encrypted LVM partition
+
+Open a terminal and [mount the required partitions](https://superuser.com/questions/165116/mount-dev-proc-sys-in-a-chroot-environment):
+
+    cryptsetup luksOpen /dev/sda3 sda3_crypt
+    vgchange -ay
+    mount /dev/mapper/ubuntu--vg-root /mnt
+    mount /dev/sda2 /mnt/boot
+    mount -t proc proc /mnt/proc
+    mount -o bind /dev /mnt/dev
+
+Note:
+
+- When running `cryptsetup luksOpen`, you must use the same name as the one
+  that is in `/etc/crypttab` on the root parition (`sda3_crypt` in this
+  example).
+
+- All of these partitions must be present (**including `/proc` and `/dev`**) for
+  the initramfs scripts to do all of their work. If you see errors or
+  warnings, you must resolve them.
+
+# Regenerate the initramfs on the boot partition
+
+Then "enter" the root partition using:
+
+    chroot /mnt
+
+and make sure that the [lvm2](https://launchpad.net/ubuntu/+source/lvm2)
+package is installed:
+
+    apt install lvm2
+
+before regenerating the initramfs for all of the installed kernels:
+
+    update-initramfs -c -k all
+
+[[!tag debian]] [[!tag nzoss]] [[!tag ubuntu]] [[!tag luks]] [[!tag lvm]]

Fix the name of the gethash pref
diff --git a/posts/how-safe-browsing-works-in-firefox.mdwn b/posts/how-safe-browsing-works-in-firefox.mdwn
index ea7c734..d48c4a8 100644
--- a/posts/how-safe-browsing-works-in-firefox.mdwn
+++ b/posts/how-safe-browsing-works-in-firefox.mdwn
@@ -86,7 +86,7 @@ whether or not the rest of the hash matches the entry on the Safe Browsing
 list.
 
 In order resolve such conflicts, Firefox requests from the Safe Browsing
-server (`browser.safebrowsing.provider.mozilla.gethashURL`) all of the
+server (`browser.safebrowsing.provider.google.gethashURL`) all of the
 hashes that start with the affected 32-bit prefix and adds these full-length
 hashes to its local database. Turn on `browser.safebrowsing.debug` to see
 some debugging information on the terminal while these "completion" requests

Fix mpd cronjobs
The change in b3226fa96cc6e88ab6aca27aede75295abcd4c4b introduced
a permission problem since the environment variable was only
available to the test command.
diff --git a/posts/home-music-server-with-mpd.mdwn b/posts/home-music-server-with-mpd.mdwn
index 936154c..aeeaa61 100644
--- a/posts/home-music-server-with-mpd.mdwn
+++ b/posts/home-music-server-with-mpd.mdwn
@@ -74,10 +74,10 @@ and created a cronjob in `/etc/cron.d/mpd-francois` to update the database
 daily and stop the music automatically in the evening:
 
     # Refresh DB once an hour
-    5 * * * *  mpd  MPD_HOST=Password1@/run/mpd/socket test -r /run/mpd/socket && /usr/bin/mpc --quiet update
+    5 * * * *  mpd  test -r /run/mpd/socket && MPD_HOST=Password1@/run/mpd/socket /usr/bin/mpc --quiet update
     # Think of the neighbours
-    0 22 * * 0-4  mpd  MPD_HOST=Password1@/run/mpd/socket test -r /run/mpd/socket && /usr/bin/mpc --quiet stop
-    0 23 * * 5-6  mpd  MPD_HOST=Password1@/run/mpd/socket test -r /run/mpd/socket && /usr/bin/mpc --quiet stop
+    0 22 * * 0-4  mpd  test -r /run/mpd/socket && MPD_HOST=Password1@/run/mpd/socket /usr/bin/mpc --quiet stop
+    0 23 * * 5-6  mpd  test -r /run/mpd/socket && MPD_HOST=Password1@/run/mpd/socket /usr/bin/mpc --quiet stop
 
 # Clients
 

Recommend reboot-notifier instead of update-notifier-common
diff --git a/posts/using-unattended-upgrades-on-rackspace-debian-ubuntu-servers.mdwn b/posts/using-unattended-upgrades-on-rackspace-debian-ubuntu-servers.mdwn
index aa7c446..5f3c515 100644
--- a/posts/using-unattended-upgrades-on-rackspace-debian-ubuntu-servers.mdwn
+++ b/posts/using-unattended-upgrades-on-rackspace-debian-ubuntu-servers.mdwn
@@ -114,18 +114,10 @@ be updated and it keeps doing that until the system is fully up-to-date.
 The only thing missing from this is getting a reminder whenever a package
 update (usually the kernel) **requires a reboot** to take effect. That's
 where the
-[update-notifier-common](https://packages.debian.org/wheezy/update-notifier-common)
+[reboot-notifier](https://feeding.cloud.geek.nz/posts/introducing-reboot-notifier/)
 package comes in.
 
-Because that package will add a hook that will create the
-`/var/run/reboot-required` file whenever a kernel update has been installed,
-all you need to do is create a cronjob like this in
-`/etc/cron.daily/reboot-required`:
-
-    #!/bin/sh
-    cat /var/run/reboot-required 2> /dev/null || true
-
-assuming of course that you are already receiving emails sent to the root
+This assumes that you are already receiving emails sent to the root
 user (if not, add the appropriate alias in `/etc/aliases` and run
 `newaliases`).
 

Update mpd DB once an hour but check it's running first
By updating once an hour, I mostly avoid the need to trigger
updates manually.
diff --git a/posts/home-music-server-with-mpd.mdwn b/posts/home-music-server-with-mpd.mdwn
index 0cc4118..936154c 100644
--- a/posts/home-music-server-with-mpd.mdwn
+++ b/posts/home-music-server-with-mpd.mdwn
@@ -73,11 +73,11 @@ silence unnecessary log messages in
 and created a cronjob in `/etc/cron.d/mpd-francois` to update the database
 daily and stop the music automatically in the evening:
 
-    # Refresh DB once a day
-    5 1 * * *  mpd  MPD_HOST=Password1@/run/mpd/socket /usr/bin/mpc --quiet update
+    # Refresh DB once an hour
+    5 * * * *  mpd  MPD_HOST=Password1@/run/mpd/socket test -r /run/mpd/socket && /usr/bin/mpc --quiet update
     # Think of the neighbours
-    0 22 * * 0-4  mpd  MPD_HOST=Password1@/run/mpd/socket /usr/bin/mpc --quiet stop
-    0 23 * * 5-6  mpd  MPD_HOST=Password1@/run/mpd/socket /usr/bin/mpc --quiet stop
+    0 22 * * 0-4  mpd  MPD_HOST=Password1@/run/mpd/socket test -r /run/mpd/socket && /usr/bin/mpc --quiet stop
+    0 23 * * 5-6  mpd  MPD_HOST=Password1@/run/mpd/socket test -r /run/mpd/socket && /usr/bin/mpc --quiet stop
 
 # Clients
 

Comment moderation
diff --git a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot/comment_1_cc5c0c144345837437be6800303ae4f1._comment b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot/comment_1_cc5c0c144345837437be6800303ae4f1._comment
new file mode 100644
index 0000000..17134d5
--- /dev/null
+++ b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot/comment_1_cc5c0c144345837437be6800303ae4f1._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ ip="78.60.202.182"
+ claimedauthor="Marius Gedminas"
+ url="https://gedmin.as"
+ subject="Why stop Apache?"
+ date="2017-04-14T13:17:59Z"
+ content="""
+You could use the Apache or webroot plugins to do the renewals without stopping Apache.  Is there anything that prevents you from doing that?
+"""]]

Use systemctl instead of apache2ctl to restart Apache
diff --git a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
index d7521cf..cc0c5b1 100644
--- a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
+++ b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
@@ -13,7 +13,7 @@ Instead, this is the script I put in `/etc/cron.daily/certbot-renew`:
 
     #!/bin/bash
 
-    /usr/bin/certbot renew --quiet --pre-hook "/usr/sbin/apache2ctl stop" --post-hook "/usr/sbin/apache2ctl start"
+    /usr/bin/certbot renew --quiet --pre-hook "/bin/systemctl stop apache2.service" --post-hook "/bin/systemctl start apache2.service"
 
     pushd /etc/ > /dev/null
     /usr/bin/git add letsencrypt

Use pre and post hooks in certbot command
diff --git a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
index 6d2e7b8..d7521cf 100644
--- a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
+++ b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
@@ -13,9 +13,7 @@ Instead, this is the script I put in `/etc/cron.daily/certbot-renew`:
 
     #!/bin/bash
 
-    /usr/sbin/apache2ctl stop
-    /usr/bin/certbot renew --quiet
-    /usr/sbin/apache2ctl start
+    /usr/bin/certbot renew --quiet --pre-hook "/usr/sbin/apache2ctl stop" --post-hook "/usr/sbin/apache2ctl start"
 
     pushd /etc/ > /dev/null
     /usr/bin/git add letsencrypt
diff --git a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot/comment_1_75826e56fac368db2417030a76ea2fb4._comment b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot/comment_1_75826e56fac368db2417030a76ea2fb4._comment
deleted file mode 100644
index 771777e..0000000
--- a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot/comment_1_75826e56fac368db2417030a76ea2fb4._comment
+++ /dev/null
@@ -1,30 +0,0 @@
-[[!comment format=mdwn
- ip="93.139.219.66"
- claimedauthor="Ivan"
- url="https://www.tomica.me"
- subject="Cerbot options"
- date="2017-04-13T15:55:52Z"
- content="""
-There are 
-
-```
---pre-hook PRE_HOOK   Command to be run in a shell before obtaining any
-                        certificates. Intended primarily for renewal, where it
-                        can be used to temporarily shut down a webserver that
-                        might conflict with the standalone plugin. This will
-                        only be called if a certificate is actually to be
-                        obtained/renewed. When renewing several certificates
-                        that have identical pre-hooks, only the first will be
-                        executed. (default: None)
---post-hook POST_HOOK
-                        Command to be run in a shell after attempting to
-                        obtain/renew certificates. Can be used to deploy
-                        renewed certificates, or to restart any servers that
-                        were stopped by --pre-hook. This is only run if an
-                        attempt was made to obtain/renew a certificate. If
-                        multiple renewed certificates have identical post-
-                        hooks, only one will be run. (default: None)
-```
-
-command line options for certbot. Why not just use combination of those in cron job?
-"""]]

Comment moderation
diff --git a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot/comment_1_75826e56fac368db2417030a76ea2fb4._comment b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot/comment_1_75826e56fac368db2417030a76ea2fb4._comment
new file mode 100644
index 0000000..771777e
--- /dev/null
+++ b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot/comment_1_75826e56fac368db2417030a76ea2fb4._comment
@@ -0,0 +1,30 @@
+[[!comment format=mdwn
+ ip="93.139.219.66"
+ claimedauthor="Ivan"
+ url="https://www.tomica.me"
+ subject="Cerbot options"
+ date="2017-04-13T15:55:52Z"
+ content="""
+There are 
+
+```
+--pre-hook PRE_HOOK   Command to be run in a shell before obtaining any
+                        certificates. Intended primarily for renewal, where it
+                        can be used to temporarily shut down a webserver that
+                        might conflict with the standalone plugin. This will
+                        only be called if a certificate is actually to be
+                        obtained/renewed. When renewing several certificates
+                        that have identical pre-hooks, only the first will be
+                        executed. (default: None)
+--post-hook POST_HOOK
+                        Command to be run in a shell after attempting to
+                        obtain/renew certificates. Can be used to deploy
+                        renewed certificates, or to restart any servers that
+                        were stopped by --pre-hook. This is only run if an
+                        attempt was made to obtain/renew a certificate. If
+                        multiple renewed certificates have identical post-
+                        hooks, only one will be run. (default: None)
+```
+
+command line options for certbot. Why not just use combination of those in cron job?
+"""]]

creating tag page tags/letsencrypt
diff --git a/tags/letsencrypt.mdwn b/tags/letsencrypt.mdwn
new file mode 100644
index 0000000..0f54283
--- /dev/null
+++ b/tags/letsencrypt.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged letsencrypt"]]
+
+[[!inline pages="tagged(letsencrypt)" actions="no" archive="yes"
+feedshow=10]]

Add old articles to a new letsencrypt tag
diff --git a/posts/hiding-network-disconnections-using-irc-bouncer.mdwn b/posts/hiding-network-disconnections-using-irc-bouncer.mdwn
index 9600e75..b4b35ee 100644
--- a/posts/hiding-network-disconnections-using-irc-bouncer.mdwn
+++ b/posts/hiding-network-disconnections-using-irc-bouncer.mdwn
@@ -107,4 +107,4 @@ kernel update, I keep the bouncer running. At the end of the day, I say yes
 to killing the bouncer. That way, I don't have a backlog to go through when
 I wake up the next day.
 
-[[!tag mozilla]] [[!tag debian]] [[!tag irc]] [[!tag irssi]] [[!tag nzoss]]
+[[!tag mozilla]] [[!tag debian]] [[!tag irc]] [[!tag irssi]] [[!tag nzoss]] [[!tag letsencrypt]]
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index b79d687..7f904e9 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -181,4 +181,4 @@ Finally, to ensure that your TLS settings are reasonable, use this
 [automated tool](https://xmpp.net/) to test both the client-to-server (c2s)
 and the server-to-server (s2s) flows.
 
-[[!tag debian]] [[!tag ubuntu]] [[!tag nzoss]] [[!tag sysadmin]] [[!tag xmpp]]
+[[!tag debian]] [[!tag ubuntu]] [[!tag nzoss]] [[!tag sysadmin]] [[!tag xmpp]] [[!tag letsencrypt]]

Add letsencrypt renewal script
diff --git a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
new file mode 100644
index 0000000..6d2e7b8
--- /dev/null
+++ b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
@@ -0,0 +1,59 @@
+[[!meta title="Automatically renewing Let's Encrypt TLS certificates on Debian using Certbot"]]
+[[!meta date="2017-04-13T08:00:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+I use [Let's Encrypt](https://letsencrypt.org/)
+[TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security) certificates
+on my Debian servers along with the [Certbot](https://certbot.eff.org/)
+tool. Since I use the "temporary webserver" method of proving domain
+ownership via the [ACME protocol](https://ietf-wg-acme.github.io/acme/), I
+cannot use the cert renewal cronjob built into Certbot.
+
+Instead, this is the script I put in `/etc/cron.daily/certbot-renew`:
+
+    #!/bin/bash
+
+    /usr/sbin/apache2ctl stop
+    /usr/bin/certbot renew --quiet
+    /usr/sbin/apache2ctl start
+
+    pushd /etc/ > /dev/null
+    /usr/bin/git add letsencrypt
+    DIFFSTAT="$(/usr/bin/git diff --cached --stat)"
+    if [ -n "$DIFFSTAT" ] ; then
+        /usr/bin/git commit --quiet -m "Renewed letsencrypt certs"
+        echo "$DIFFSTAT"
+    fi
+    popd > /dev/null
+
+It temporarily disables my [Apache](https://httpd.apache.org/) webserver while it renews the
+certificates and then only outputs something to STDOUT (since my cronjob
+will email me any output) if certs have been renewed.
+
+Since I'm using [etckeeper](https://etckeeper.branchable.com/) to keep track of config changes on my
+servers, my renewal script also commits to the repository if any certs have
+changed.
+
+# External Monitoring
+
+In order to catch mistakes or oversights, I use
+[ssl-cert-check](https://packages.debian.org/stable/ssl-cert-check) to
+monitor my domains once a day:
+
+    ssl-cert-check -s fmarier.org -p 443 -q -a -e francois@fmarier.org
+
+I also signed up with [Cert Spotter](https://sslmate.com/certspotter/) which
+watches the
+[Certificate Transparency](https://www.certificate-transparency.org/) log
+and notifies me of any newly-issued certificates for my domains.
+
+In other words, I get notified:
+
+- if my cronjob fails and a cert is about to expire, or
+- as soon as a new cert is issued.
+
+The whole thing seems to work well, but if there's anything I could be doing
+better, feel free to leave a comment!
+
+[[!tag nzoss]] [[!tag sysadmin]] [[!tag debian]] [[!tag mozilla]]
+[[!tag ubuntu]] [[!tag ssl]] [[!tag apache]] [[!tag letsencrypt]]

How to reset the root password
diff --git a/posts/lxc-setup-on-debian-jessie.mdwn b/posts/lxc-setup-on-debian-jessie.mdwn
index c73f7c9..b46eab6 100644
--- a/posts/lxc-setup-on-debian-jessie.mdwn
+++ b/posts/lxc-setup-on-debian-jessie.mdwn
@@ -66,8 +66,13 @@ logins, so you'll need to log into the console:
     sudo lxc-stop -n sid64
     sudo lxc-start -n sid64 -F
 
-then install a text editor inside the container because the root image
-doesn't have one by default:
+Since the root password is randomly generated, you'll need to reset it before
+you can login as root:
+
+    sudo lxc-attach -n sid64 passwd
+
+Then login as root and install a text editor inside the container because the
+root image doesn't have one by default:
 
     apt install vim
 

Force foreground mode for console logins
The default seems to have changed to daemon mode so it's now necessary
to specify foreground mode to log into the console.
diff --git a/posts/lxc-setup-on-debian-jessie.mdwn b/posts/lxc-setup-on-debian-jessie.mdwn
index 37c83d2..c73f7c9 100644
--- a/posts/lxc-setup-on-debian-jessie.mdwn
+++ b/posts/lxc-setup-on-debian-jessie.mdwn
@@ -64,7 +64,7 @@ The ssh server is configured to require pubkey-based authentication for root
 logins, so you'll need to log into the console:
 
     sudo lxc-stop -n sid64
-    sudo lxc-start -n sid64
+    sudo lxc-start -n sid64 -F
 
 then install a text editor inside the container because the root image
 doesn't have one by default:

Add AppArmor and homedir mounting instructions
diff --git a/posts/lxc-setup-on-debian-jessie.mdwn b/posts/lxc-setup-on-debian-jessie.mdwn
index 087ad23..37c83d2 100644
--- a/posts/lxc-setup-on-debian-jessie.mdwn
+++ b/posts/lxc-setup-on-debian-jessie.mdwn
@@ -79,6 +79,19 @@ by typing this command:
 
     sudo lxc-ls --fancy
 
+# Mounting your home directory inside a container
+
+In order to have my home directory available within the container, I
+created a user account for myself inside the container and then added
+the following to the container config file (`/var/lib/lxc/sid64/config`):
+
+    lxc.mount.entry=/home/francois /var/lib/lxc/sid64/rootfs/home/francois none bind 0 0
+
+before restarting the container:
+
+    lxc-stop -n sid64
+    lxc-start -n sid64 -d
+
 # Fixing locale errors
 
 If you see a bunch of errors like these when you start your container:
@@ -123,4 +136,11 @@ and then start up it later once the locales have been updates:
     service apparmor start
     lxc-start -n sid64 -d
 
+# AppArmor support
+
+If you are running AppArmor, your container probably won't start until you
+add the following to the container config (`/var/lib/lxc/sid64/config`):
+
+    lxc.aa_allow_incomplete = 1
+
 [[!tag debian]] [[!tag lxc]] [[!tag nzoss]]

Add missing tag on RAID1 post
diff --git a/posts/manually-expanding-raid1-array-ubuntu.mdwn b/posts/manually-expanding-raid1-array-ubuntu.mdwn
index 8b77ed4..97712c6 100644
--- a/posts/manually-expanding-raid1-array-ubuntu.mdwn
+++ b/posts/manually-expanding-raid1-array-ubuntu.mdwn
@@ -148,4 +148,4 @@ The last step was to regenerate the initramfs:
 before rebooting into something that looks exactly like the original RAID1
 array but with twice the size.
 
-[[!tag nzoss]] [[!tag sysadmin]] [[!tag debian]] [[!tag raid]] [[!tag ubuntu]]
+[[!tag nzoss]] [[!tag sysadmin]] [[!tag debian]] [[!tag raid]] [[!tag ubuntu]] [[!tag luks]]

Add RAID expansion post
diff --git a/posts/manually-expanding-raid1-array-ubuntu.mdwn b/posts/manually-expanding-raid1-array-ubuntu.mdwn
new file mode 100644
index 0000000..8b77ed4
--- /dev/null
+++ b/posts/manually-expanding-raid1-array-ubuntu.mdwn
@@ -0,0 +1,151 @@
+[[!meta title="Manually expanding a RAID1 array on Ubuntu"]]
+[[!meta date="2017-03-31T23:00:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+Here are the notes I took while manually expanding an non-LVM encrypted
+RAID1 array on an Ubuntu machine.
+
+My original setup consisted of a 1 TB drive along with a 2 TB drive, which
+meant that the RAID1 array was 1 TB in size and the second drive had 1 TB of
+unused capacity. This is how I replaced the old 1 TB drive with a new 3 TB
+drive and expanded the RAID1 array to 2 TB (leaving 1 TB unused on the new 3
+TB drive).
+
+# Partition the new drive
+
+In order to partition the new 3 TB drive, I started by creating a
+**temporary partition** on the old 2 TB drive (`/dev/sdc`) to use up all of
+the capacity on that drive:
+
+    $ parted /dev/sdc
+    unit s
+    print
+    mkpart
+    print
+
+Then I initialized the partition table and creating the EFI partition
+partition on the new drive (`/dev/sdd`):
+
+    $ parted /dev/sdd
+    unit s
+    mktable gpt
+    mkpart
+
+Since I want to have the RAID1 array be as large as the smaller of the two
+drives, I made sure that the second partition (`/home`) on the
+new 3 TB drive had:
+
+- the same **start position** as the second partition on the old drive
+- the **end position** of the third partition (the temporary one I just
+  created) on the old drive
+
+I created the partition and flagged it as a RAID one:
+
+    mkpart
+    toggle 2 raid
+
+and then deleted the temporary partition on the old 2 TB drive:
+
+    $ parted /dev/sdc
+    print
+    rm 3
+    print
+
+# Create a temporary RAID1 array on the new drive
+
+With the new drive properly partitioned, I created a new RAID array for it:
+
+    mdadm /dev/md10 --create --level=1 --raid-devices=2 /dev/sdd1 missing
+
+and added it to `/etc/mdadm/mdadm.conf`:
+
+    mdadm --detail --scan >> /etc/mdadm/mdadm.conf
+
+which required manual editing of that file to remove duplicate entries.
+
+# Create the encrypted partition
+
+With the new RAID device in place, I created the encrypted LUKS partition:
+
+    cryptsetup -h sha256 -c aes-xts-plain64 -s 512 luksFormat /dev/md10
+    cryptsetup luksOpen /dev/md10 chome2
+
+I took the UUID for the temporary RAID partition:
+
+    blkid /dev/md10
+
+and put it in `/etc/crypttab` as `chome2`.
+
+Then, I formatted the new LUKS partition and mounted it:
+
+    mkfs.ext4 -m 0 /dev/mapper/chome2
+    mkdir /home2
+    mount /dev/mapper/chome2 /home2
+
+# Copy the data from the old drive
+
+With the home paritions of both drives mounted, I copied the files over to
+the new drive:
+
+    eatmydata nice ionice -c3 rsync -axHAX --progress /home/* /home2/
+
+making use of
+[wrappers that preserve system reponsiveness](https://feeding.cloud.geek.nz/posts/three-wrappers-to-run-commands-without-impacting-the-rest-of-the-system/)
+during I/O-intensive operations.
+
+# Switch over to the new drive
+
+After the copy, I switched over to the new drive in a step-by-step way:
+
+1. Changed the UUID of `chome` in `/etc/crypttab`.
+2. Changed the UUID and name of `/dev/md1` in `/etc/mdadm/mdadm.conf`.
+3. Rebooted with both drives.
+4. Checked that the new drive was the one used in the encrypted `/home` mount using: `df -h`.
+
+
+# Add the old drive to the new RAID array
+
+With all of this working, it was time to clear the mdadm superblock from the
+old drive:
+
+    mdadm --zero-superblock /dev/sdc1
+
+and then change the second partition of the old drive to make it the same
+size as the one on the new drive:
+
+    $ parted /dev/sdc
+    rm 2
+    mkpart
+    toggle 2 raid
+    print
+
+before adding it to the new array:
+
+    mdadm /dev/md1 -a /dev/sdc1
+
+# Rename the new array
+
+To
+[change the name of the new RAID array](https://askubuntu.com/questions/63980/how-do-i-rename-an-mdadm-raid-array#64356)
+back to what it was on the old drive, I first had to stop both the old and
+the new RAID arrays:
+
+    umount /home
+    cryptsetup luksClose chome
+    mdadm --stop /dev/md10
+    mdadm --stop /dev/md1
+
+before running this command:
+
+    mdadm --assemble /dev/md1 --name=mymachinename:1 --update=name /dev/sdd2
+
+and updating the name in `/etc/mdadm/mdadm.conf`.
+
+The last step was to regenerate the initramfs:
+
+    update-initramfs -u
+
+before rebooting into something that looks exactly like the original RAID1
+array but with twice the size.
+
+[[!tag nzoss]] [[!tag sysadmin]] [[!tag debian]] [[!tag raid]] [[!tag ubuntu]]

Remove unnecessary grep.
Thanks to Carlos Eduardo Moreira dos Santos for pointing that out.
diff --git a/posts/creating-a-modern-tiling-desktop-environment-using-i3.mdwn b/posts/creating-a-modern-tiling-desktop-environment-using-i3.mdwn
index 3d288c0..1c3e781 100644
--- a/posts/creating-a-modern-tiling-desktop-environment-using-i3.mdwn
+++ b/posts/creating-a-modern-tiling-desktop-environment-using-i3.mdwn
@@ -92,7 +92,7 @@ A few applications make too many assumptions about window placement and are just
 
 You can get the Xorg class of the offending application by running this command:
 
-    xprop | grep WM_CLASS
+    xprop WM_CLASS
 
 before clicking on the window.
 

Link to Matt Might's article on using Tor while reviewing papers
diff --git a/posts/things-that-work-well-with-tor.mdwn b/posts/things-that-work-well-with-tor.mdwn
index ce3afd6..1885807 100644
--- a/posts/things-that-work-well-with-tor.mdwn
+++ b/posts/things-that-work-well-with-tor.mdwn
@@ -9,7 +9,9 @@ connections, an unfortunate performance-privacy trade-off which means that
 few users choose to do all of their browsing through Tor.
 
 Here are a few things that I have found work quite well through Tor. If
-there are any other interesting use cases I've missed, please leave a comment!
+there are any other interesting use cases I've missed (e.g.
+[reviewing academic papers](http://matt.might.net/articles/why-peer-reviewers-should-use-tor/)),
+please leave a comment!
 
 # Tor setup
 

Move all sidebar links to HTTPS
diff --git a/sidebar.mdwn b/sidebar.mdwn
index 48e4aa6..463ac41 100644
--- a/sidebar.mdwn
+++ b/sidebar.mdwn
@@ -1,20 +1,20 @@
 # Subscribe to this blog
 
-<a href="http://feeding.cloud.geek.nz/index.rss"><img src="/feed-icon.png" height="32" width="32" align="left">Subscribe in a reader</a>
-[Subscribe by Email](http://www.feedburner.com/fb/a/emailverifySubmit?feedId=1839853&loc=en_US)
+<a href="https://feeding.cloud.geek.nz/index.rss"><img src="/feed-icon.png" height="32" width="32" align="left">Subscribe in a reader</a>
+[Subscribe by Email](https://www.feedburner.com/fb/a/emailverifySubmit?feedId=1839853&loc=en_US)
 
-<br><a href="http://flattr.com/thing/311291/Feeding-the-Cloud"><img src="/flattr_button.png" border="0" alt="Flattr" width="93" height="20"></a>
+<br><a href="https://flattr.com/thing/311291/Feeding-the-Cloud"><img src="/flattr_button.png" border="0" alt="Flattr" width="93" height="20"></a>
 
 # About me
 
-<a href="http://fmarier.org"><img src="/avatar.jpg" width="80" height="80">
+<a href="https://fmarier.org"><img src="/avatar.jpg" width="80" height="80">
 
 **François Marier**</a>
 <br><a href="mailto:francois@fmarier.org">francois@fmarier.org</a>
 <br>Free and Open Source software developer
 <br>
-<br>[Twitter](https://twitter.com/fmarier) / [Identica](http://identi.ca/fmarier)
-<br>[Linked In](http://linkedin.com/in/fmarier)
+<br>[Twitter](https://twitter.com/fmarier) / [Identica](https://identi.ca/fmarier)
+<br>[Linked In](https://linkedin.com/in/fmarier)
 
 # More from this blog
 

creating tag page tags/ipv6
diff --git a/tags/ipv6.mdwn b/tags/ipv6.mdwn
new file mode 100644
index 0000000..50751c3
--- /dev/null
+++ b/tags/ipv6.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged ipv6"]]
+
+[[!inline pages="tagged(ipv6)" actions="no" archive="yes"
+feedshow=10]]

Add post on IPv6 and OpenVPN
diff --git a/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu.mdwn b/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu.mdwn
index 4fe6c9c..fd98016 100644
--- a/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu.mdwn
+++ b/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu.mdwn
@@ -105,7 +105,7 @@ and set the following in `/etc/openvpn/server.conf` (which includes recommendati
 
 Finally, I added the following to these configuration files:
 
-* `/etc/sysctl.conf`:
+* `/etc/sysctl.d/openvpn.conf`:
 
       net.ipv4.ip_forward=1
 
@@ -189,8 +189,12 @@ usually enough to solve the problem.
 
 # Next steps
 
+With the basics working, you could now
+[add support for IPv6](https://feeding.cloud.geek.nz/posts/ipv6-and-openvpn-on-linode/)
+to your VPN.
+
 The next thing I'm going to add to this VPN setup is a
-[local unbound DNS resolver](http://feeding.cloud.geek.nz/posts/setting-up-your-own-dnssec-aware/)
+[local unbound DNS resolver](https://feeding.cloud.geek.nz/posts/setting-up-your-own-dnssec-aware/)
 that will be offered to all clients.
 
 Is there anything else you have in your setup and that I should consider
diff --git a/posts/ipv6-and-openvpn-on-linode.mdwn b/posts/ipv6-and-openvpn-on-linode.mdwn
new file mode 100644
index 0000000..f118113
--- /dev/null
+++ b/posts/ipv6-and-openvpn-on-linode.mdwn
@@ -0,0 +1,132 @@
+[[!meta title="IPv6 and OpenVPN on Linode Debian/Ubuntu VPS"]]
+[[!meta date="2017-02-05T21:20:00.000+08:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+Here is how I managed to extend my
+[OpenVPN setup on my Linode VPS](https://feeding.cloud.geek.nz/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu/)
+to include [IPv6](https://community.openvpn.net/openvpn/wiki/IPv6) traffic.
+This ensures that clients can route all of their traffic through the VPN and
+avoid leaking IPv6 traffic, for example. It also enables clients on
+IPv4-only networks to receive a routable IPv6 address and connect to
+[IPv6-only servers](https://ipv6.google.com) (i.e. running your own IPv6 broker).
+
+# Request an additional IPv6 block
+
+The first thing you need to do is get a new IPv6 address block (or "pool" as
+Linode calls it) from which you can allocate a single address to each VPN
+client that connects to the server.
+
+If you are using a
+[Linode VPS](https://www.linode.com/?r=4f882417aa3809652b227d6d9c25b2a0472c6cff),
+there are
+[instructions on how to request a new IPv6 pool](https://www.linode.com/docs/networking/native-ipv6-networking#additional-ipv6-addresses).
+Note that you need to get an address block **between `/64` and `/112`**. A
+`/116` like Linode offers won't work in [OpenVPN](https://openvpn.net/). Thankfully, Linode
+is happy to allocate you an extra `/64` for free.
+
+# Setup the new IPv6 address
+
+If your server only has an single IPv4 address and a single IPv6 address,
+then a simple DHCP-backed network configuration will work fine.
+To add the second IPv6 block on the other hand, I had to change my network
+configuration (`/etc/network/interfaces`) to this:
+
+    auto lo
+    iface lo inet loopback
+    
+    allow-hotplug eth0
+    iface eth0 inet dhcp
+    	pre-up iptables-restore /etc/network/iptables.up.rules
+    
+    iface eth0 inet6 static
+    	address 2600:3c01::xxxx:xxxx:xxxx:939f/64
+    	gateway fe80::1
+    	pre-up ip6tables-restore /etc/network/ip6tables.up.rules
+    
+    iface tun0 inet6 static
+    	address 2600:3c01:xxxx:xxxx::/64
+    	pre-up ip6tables-restore /etc/network/ip6tables.up.rules
+
+where `2600:3c01::xxxx:xxxx:xxxx:939f/64` (bound to `eth0`) is your main
+IPv6 address and
+`2600:3c01:xxxx:xxxx::/64` (bound to `tun0`) is the new block you
+requested.
+
+Once you've setup the new IPv6 block, test it from another IPv6-enabled host
+using:
+
+    ping6 2600:3c01:xxxx:xxxx::1
+
+# OpenVPN configuration
+
+The only thing I had to change in my
+[OpenVPN configuration](https://feeding.cloud.geek.nz/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu/)
+(`/etc/openvpn/server.conf`) was to change:
+
+    proto udp
+
+to:
+
+    proto udp6
+
+in order to make the VPN server
+[available over both IPv4 and IPv6](https://serverfault.com/questions/651832/openvpn-with-mixed-ipv4-and-ipv6-clients),
+and to add the following lines:
+
+    server-ipv6 2600:3c01:xxxx:xxxx::/64
+    push "route-ipv6 2000::/3"
+
+to bind to the right V6 address and to tell clients to tunnel all V6 Internet
+traffic through the VPN.
+
+In addition to updating the OpenVPN config, you will need to add the
+following line to `/etc/sysctl.d/openvpn.conf`:
+
+    net.ipv6.conf.all.forwarding=1
+
+and the following to your firewall (e.g. `/etc/network/ip6tables.up.rules`):
+ 
+    # openvpn
+    -A INPUT -p udp --dport 1194 -j ACCEPT
+    -A FORWARD -m state --state NEW -i tun0 -o eth0 -s 2600:3c01:xxxx:xxxx::/64 -j ACCEPT
+    -A FORWARD -m state --state NEW -i eth0 -o tun0 -d 2600:3c01:xxxx:xxxx::/64 -j ACCEPT
+    -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
+
+in order to ensure that
+[IPv6 packets are forwarded from the `eth0` network interface to `tun0`](https://unix.stackexchange.com/questions/170598/openvpn-using-ipv6-on-vps/187867#187867)
+on the VPN server.
+
+With all of this done, apply the settings by running:
+
+    sysctl -p /etc/sysctl.d/openvpn.conf
+    ip6tables-apply
+    systemctl restart openvpn.service
+
+# Testing the connection
+
+Now connect to the VPN using your desktop client and check that the default
+IPv6 route is set correctly using `ip -6 route`.
+
+Then you can ping the server's new IP address:
+
+    ping6 2600:3c01:xxxx:xxxx::1
+
+and from the server, you can ping the client's IP (which you can see in the
+network settings):
+
+    ping6 2600:3c01:xxxx:xxxx::1002
+
+Once both ends of the tunnel can talk to each other, you can try pinging an
+IPv6-only server from your client:
+
+    ping6 ipv6.google.com
+
+and then pinging your client from an IPv6-enabled host somewhere:
+
+    ping6 2600:3c01:xxxx:xxxx::1002
+
+If that works, other [online](http://test-ipv6.com/)
+[tests](http://ipv6-test.com/) should also work.
+
+[[!tag ipv6]] [[!tag debian]] [[!tag ubuntu]] [[!tag nzoss]] [[!tag sysadmin]] [[!tag openvpn]]
+

Stop linking to EntropyKey since that hardware hasn't been available in years
diff --git a/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu.mdwn b/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu.mdwn
index a7c7b16..4fe6c9c 100644
--- a/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu.mdwn
+++ b/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu.mdwn
@@ -27,8 +27,8 @@ doesn't seem work on Linode or Rackspace virtual servers.
 # Generating the keys
 
 Make sure you run the following on a machine with good entropy and not a VM!
-I personally use a machine fitted with an
-[Entropy Key](http://www.entropykey.co.uk/).
+I personally use a machine fitted with a
+[Chaos Key](http://shop.gag.com/logo-items/chaoskey.html).
 
 The first step is to install the required package:
 
diff --git a/posts/raid1-alternative-for-ssd-drives.mdwn b/posts/raid1-alternative-for-ssd-drives.mdwn
index e526408..e7f2eb5 100644
--- a/posts/raid1-alternative-for-ssd-drives.mdwn
+++ b/posts/raid1-alternative-for-ssd-drives.mdwn
@@ -50,7 +50,7 @@ Finally, after reading this [excellent LWN article](http://lwn.net/Articles/4084
       echo noop &gt; /sys/block/<i>sda</i>/queue/scheduler
       echo 1 &gt; /sys/block/<i>sda</i>/queue/iosched/fifo_batch
 
-* Turn off [entropy gathering](http://www.entropykey.co.uk/) (for kernels 2.6.36 or later) by adding this line to `/etc/rc.local`:
+* Turn off entropy gathering (for kernels 2.6.36 or later) by adding this line to `/etc/rc.local`:
 
       echo 0 &gt; /sys/block/<i>sda</i>/queue/add_random
   

creating tag page tags/osx
diff --git a/tags/osx.mdwn b/tags/osx.mdwn
new file mode 100644
index 0000000..d44622e
--- /dev/null
+++ b/tags/osx.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged osx"]]
+
+[[!inline pages="tagged(osx)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/mpd
diff --git a/tags/mpd.mdwn b/tags/mpd.mdwn
new file mode 100644
index 0000000..dd1601c
--- /dev/null
+++ b/tags/mpd.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged mpd"]]
+
+[[!inline pages="tagged(mpd)" actions="no" archive="yes"
+feedshow=10]]

creating tag page tags/ios
diff --git a/tags/ios.mdwn b/tags/ios.mdwn
new file mode 100644
index 0000000..ef17645
--- /dev/null
+++ b/tags/ios.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged ios"]]
+
+[[!inline pages="tagged(ios)" actions="no" archive="yes"
+feedshow=10]]

Add a post about mpd
diff --git a/posts/home-music-server-with-mpd.mdwn b/posts/home-music-server-with-mpd.mdwn
new file mode 100644
index 0000000..0cc4118
--- /dev/null
+++ b/posts/home-music-server-with-mpd.mdwn
@@ -0,0 +1,135 @@
+[[!meta title="Creating a home music server using mpd"]]
+[[!meta date="2017-01-29T22:20:00.000-08:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+I recently setup a music server on my home server using the [Music Player
+Daemon](https://www.musicpd.org/), a cross-platform [free
+software](https://www.gnu.org/philosophy/free-sw.html) project which has
+been around for a long time.
+
+# Basic setup
+
+Start by installing the server and the client package:
+
+    apt install mpd mpc
+
+then open `/etc/mpd.conf` and set these:
+
+    music_directory    "/path/to/music/"
+    bind_to_address    "192.168.1.2"
+    bind_to_address    "/run/mpd/socket"
+    zeroconf_enabled   "yes"
+    password           "Password1"
+
+before replacing the alsa output:
+
+    audio_output {
+       type    "alsa"
+       name    "My ALSA Device"
+    }
+
+with a pulseaudio one:
+
+    audio_output {
+       type    "pulse"
+       name    "Pulseaudio Output"
+    }
+
+In order for the automatic detection (zeroconf) of your music server
+to work, you need to [prevent systemd from creating the network
+socket](https://www.mail-archive.com/mpd-devel@musicpd.org/msg00239.html):
+
+    systemctl stop mpd.service
+    systemctl stop mpd.socket
+    systemctl disable mpd.socket
+
+otherwise you'll see this in `/var/log/mpd/mpd.log`:
+
+    zeroconf: No global port, disabling zeroconf
+
+Once all of that is in place, start the mpd daemon:
+
+    systemctl start mpd.service
+
+and create an index of your music files:
+
+    MPD_HOST=Password1@/run/mpd/socket mpc update
+
+while watching the logs to notice any files that the mpd user doesn't have
+access to:
+
+    tail -f /var/log/mpd/mpd.log
+
+# Enhancements
+
+I also added the following in `/etc/logcheck/ignore.server.d/local-mpd` to
+silence unnecessary log messages in
+[logcheck](https://packages.debian.org/stable/logcheck) emails:
+
+    ^\w{3} [ :0-9]{11} [._[:alnum:]-]+ systemd\[1\]: Started Music Player Daemon.$
+    ^\w{3} [ :0-9]{11} [._[:alnum:]-]+ systemd\[1\]: Stopped Music Player Daemon.$
+    ^\w{3} [ :0-9]{11} [._[:alnum:]-]+ systemd\[1\]: Stopping Music Player Daemon...$
+
+and created a cronjob in `/etc/cron.d/mpd-francois` to update the database
+daily and stop the music automatically in the evening:
+
+    # Refresh DB once a day
+    5 1 * * *  mpd  MPD_HOST=Password1@/run/mpd/socket /usr/bin/mpc --quiet update
+    # Think of the neighbours
+    0 22 * * 0-4  mpd  MPD_HOST=Password1@/run/mpd/socket /usr/bin/mpc --quiet stop
+    0 23 * * 5-6  mpd  MPD_HOST=Password1@/run/mpd/socket /usr/bin/mpc --quiet stop
+
+# Clients
+
+To let anybody on the local network connect, I opened **port 6600** on the
+firewall (`/etc/network/iptables.up.rules` since I'm using Debian's
+`iptables-apply`):
+
+    -A INPUT -s 192.168.1.0/24 -p tcp --dport 6600 -j ACCEPT
+
+Then I looked at [the long list of clients](http://mpd.wikia.com/wiki/Clients) on the mpd wiki.
+
+## Desktop
+
+The official website [suggests two
+clients](https://www.musicpd.org/clients/) which are available in Debian and
+Ubuntu:
+
+- [Ario](http://ario-player.sourceforge.net/) (`apt install ario`)
+- [GNOME Music Player Client](http://gmpclient.org/) (`apt install gmpc gmpc-plugins`)
+
+Both of them work well, but haven't had a release since 2011, even though
+there is some activity
+in [2013](https://sourceforge.net/p/ario-player/code/HEAD/tree/)
+and [2015](http://repo.or.cz/w/gmpc.git) in their respective source control
+repositories.
+
+Ario has a simpler user interface but gmpc has cover art download
+working out of the box, which is why I might stick with it.
+
+In both cases, it is possible to [configure a polipo
+proxy](https://feeding.cloud.geek.nz/posts/things-that-work-well-with-tor/)
+so that any external resources are fetched via
+[Tor](https://www.torproject.org/).
+
+## Android
+
+On Android, I got these two to work:
+
+- [M.A.L.P.](https://f-droid.org/repository/browse/?fdfilter=malp&fdid=org.gateshipone.malp) (requires Android 5 or later)
+- [MPDroid](https://f-droid.org/repository/browse/?fdfilter=mpdroid&fdid=com.namelessdev.mpdroid)
+
+I picked M.A.L.P. since it includes a nice widget for the homescreen.
+
+## iOS
+
+On iOS, these are the most promising clients I found:
+
+- [MPDRemote](https://github.com/Nyx0uf/MPDRemote) (free software, not on the AppStore)
+- [MPDluxe](http://kineticfactory.com/MPDluxe/) (proprietary, sold on the [AppStore](https://itunes.apple.com/app/mpdluxe/id991758069?mt=8))
+
+since [MPoD](http://www.katoemba.net/makesnosenseatall/mpod/) and
+[MPaD](http://www.katoemba.net/makesnosenseatall/mpad/) don't appear to be
+available on the AppStore anymore.
+
+[[!tag debian]] [[!tag ubuntu]] [[!tag nzoss]] [[!tag mpd]] [[!tag ios]] [[!tag android]] [[!tag tor]]

Create ios and osx tags
diff --git a/posts/using-openvpn-on-ios-and-osx.mdwn b/posts/using-openvpn-on-ios-and-osx.mdwn
index c5e7641..d104815 100644
--- a/posts/using-openvpn-on-ios-and-osx.mdwn
+++ b/posts/using-openvpn-on-ios-and-osx.mdwn
@@ -95,4 +95,4 @@ connection:
          cipher AES-256-CBC
          auth SHA384
 
-[[!tag openvpn]]
+[[!tag openvpn]] [[!tag ios]] [[!tag osx]]

Fix formatting of preformatted text in bullets
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index 7960266..b79d687 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -92,7 +92,7 @@ permissions correctly:
       chown root:ejabberd /etc/ejabberd/ejabberd.pem
       chmod 640 /etc/ejabberd/ejabberd.pem
 
-3. [Improve](https://bettercrypto.org/) the client-to-server TLS configuration
+4. [Improve](https://bettercrypto.org/) the client-to-server TLS configuration
 by adding `starttls_required` to this block:
 
       listen:
@@ -124,27 +124,24 @@ by adding `starttls_required` to this block:
       s2s_dhfile: /etc/ssl/ejabberd/dh2048.pem
       s2s_ciphers: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
 
-4. Create the required dh2048.pem file:
+5. Create the required dh2048.pem file:
 
-      openssl dhparam -out /etc/ssl/ejabberd/dh2048.pem 2048
+       openssl dhparam -out /etc/ssl/ejabberd/dh2048.pem 2048
 
-5. Restart the ejabberd
-daemon:
+6. Restart the ejabberd daemon:
 
-      /etc/init.d/ejabberd restart
+       /etc/init.d/ejabberd restart
 
-6. Create a new user account for
-yourself:
+7. Create a new user account for yourself:
 
-      ejabberdctl register me fmarier.org P@ssw0rd1!
+       ejabberdctl register me fmarier.org P@ssw0rd1!
 
-7. Open up the following ports on the server's
-firewall:
+8. Open up the following ports on the server's firewall:
 
-      iptables -A INPUT -p tcp --dport 5222 -j ACCEPT
-      iptables -A INPUT -p tcp --dport 5269 -j ACCEPT
+       iptables -A INPUT -p tcp --dport 5222 -j ACCEPT
+       iptables -A INPUT -p tcp --dport 5269 -j ACCEPT
 
-8. Optionally create a cronjob in `/etc/cron.d/restart-ejabberd`
+9. Optionally create a cronjob in `/etc/cron.d/restart-ejabberd`
 to restart ejabberd once a day to ensure it doesn't stop responding
 to requests after running for a while:
 

Add a step to generate the DH parameters
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index 4198b90..7960266 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -124,23 +124,27 @@ by adding `starttls_required` to this block:
       s2s_dhfile: /etc/ssl/ejabberd/dh2048.pem
       s2s_ciphers: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
 
-4. Restart the ejabberd
+4. Create the required dh2048.pem file:
+
+      openssl dhparam -out /etc/ssl/ejabberd/dh2048.pem 2048
+
+5. Restart the ejabberd
 daemon:
 
       /etc/init.d/ejabberd restart
 
-5. Create a new user account for
+6. Create a new user account for
 yourself:
 
       ejabberdctl register me fmarier.org P@ssw0rd1!
 
-6. Open up the following ports on the server's
+7. Open up the following ports on the server's
 firewall:
 
       iptables -A INPUT -p tcp --dport 5222 -j ACCEPT
       iptables -A INPUT -p tcp --dport 5269 -j ACCEPT
 
-7. Optionally create a cronjob in `/etc/cron.d/restart-ejabberd`
+8. Optionally create a cronjob in `/etc/cron.d/restart-ejabberd`
 to restart ejabberd once a day to ensure it doesn't stop responding
 to requests after running for a while:
 

Mention client-side firewalls too
diff --git a/posts/setting-up-a-network-scanner-using-sane.mdwn b/posts/setting-up-a-network-scanner-using-sane.mdwn
index 6aca75b..ca2e320 100644
--- a/posts/setting-up-a-network-scanner-using-sane.mdwn
+++ b/posts/setting-up-a-network-scanner-using-sane.mdwn
@@ -92,6 +92,11 @@ On the client, all you need to do is add the following to
 
 where `myserver` is the hostname or IP address of the server running saned.
 
+If you have a firewall runnning on the client, make sure you allow
+SANE traffic from the server:
+
+    -A INPUT -s 192.168.1.2 -p tcp --sport 6566  -j ACCEPT
+
 # Test the scanner remotely
 
 With everything in place, you should be able to see the scanner from the

creating tag page tags/luks
diff --git a/tags/luks.mdwn b/tags/luks.mdwn
new file mode 100644
index 0000000..396a5a6
--- /dev/null
+++ b/tags/luks.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged luks"]]
+
+[[!inline pages="tagged(luks)" actions="no" archive="yes"
+feedshow=10]]

Create a "luks" tag for encrypted partition posts
diff --git a/posts/encrypted-swap-partition-on.mdwn b/posts/encrypted-swap-partition-on.mdwn
index 0056255..a3b2712 100644
--- a/posts/encrypted-swap-partition-on.mdwn
+++ b/posts/encrypted-swap-partition-on.mdwn
@@ -33,4 +33,4 @@ You will of course want to replace `/dev/hda2` with the partition that currently
 (This is loosely based on a similar [procedure for Ubuntu 6.10](http://www.c3l.de/linux/howto-completly-encrypted-harddisk-including-suspend-to-encrypted-disk-with-ubuntu-6.10-edgy-eft.html).)
 
 
-[[!tag debian]] [[!tag security]] [[!tag ubuntu]] 
+[[!tag debian]] [[!tag security]] [[!tag ubuntu]] [[!tag luks]]
diff --git a/posts/encrypting-your-home-directory-using.mdwn b/posts/encrypting-your-home-directory-using.mdwn
index 6dc311d..96873ba 100644
--- a/posts/encrypting-your-home-directory-using.mdwn
+++ b/posts/encrypting-your-home-directory-using.mdwn
@@ -42,4 +42,4 @@ If you happen to have `/home` on a separate partition already (`/dev/sda5` in th
 That's it. Now to fully secure your laptop against theft, you should think about an [encrypted backup strategy](http://packages.debian.org/sid/duplicity) for your data...
 
 
-[[!tag debian]] [[!tag sysadmin]] [[!tag ubuntu]]
+[[!tag debian]] [[!tag sysadmin]] [[!tag ubuntu]] [[!tag luks]]
diff --git a/posts/poor-mans-raid1-between-ssd-and-hard-drive.mdwn b/posts/poor-mans-raid1-between-ssd-and-hard-drive.mdwn
index ba053e7..a36683d 100644
--- a/posts/poor-mans-raid1-between-ssd-and-hard-drive.mdwn
+++ b/posts/poor-mans-raid1-between-ssd-and-hard-drive.mdwn
@@ -111,4 +111,4 @@ The sync scripts are run every couple of hours through this crontab:
 which includes a reduced frequency while running on battery to avoid
 spinning the hard drive up too much.
 
-[[!tag debian]] [[!tag nzoss]] [[!tag raid]]
+[[!tag debian]] [[!tag nzoss]] [[!tag raid]] [[!tag luks]]

Include my polipo config in full
Not only has the file been removed by the torproject, but it has also apparently
been purged from the git history.
diff --git a/posts/things-that-work-well-with-tor.mdwn b/posts/things-that-work-well-with-tor.mdwn
index 269a88f..ce3afd6 100644
--- a/posts/things-that-work-well-with-tor.mdwn
+++ b/posts/things-that-work-well-with-tor.mdwn
@@ -20,8 +20,38 @@ around is quite useful for those applications that support HTTP
 proxies but not [SOCKS](https://en.wikipedia.org/wiki/SOCKS) proxies.
 
 On Debian, it's just a matter of installing the
-[polipo](http://packages.debian.org/wheezy/polipo) package and then
-configuring it as [it used to be recommended by the Tor project](https://gitweb.torproject.org/torbrowser.git/blob/21e3c22670f0ceb1760b3403ff1a217301112e9d:/build-scripts/config/polipo.conf).
+[polipo](http://packages.debian.org/stable/polipo) package and then
+setting the following in `/etc/polipo/config`:
+
+    logSyslog = true
+    logFile = /var/log/polipo/polipo.log
+    
+    # Configure polipo for use with tor
+    proxyAddress = "127.0.0.1"
+    proxyPort = 8008
+    allowedClients = 127.0.0.1
+    allowedPorts = 1-65535
+    proxyName = "localhost"
+    cacheIsShared = false
+    socksParentProxy = "localhost:9050"
+    socksProxyType = socks5
+    chunkHighMark = 67108864
+    diskCacheRoot = ""
+    localDocumentRoot = ""
+    disableLocalInterface = true
+    disableConfiguration = true
+    dnsQueryIPv6 = no
+    dnsUseGethostbyname = yes
+    disableVia = true
+    censoredHeaders = from,accept-language,x-pad,link
+    censorReferer = maybe
+    
+    # Suggestions from Incognito configuration
+    maxConnectionAge = 5m
+    maxConnectionRequests = 120
+    serverMaxSlots = 8
+    serverSlots = 2
+    tunnelAllowedPorts = 1-65535
 
 # RSS feeds
 

Comment moderation
diff --git a/posts/using-dnssec-and-dnscrypt-in-debian/comment_6_fbbd5eda44b6a20fe2e893ca761feffe._comment b/posts/using-dnssec-and-dnscrypt-in-debian/comment_6_fbbd5eda44b6a20fe2e893ca761feffe._comment
new file mode 100644
index 0000000..5919faf
--- /dev/null
+++ b/posts/using-dnssec-and-dnscrypt-in-debian/comment_6_fbbd5eda44b6a20fe2e893ca761feffe._comment
@@ -0,0 +1,11 @@
+[[!comment format=txt
+ ip="163.172.62.104"
+ subject="comment 6"
+ date="2017-01-11T01:32:33Z"
+ content="""
+@Jonathan
+
+Because programs other than browsers use dns.
+
+Or maybe because you do local dns lookups while using a socks proxy for the https requests.
+"""]]

calendar update
diff --git a/archives/2017.mdwn b/archives/2017.mdwn
new file mode 100644
index 0000000..592399b
--- /dev/null
+++ b/archives/2017.mdwn
@@ -0,0 +1 @@
+[[!calendar type=year year=2017 pages="page(posts/*) and !*/Discussion"]]
diff --git a/archives/2017/01.mdwn b/archives/2017/01.mdwn
new file mode 100644
index 0000000..2441b7a
--- /dev/null
+++ b/archives/2017/01.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=01 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(01) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/02.mdwn b/archives/2017/02.mdwn
new file mode 100644
index 0000000..e295fbe
--- /dev/null
+++ b/archives/2017/02.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=02 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(02) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/03.mdwn b/archives/2017/03.mdwn
new file mode 100644
index 0000000..6c05242
--- /dev/null
+++ b/archives/2017/03.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=03 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(03) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/04.mdwn b/archives/2017/04.mdwn
new file mode 100644
index 0000000..76e7c08
--- /dev/null
+++ b/archives/2017/04.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=04 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(04) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/05.mdwn b/archives/2017/05.mdwn
new file mode 100644
index 0000000..678f63a
--- /dev/null
+++ b/archives/2017/05.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=05 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(05) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/06.mdwn b/archives/2017/06.mdwn
new file mode 100644
index 0000000..2887ab6
--- /dev/null
+++ b/archives/2017/06.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=06 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(06) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/07.mdwn b/archives/2017/07.mdwn
new file mode 100644
index 0000000..0f746b9
--- /dev/null
+++ b/archives/2017/07.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=07 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(07) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/08.mdwn b/archives/2017/08.mdwn
new file mode 100644
index 0000000..4da2722
--- /dev/null
+++ b/archives/2017/08.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=08 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(08) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/09.mdwn b/archives/2017/09.mdwn
new file mode 100644
index 0000000..70f5e1d
--- /dev/null
+++ b/archives/2017/09.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=09 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(09) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/10.mdwn b/archives/2017/10.mdwn
new file mode 100644
index 0000000..04f5435
--- /dev/null
+++ b/archives/2017/10.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=10 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(10) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/11.mdwn b/archives/2017/11.mdwn
new file mode 100644
index 0000000..fe53f8d
--- /dev/null
+++ b/archives/2017/11.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=11 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(11) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2017/12.mdwn b/archives/2017/12.mdwn
new file mode 100644
index 0000000..bb4a435
--- /dev/null
+++ b/archives/2017/12.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=12 year=2017 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(12) and creation_year(2017) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]

creating tag page tags/iptables
diff --git a/tags/iptables.mdwn b/tags/iptables.mdwn
new file mode 100644
index 0000000..9a0031d
--- /dev/null
+++ b/tags/iptables.mdwn
@@ -0,0 +1,4 @@
+[[!meta title="pages tagged iptables"]]
+
+[[!inline pages="tagged(iptables)" actions="no" archive="yes"
+feedshow=10]]

Add a new iptables and NetworkManager post
diff --git a/posts/using-iptables-with-network-manager.mdwn b/posts/using-iptables-with-network-manager.mdwn
new file mode 100644
index 0000000..92a21d8
--- /dev/null
+++ b/posts/using-iptables-with-network-manager.mdwn
@@ -0,0 +1,62 @@
+[[!meta title="Using iptables with NetworkManager"]]
+[[!meta date="2016-12-26T17:05:00.000-05:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+I used to rely on [ifupdown](https://packages.debian.org/stable/ifupdown) to
+bring up my [iptables](https://packages.debian.org/stable/iptables) firewall
+automatically using a config like this in `/etc/network/interfaces`:
+
+    allow-hotplug eth0
+    iface eth0 inet dhcp
+        pre-up /sbin/iptables-restore /etc/network/iptables.up.rules
+        pre-up /sbin/ip6tables-restore /etc/network/ip6tables.up.rules
+
+    allow-hotplug wlan0
+    iface wlan0 inet dhcp
+        pre-up /sbin/iptables-restore /etc/network/iptables.up.rules
+        pre-up /sbin/ip6tables-restore /etc/network/ip6tables.up.rules
+
+but that doesn't seem to work very well in the brave new
+[NetworkManager](https://wiki.gnome.org/Projects/NetworkManager/)
+world.
+
+What does work reliably is a "pre-up" NetworkManager script, something
+that gets run before a network interface is brought up. However,
+despite what the
+[documentation](https://developer.gnome.org/NetworkManager/unstable/NetworkManager.html)
+says, a dispatcher script in `/etc/NetworkManager/dispatched.d/` won't
+work on my Debian and Ubuntu machines. Instead, I had to create a new
+`iptables` script in `/etc/NetworkManager/dispatcher.d/pre-up.d/`:
+
+    #!/bin/sh
+    
+    LOGFILE=/var/log/iptables.log
+    
+    if [ "$1" = lo ]; then
+        echo "$0: ignoring $1 for \`$2'" >> $LOGFILE
+        exit 0
+    fi
+    
+    case "$2" in
+        pre-up)
+            echo "$0: restoring iptables rules for $1" >> $LOGFILE
+            /sbin/iptables-restore /etc/network/iptables.up.rules >> $LOGFILE 2>&1
+            /sbin/ip6tables-restore /etc/network/ip6tables.up.rules >> $LOGFILE 2>&1
+            ;;
+        *)
+            echo "$0: nothing to do with $1 for \`$2'" >> $LOGFILE
+            ;;
+    esac
+    
+    exit 0
+
+and then make that script executable:
+
+    chmod a+x /etc/NetworkManager/dispatcher.d/pre-up.d/iptables
+
+With this in place, I can put my iptables rules in the usual place
+(`/etc/network/iptables.up.rules` and `/etc/network/ip6tables.up.rules`) and
+use the handy `iptables-apply` and `ip6tables-apply` commands to test
+any changes to my firewall rules.
+
+[[!tag nzoss]] [[!tag debian]] [[!tag iptables]]

Add Frab
diff --git a/posts/list-of-open-source-conference.mdwn b/posts/list-of-open-source-conference.mdwn
index 8586361..f657f3d 100644
--- a/posts/list-of-open-source-conference.mdwn
+++ b/posts/list-of-open-source-conference.mdwn
@@ -9,7 +9,9 @@ Since [Wikipedia](http://ubuntard.com/2010/03/wikipedia-notability-and-open-sour
 </tr>
 <tr><td><a href="http://act.mongueurs.net/">A Conference Toolkit</a></td><td>YAPC::Eu</td><td><a href="http://www.perlfoundation.org/artistic_license_2_0">Artistic License</a></td><td><a href="http://www.perl.org/">Perl</a></td>
 </tr>
-<tr><td><a href="http://github.com/herlo/ConMan">ConMan</a></td><td><a href="http://utosc.com/">Utah Open Source Conference</a>, <a href="http://www.texaslinuxfest.org/">Texax Linux Fest</a></td><td><a href="http://www.gnu.org/licenses/gpl.html">GPL</a></td><td><a href="http://www.python.org/">Python</a> (<a href="http://www.djangoproject.com/">Django</a>)</td>
+<tr><td><a href="http://github.com/herlo/ConMan">ConMan</a></td><td><a href="http://utosc.com/">Utah Open Source Conference</a>, <a href="http://www.texaslinuxfest.org/">Texas Linux Fest</a></td><td><a href="http://www.gnu.org/licenses/gpl.html">GPL</a></td><td><a href="http://www.python.org/">Python</a> (<a href="http://www.djangoproject.com/">Django</a>)</td>
+</tr>
+<tr><td><a href="https://frab.github.io/frab/">Frab</a></td><td><a href="http://www.froscon.org/">FrOSCon</a></td><td><a href="https://github.com/frab/frab/blob/master/LICENSE">Permissive</a></td><td><a href="http://www.rubyonrails.org/">Ruby on Rails</a></td>
 </tr>
 <tr><td><a href="http://pkp.sfu.ca/?q=ocs">Open Conference Systems</a></td><td>various academic conferences</td><td><a href="http://www.gnu.org/licenses/gpl.html">GPL</a></td><td><a href="http://www.php.org/">PHP</a></td>
 </tr>

Add an important keyword to my git-archive post
diff --git a/posts/excluding-files-from-git-archive.mdwn b/posts/excluding-files-from-git-archive.mdwn
index 9d8d27f..841b292 100644
--- a/posts/excluding-files-from-git-archive.mdwn
+++ b/posts/excluding-files-from-git-archive.mdwn
@@ -1,7 +1,7 @@
 [[!meta title="Excluding files from git archive exports using gitattributes"]]
 [[!meta date="2010-02-09T16:45:00.000+13:00"]]
 [[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
-[git archive](http://www.kernel.org/pub/software/scm/git/docs/git-archive.html) provides an easy way of producing a tarball directly from a project's git branch.  
+[git archive](http://www.kernel.org/pub/software/scm/git/docs/git-archive.html) provides an easy way of producing a tarball (or a zip file) directly from a project's git branch.
   
 For example, this is what we use to build the [Mahara](http://www.mahara.org) tarballs:  
 
diff --git a/posts/excluding-files-from-git-archive/comment_4_be6644c4f259c9b0d15579fdd3c10283._comment b/posts/excluding-files-from-git-archive/comment_4_be6644c4f259c9b0d15579fdd3c10283._comment
index 7fe29d2..2039d9c 100644
--- a/posts/excluding-files-from-git-archive/comment_4_be6644c4f259c9b0d15579fdd3c10283._comment
+++ b/posts/excluding-files-from-git-archive/comment_4_be6644c4f259c9b0d15579fdd3c10283._comment
@@ -3,5 +3,5 @@
  subject="--worktree-attributes"
  date="2015-02-03T18:18:02Z"
  content="""
-nah dog, if you commit the .gitattributes file first you don't need that option. go look up the definition of worktree as it relates to git
+nah, if you commit the .gitattributes file first you don't need that option. go look up the definition of worktree as it relates to git
 """]]

Use a better system tmpdir and mention the system restart
diff --git a/posts/crashplan-and-non-executable-tmp-directories.mdwn b/posts/crashplan-and-non-executable-tmp-directories.mdwn
index ff66bc9..c63036c 100644
--- a/posts/crashplan-and-non-executable-tmp-directories.mdwn
+++ b/posts/crashplan-and-non-executable-tmp-directories.mdwn
@@ -63,6 +63,9 @@ is executable and writable by the CrashPlan engine user (`root` on my
 machine), by adding something like this to the `SRV_JAVA_OPTS` variable of
 `/usr/local/crashplan/bin/run.conf`:
 
-    -Djava.io.tmpdir=/var/crashplan
+    -Djava.io.tmpdir=/var/tmp/crashplan
+
+Finally, it seems like you **need to restart the machine** before this
+starts working. I'm not sure why restarting crashplan isn't enough.
 
 [[!tag mozilla]] [[!tag backup]]

Small tweaks for stretch
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index b1f8409..70a3473 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -115,7 +115,7 @@ and add a timeout for root sessions by putting this in `/root/.bash_profile`:
 # Security checks
 
     apt-get install logcheck logcheck-database fcheck tiger debsums corekeeper mcelog rkhunter
-    apt-get remove --purge john john-data rpcbind tripwire
+    apt-get remove --purge john john-data rpcbind tripwire unhide unhide.rb
 
 Logcheck is the main tool I use to keep an eye on log files, which is why I
 add a few additional log files to the default list in
@@ -190,7 +190,7 @@ While the harden packages are configuration-free, AppArmor must be [manually ena
     update-grub
 
 In addition, certain kernel security features can be enabled by putting the
-following in `/etc/sysctl.conf` to
+following in `/etc/sysctl.d/local.conf` to
 [hide kernel pointers and messages](https://www.kernel.org/doc/Documentation/sysctl/kernel.txt)
 from unprivileged processes:
 
@@ -332,7 +332,7 @@ test the whole setup using `mail root`.
 
 To [reduce the server's contribution to
 bufferbloat](https://lwn.net/Articles/616241/) I change the default kernel
-queueing discipline (jessie or later) by putting the following in `/etc/sysctl.conf`:
+queueing discipline (jessie or later) by putting the following in `/etc/sysctl.d/local.conf`:
 
     net.core.default_qdisc=fq_codel
 

Add Persona principles post
diff --git a/posts/persona-guiding-principles.mdwn b/posts/persona-guiding-principles.mdwn
new file mode 100644
index 0000000..650de2e
--- /dev/null
+++ b/posts/persona-guiding-principles.mdwn
@@ -0,0 +1,136 @@
+[[!meta title="Persona Guiding Principles"]]
+[[!meta date="2016-11-29T11:42:00.000-08:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+Given the
+[impending shutdown of Persona](https://wiki.mozilla.org/Identity/Persona_Shutdown_Guidelines_for_Reliers)
+and the lack of a clear alternative to it, I decided to write about some of
+the principles that guided its design and development in the hope that it
+may influence future efforts in some way.
+
+# Permission-less system
+
+There was no need for reliers (sites relying on Persona to log their users
+in) to ask for permission before using Persona. Just like a site doesn't
+need to ask for permission before creating a link to another site, reliers
+didn't need to apply for an API key before they got started and authenticated
+their users using Persona.
+
+Similarly, identity providers (the services vouching for their users
+identity) didn't have to be whitelisted by reliers in order to be useful to
+their users.
+
+# Federation at the domain level
+
+Just like email, Persona was federated at the domain name level and put
+domain owners in control. Just like they can choose who gets to manage
+emails for their domain, they could:
+
+- run their own identity provider, or
+- delegate to their favourite provider.
+
+Site owners were also in **control of the mechanism and policies** involved
+in authenticating their users. For example, a security-sensitive corporation
+could decide to require 2-factor authentication for everyone or put a very
+short expiry on the certificates they issued.
+
+Alternatively, a low-security domain could get away with a much simpler
+login mechanism (including a "0-factor" mechanism in the case of
+<http://mockmyid.com>!).
+
+# Privacy from your identity provider
+
+While identity providers were the ones vouching for their users' identity,
+they didn't need to know the websites that their users are visiting. This is
+a potential source of control or censorship and the design of Persona was
+able to eliminate this.
+
+The downside of this design of course is that it becomes impossible for an
+identity provider to provide their users with a list of all of the sites
+where they successfully logged in for audit purposes, something that
+centralized systems can provide easily.
+
+# The browser as a trusted agent
+
+The browser, whether it had native support for the
+[BrowserID protocol](https://developer.mozilla.org/Persona/Protocol_Overview)
+or not, was the agent that the user needed to trust. It connected
+reliers (sites using Persona for logins) and identity providers together and
+got to see all aspects of the login process.
+
+It also held your private keys and therefore was the only party that could
+impersonate you. This is of course a power which it already held by virtue
+of its role as the web browser.
+
+Additionally, since it was the one generating and holding the private keys,
+your browser could also choose how long these keys are valid and may choose to
+vary that amount of time depending on factors like a shared computer
+environment or Private Browsing mode.
+
+Other clients/agents would likely be necessary as well, especially
+when it comes to interacting with mobile applications or native desktop
+applications. Each client would have its own key, but they would all be
+signed by the identity provider and therefore valid.
+
+# Bootstrapping a complex system requires fallbacks
+
+Persona was a complex system which involved a number of different actors. In
+order to slowly roll this out without waiting on every actor to implement
+the BrowserID protocol (something that would have taken an infinite amount of
+time), fallbacks were deemed necessary:
+
+- client-side JavaScript implementation for browsers without built-in support
+- centralized fallback identity provider for domains without native support
+  or a working delegation
+- centralized verifier until local verification is done within
+  authentication libraries
+
+In addition, to lessen the burden on the centralized identity provider
+fallback, Persona experimented with a number of bridges to provide
+quasi-native support for a few large email providers.
+
+# Support for multiple identities
+
+User research has shown that many users choose to present a different
+identity to different websites. An identity system that would restrict them
+to a single identity wouldn't work.
+
+Persona handled this naturally by linking identities to email addresses.
+Users who wanted to present a different identity to a website could simply use
+a different email address. For example, a work address and a personal
+address.
+
+# No lock-in
+
+Persona was an identity system which didn't stand between a site and its
+users. It exposed email address to sites and allowed them to control the
+relationship with their users.
+
+Sites wanting to move away from Persona can use the email addresses they
+have to both:
+
+- notify users of the new login system, and
+- allow users to reset (or set) their password via an email flow.
+
+Websites should not have to depend on the operator of an identity system in
+order to be able to talk to their users.
+
+# Short-lived certificates instead of revocation
+
+Instead of relying on the correct use of revocation systems, Persona used
+short-lived certificates in an effort to simplify this critical part of any
+cryptographic system.
+
+It offered three ways to limit the lifetime of crypto keys:
+
+- assertion expiry (set by the client)
+- key expiry (set by the client)
+- certificate expiry (set by the identify provider)
+
+The main drawback of such a pure expiration-based system is the increased
+window of time between a password change (or a similar signal that the user
+would like to revoke access) and the actual termination of all sessions. A
+short expirty can mitigate this problem, but it cannot be eliminated
+entirely unlike in a centralized identity system.
+
+[[!tag nzoss]] [[!tag mozilla]] [[!tag browserid]] [[!tag indieweb]] [[!tag web]]

Fix formatting of other comments
diff --git a/posts/restoring-single-table-from-postgres/comment_1_991b21accf85081445265855cd6c9284._comment b/posts/restoring-single-table-from-postgres/comment_1_991b21accf85081445265855cd6c9284._comment
index 36cd9f5..e15b7db 100644
--- a/posts/restoring-single-table-from-postgres/comment_1_991b21accf85081445265855cd6c9284._comment
+++ b/posts/restoring-single-table-from-postgres/comment_1_991b21accf85081445265855cd6c9284._comment
@@ -6,7 +6,7 @@
  content="""
 Generally, it's better to do your dumping via  
   
-pg_dump -Fc  
+    pg_dump -Fc  
   
 which lets you then use the full power of pg_restore.
 
diff --git a/posts/restoring-single-table-from-postgres/comment_3_56277f98ca9523047ec0b51af8ed7526._comment b/posts/restoring-single-table-from-postgres/comment_3_56277f98ca9523047ec0b51af8ed7526._comment
index 7e0c14f..7f8a7c2 100644
--- a/posts/restoring-single-table-from-postgres/comment_3_56277f98ca9523047ec0b51af8ed7526._comment
+++ b/posts/restoring-single-table-from-postgres/comment_3_56277f98ca9523047ec0b51af8ed7526._comment
@@ -6,7 +6,7 @@
  content="""
 Following this STACKOVERFLOW's [question](http://stackoverflow.com/questions/1013852/can-i-restore-a-single-table-from-a-full-mysql-mysqldump-file), if the dump format is text
 
-$ sed -n -e '/COPY.*mytable/,/CREATE TABLE/p' pg_whole.dump > mytable.dump
+    sed -n -e '/COPY.*mytable/,/CREATE TABLE/p' pg_whole.dump > mytable.dump
 
-works fine
+works fine.
 """]]

Improve formatting of comment
diff --git a/posts/restoring-single-table-from-postgres/comment_4_06b8b9d9ef8de189c662afbc69c9bafa._comment b/posts/restoring-single-table-from-postgres/comment_4_06b8b9d9ef8de189c662afbc69c9bafa._comment
index a98f471..b1d3f00 100644
--- a/posts/restoring-single-table-from-postgres/comment_4_06b8b9d9ef8de189c662afbc69c9bafa._comment
+++ b/posts/restoring-single-table-from-postgres/comment_4_06b8b9d9ef8de189c662afbc69c9bafa._comment
@@ -1,13 +1,13 @@
 [[!comment format=mdwn
  ip="193.40.192.10"
- subject="onliy if dump is cutom tump"
+ subject="onliy if dump is custom dump"
  date="2016-11-26T16:19:02Z"
  content="""
 For these type of operations the dump file should be in the postgresql custom format created with pg_dump:
 
-pg_dump -Fc
+    pg_dump -Fc
 
-Then you can restore a single table with pg_restore
+Then you can restore a single table with pg_restore:
 
-pg_restore --table=dancing_core_spice dump_full.sql > dancing_core_spice.sql
+    pg_restore --table=dancing_core_spice dump_full.sql > dancing_core_spice.sql
 """]]

Comment moderation
diff --git a/posts/combining-multiple-commits-into-one/comment_4_b48039159cc13b7318b66436263d2f95._comment b/posts/combining-multiple-commits-into-one/comment_4_b48039159cc13b7318b66436263d2f95._comment
new file mode 100644
index 0000000..d28993a
--- /dev/null
+++ b/posts/combining-multiple-commits-into-one/comment_4_b48039159cc13b7318b66436263d2f95._comment
@@ -0,0 +1,8 @@
+[[!comment format=txt
+ ip="178.63.0.194"
+ claimedauthor="Johnf663"
+ subject="Cheap goods"
+ date="2016-11-22T18:03:50Z"
+ content="""
+Amazing YouTube movies posted at this website, I am going to subscribe for daily updates, as I dont want to fail to take this series. gbfgedddbcdf
+"""]]
diff --git a/posts/restoring-single-table-from-postgres/comment_4_06b8b9d9ef8de189c662afbc69c9bafa._comment b/posts/restoring-single-table-from-postgres/comment_4_06b8b9d9ef8de189c662afbc69c9bafa._comment
new file mode 100644
index 0000000..a98f471
--- /dev/null
+++ b/posts/restoring-single-table-from-postgres/comment_4_06b8b9d9ef8de189c662afbc69c9bafa._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ ip="193.40.192.10"
+ subject="onliy if dump is cutom tump"
+ date="2016-11-26T16:19:02Z"
+ content="""
+For these type of operations the dump file should be in the postgresql custom format created with pg_dump:
+
+pg_dump -Fc
+
+Then you can restore a single table with pg_restore
+
+pg_restore --table=dancing_core_spice dump_full.sql > dancing_core_spice.sql
+"""]]

Use Let's Encrypt certs with ZNC
diff --git a/posts/hiding-network-disconnections-using-irc-bouncer.mdwn b/posts/hiding-network-disconnections-using-irc-bouncer.mdwn
index 002ce57..9600e75 100644
--- a/posts/hiding-network-disconnections-using-irc-bouncer.mdwn
+++ b/posts/hiding-network-disconnections-using-irc-bouncer.mdwn
@@ -26,18 +26,15 @@ The first step is to install [znc](http://wiki.znc.in/ZNC):
 Make sure you get the 1.0 series (in **jessie or trusty**, not wheezy
 or precise) since it has much better [multi-network support](http://wiki.znc.in/FAQ#Networks).
 
-Then, as a **non-root** user, generate a self-signed TLS certificate for it:
+Then, generate a Let's Encrypt TLS certificate for it:
 
-    openssl req -x509 -sha256 -newkey rsa:2048 -keyout znc.pem -nodes -out znc.crt -days 365
-
-and make sure you use something like `irc.example.com` as the *subject
-name*, that is the URL you will be connecting to from your IRC client.
+    apt install certbot
+    certbot certonly -d irc.example.com --standalone
 
 Then install the certificate in the right place:
 
     mkdir ~/.znc
-    mv znc.pem ~/.znc/
-    cat znc.crt >> ~/.znc/znc.pem
+    cat /etc/letsencrypt/live/irc.example.com/privkey.pem /etc/letsencrypt/live/irc.example.com/fullchain.pem > ~/.znc/znc.pem
 
 Once that's done, you're ready to create a config file for znc using the
 `znc --makeconf` command, again as the same non-root user:
@@ -68,7 +65,6 @@ and `irc.mozilla.org`):
         port = "6697";
         use_ssl = "yes";
         ssl_verify = "yes";
-        ssl_cafile = "~/.irssi/certs/znc.crt";
       },
       {
         address = "irc.example.com";
@@ -77,13 +73,9 @@ and `irc.mozilla.org`):
         port = "6697";
         use_ssl = "yes";
         ssl_verify = "yes";
-        ssl_cafile = "~/.irssi/certs/znc.crt";
       }
     );
 
-Of course, you'll need to copy your `znc.crt` file from the server into
-`~/.irssi/certs/znc.crt`.
-
 Make sure that you're no longer authenticating with the `nickserv` from
 within irssi. That's znc's job now.
 

Tighten up the ejabberd TLS settings
Based on https://bettercrypto.org/ and
https://blog.process-one.net/securing-ejabberd-with-tls-encryption/
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index 1bc4c87..4198b90 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -102,11 +102,27 @@ by adding `starttls_required` to this block:
           module: ejabberd_c2s
           certfile: "/etc/ejabberd/ejabberd.pem"
           starttls: true
+          starttls_required: true
           protocol_options:
             - "no_sslv3"
+            - "no_tlsv1"
+            - "no_tlsv1_1"
+            - "cipher_server_preference"
+          ciphers: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
+          tls_compression: false
+          dhfile: "/etc/ssl/ejabberd/dh2048.pem"
           max_stanza_size: 65536
           shaper: c2s_shaper
           access: c2s
+      
+      s2s_use_starttls: required_trusted
+      s2s_protocol_options:
+        - "no_sslv3"
+        - "no_tlsv1"
+        - "no_tlsv1_1"
+        - "cipher_server_preference"
+      s2s_dhfile: /etc/ssl/ejabberd/dh2048.pem
+      s2s_ciphers: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
 
 4. Restart the ejabberd
 daemon:
@@ -130,6 +146,12 @@ to requests after running for a while:
 
       0 4 * * *      root    /bin/systemctl restart ejabberd.service
 
+Note that if you'd like to be able to talk to contact via the GMail XMPP
+server, you will unfortunately need to change the `s2s_use_starttls`
+setting in step 3 to the following:
+
+      s2s_use_starttls: optional
+
 # Client setup
 
 On the client side, if you use Pidgin, create a new account with the

Add Let's Encrypt instructions for ejabberd
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index 574424e..1bc4c87 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -19,8 +19,37 @@ records:
     _xmpp-client._tcp    SRV      5 0 5222 jabber-gw.fmarier.org.
     _xmpp-server._tcp    SRV 	  5 0 5269 jabber-gw.fmarier.org.
 
-Then I went to get a free XMPP SSL certificate for `jabber-gw.fmarier.org`
-from [StartSSL](https://startssl.com). This is how I generated the CSR
+Then I went to get a free TLS certificate for `jabber-gw.fmarier.org` and `fmarier.org`.
+
+## Let's Encrypt
+
+The easiest way to get a certificate is to install [certbot](https://certbot.eff.org/) from
+[debian-backports](https://backports.debian.org/) by adding the following to
+your `/etc/apt/sources.list`:
+
+    deb http://httpredir.debian.org/debian jessie-backports main contrib non-free
+
+and then installing the package:
+
+    apt update && apt install certbot
+
+Then, shutdown your existing webserver if you have one running and request
+a cert like this:
+
+    certbot certonly -d jabber-gw.fmarier.org,fmarier.org --standalone
+
+Once you have the cert, you can merge the private and public keys
+into the file that ejabberd expects:
+
+    cat /etc/letsencrypt/live/jabber-gw.fmarier.org/privkey.pem /etc/letsencrypt/live/jabber-gw.fmarier.org/fullchain.pem > ejabberd.pem
+
+and then restart the service:
+
+    systemctl restart ejabberd.service
+
+## StartSSL
+
+I have also used [StartSSL](https://startssl.com) successfully. This is how I generated the CSR
 (Certificate Signing Request) on a high-entropy machine:
 
     openssl req -new -newkey rsa:2048 -sha256 -nodes -out ssl.csr -keyout ssl.key -subj "/C=NZ/CN=jabber-gw.fmarier.org"

Trim quote
diff --git a/posts/how-safe-browsing-works-in-firefox/comment_2_07411da9c7716700a5aa82e4978a8b14._comment b/posts/how-safe-browsing-works-in-firefox/comment_2_07411da9c7716700a5aa82e4978a8b14._comment
index 1cf10b6..d5d30fc 100644
--- a/posts/how-safe-browsing-works-in-firefox/comment_2_07411da9c7716700a5aa82e4978a8b14._comment
+++ b/posts/how-safe-browsing-works-in-firefox/comment_2_07411da9c7716700a5aa82e4978a8b14._comment
@@ -5,7 +5,7 @@
  subject="Re: comment 1"
  date="2016-11-03T15:57:10Z"
  content="""
-> We're now in 2016. Why isn't the complete sha256 hash trasferred in the initial list?
+> Why isn't the complete sha256 hash trasferred in the initial list?
 > 
 > The complete list is usually downloaded only once (or may also be shipped with the browser) and updates can be applied as differential updates thus reducing size.
 

Comment moderation
diff --git a/posts/how-safe-browsing-works-in-firefox/comment_2_07411da9c7716700a5aa82e4978a8b14._comment b/posts/how-safe-browsing-works-in-firefox/comment_2_07411da9c7716700a5aa82e4978a8b14._comment
new file mode 100644
index 0000000..1cf10b6
--- /dev/null
+++ b/posts/how-safe-browsing-works-in-firefox/comment_2_07411da9c7716700a5aa82e4978a8b14._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="francois@665656f0ba400877c9b12e8fbb086e45aa01f7c0"
+ nickname="francois"
+ avatar="http://fmarier.org/avatar/0110e86fdb31486c22dd381326d99de9"
+ subject="Re: comment 1"
+ date="2016-11-03T15:57:10Z"
+ content="""
+> We're now in 2016. Why isn't the complete sha256 hash trasferred in the initial list?
+> 
+> The complete list is usually downloaded only once (or may also be shipped with the browser) and updates can be applied as differential updates thus reducing size.
+
+This is what we do for small lists (all of the [Tracking Protection](https://feeding.cloud.geek.nz/posts/how-tracking-protection-works-in-firefox/) lists, as well as the certificate whitelist on Windows: `goog-downloadwhite-digest256`).
+
+As for the other lists (the ones that end in `-shavar` instead of `-digest256`), it's not practical the ship the whole list to each user because they are enormous and change a lot.
+"""]]

Comment moderation
diff --git a/posts/how-safe-browsing-works-in-firefox/comment_1_39954943a86494a62318f70507e99a0c._comment b/posts/how-safe-browsing-works-in-firefox/comment_1_39954943a86494a62318f70507e99a0c._comment
new file mode 100644
index 0000000..aa4a050
--- /dev/null
+++ b/posts/how-safe-browsing-works-in-firefox/comment_1_39954943a86494a62318f70507e99a0c._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ ip="91.89.253.64"
+ subject="comment 1"
+ date="2016-11-03T12:41:39Z"
+ content="""
+> When requesting complete hashes for a 32-bit prefix, Firefox throws in a number of extra \"noise\" entries to obfuscate the original URL further.
+
+We're now in 2016. Why isn't the complete sha256 hash trasferred in the initial list?
+
+The complete list is usually downloaded only once (or may also be shipped with the browser)
+and updates can be applied as differential updates thus reducing size.
+
+This eliminates the 2nd step where the complete hash of the url is sent to the safe browsing provider.
+"""]]

4am is a better time to restart services
It's unlikely that you'll be using your XMPP server at 4 in the morning.
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index b5c1299..574424e 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -99,7 +99,7 @@ firewall:
 to restart ejabberd once a day to ensure it doesn't stop responding
 to requests after running for a while:
 
-      0 11 * * *      root    /bin/systemctl restart ejabberd.service
+      0 4 * * *      root    /bin/systemctl restart ejabberd.service
 
 # Client setup
 

Add cronjob to restart the ejabberd daemon once a day
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index 5a0e33f..b5c1299 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -95,6 +95,12 @@ firewall:
       iptables -A INPUT -p tcp --dport 5222 -j ACCEPT
       iptables -A INPUT -p tcp --dport 5269 -j ACCEPT
 
+7. Optionally create a cronjob in `/etc/cron.d/restart-ejabberd`
+to restart ejabberd once a day to ensure it doesn't stop responding
+to requests after running for a while:
+
+      0 11 * * *      root    /bin/systemctl restart ejabberd.service
+
 # Client setup
 
 On the client side, if you use Pidgin, create a new account with the

Comment moderation
diff --git a/posts/tweaking-referrer-for-privacy-in-firefox/comment_1_a0e85cb8c263cd9ee80e78f1087460f0._comment b/posts/tweaking-referrer-for-privacy-in-firefox/comment_1_a0e85cb8c263cd9ee80e78f1087460f0._comment
new file mode 100644
index 0000000..9c92f3c
--- /dev/null
+++ b/posts/tweaking-referrer-for-privacy-in-firefox/comment_1_a0e85cb8c263cd9ee80e78f1087460f0._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ ip="37.35.165.201"
+ claimedauthor="aL"
+ subject="all this is great but..."
+ date="2016-10-24T11:31:58Z"
+ content="""
+sudo apt install xul-ext-refcontrol
+
+and then set default to block or use base url as referrer
+
+
+"""]]

Fix OWASP link
diff --git a/posts/tweaking-referrer-for-privacy-in-firefox.mdwn b/posts/tweaking-referrer-for-privacy-in-firefox.mdwn
index f11f5e2..bd8ca21 100644
--- a/posts/tweaking-referrer-for-privacy-in-firefox.mdwn
+++ b/posts/tweaking-referrer-for-privacy-in-firefox.mdwn
@@ -44,7 +44,7 @@ Armed with the `Referer` information, analytics tools can figure out:
 - how users are navigating the site.
 
 Another place where the `Referer` is useful is as a mitigation against
-[cross-site request forgeries](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Checking_The_Referer_Header).
+[cross-site request forgeries](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF\)_Prevention_Cheat_Sheet#Checking_the_Referer_Header).
 In that case, a website receiving a form submission can reject that form
 submission if the request originated from a different website.
 

Add Referrer post
diff --git a/posts/tweaking-referrer-for-privacy-in-firefox.mdwn b/posts/tweaking-referrer-for-privacy-in-firefox.mdwn
new file mode 100644
index 0000000..f11f5e2
--- /dev/null
+++ b/posts/tweaking-referrer-for-privacy-in-firefox.mdwn
@@ -0,0 +1,168 @@
+[[!meta title="Tweaking Referrers For Privacy in Firefox"]]
+[[!meta date="2016-10-23T20:00:00.000-04:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+The [Referer header](https://tools.ietf.org/html/rfc7231#section-5.5.2) has
+been a part of the web for a long time. Websites rely on it for a few
+different purposes (e.g. analytics, ads, CSRF protection) but it can be
+quite problematic from a privacy perspective.
+
+Thankfully, there are now tools in Firefox to help users and developers
+mitigate some of these problems.
+
+# Description
+
+In a nutshell, the browser adds a `Referer` header to all outgoing HTTP
+requests, revealing to the server on the other end the URL of the page you
+were on when you placed the request. For example, it tells the server where
+you were when you followed a link to that site, or what page you
+were on when you requested an image or a script. There are, however, a few
+limitations to this simplified explanation.
+
+First of all, by default, browsers won't send a referrer if you place a
+request from an HTTPS page to an HTTP page. This would reveal potentially
+confidential information (such as the URL path and query string which could
+contain session tokens or other secret identifiers) from a secure page over
+an insecure HTTP channel. Firefox will however include a `Referer` header in
+HTTPS to HTTPS transitions unless `network.http.sendSecureXSiteReferrer`
+(removed in Firefox 52) is set to `false` in `about:config`.
+
+Secondly, using the new
+[Referrer Policy specification](https://www.w3.org/TR/referrer-policy/) web
+developers can override the default behaviour for their pages, including on
+a per-element basis. This can be used both to increase or reduce the amount
+of information present in the referrer.
+
+# Legitimate Uses
+
+Because the `Referer` header has been around for so long, a number of
+techniques rely on it.
+
+Armed with the `Referer` information, analytics tools can figure out:
+
+- where website traffic comes from, and
+- how users are navigating the site.
+
+Another place where the `Referer` is useful is as a mitigation against
+[cross-site request forgeries](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Checking_The_Referer_Header).
+In that case, a website receiving a form submission can reject that form
+submission if the request originated from a different website.
+
+It's worth pointing out that this CSRF mitigation might be better implemented
+via a [separate header](http://crypto.stanford.edu/websec/csrf/) that could
+be restricted to particularly dangerous requests (i.e. POST and DELETE
+requests) and only include the information required for that security check
+(i.e. the [origin](https://tools.ietf.org/html/rfc6454)).
+
+# Problems with the Referrer
+
+Unfortunately, this header also creates significant privacy and security
+concerns.
+
+The most obvious one is that it leaks part of your browsing history to sites
+you visit as well as all of the resources they pull in (e.g. ads and
+third-party scripts). It can be quite complicated to
+[fix these leaks in a cross-browser way](https://www.facebook.com/notes/facebook-engineering/protecting-privacy-with-referrers/392382738919).
+
+These leaks can also lead to exposing private personally-identifiable
+information when they are part of the query string. One of the most
+high-profile example is
+[the accidental leakage of user searches by healthcare.gov](https://www.eff.org/deeplinks/2015/01/healthcare.gov-sends-personal-data).
+
+# Solutions for Firefox Users
+
+While web developers can use the new mechanisms exposed through the Referrer
+Policy, Firefox users can also take steps to limit the amount of information
+they send to websites, advertisers and trackers.
+
+In addition to enabling Firefox's built-in
+[tracking protection](https://feeding.cloud.geek.nz/posts/how-tracking-protection-works-in-firefox/)
+by setting `privacy.trackingprotection.enabled` to `true` in `about:config`,
+which will prevent all network connections to known trackers, users can
+control **when the `Referer` header is sent** by setting
+`network.http.sendRefererHeader` to:
+
+- `0` to never send the header
+- `1` to send the header only when clicking on links and similar elements
+- `2` (default) to send the header on all requests (e.g. images, links, etc.)
+
+It's also possible to put a **limit on the maximum amount of information** that
+the header will contain by setting the `network.http.referer.trimmingPolicy`
+to:
+
+- `0` (default) to send the full URL
+- `1` to send the URL without its query string
+- `2` to only send the scheme, host and port
+
+or using the `network.http.referer.XOriginTrimmingPolicy` option (added in
+Firefox 52) to only **restrict the contents of referrers attached to
+cross-origin requests**.
+
+Site owners can opt to share less information with other sites, but they
+can't share any more than what the user trimming policies allow.
+
+Another approach is to **disable the `Referer` when doing cross-origin
+requests** (from one site to another). The
+`network.http.referer.XOriginPolicy` preference can be set to:
+
+- `0` (default) to send the referrer in all cases
+- `1` to send a referrer only when the [base domains](https://en.wikipedia.org/wiki/Public_Suffix_List) are the same
+- `2` to send a referrer only when the full hostnames match
+
+# Breakage
+
+If you try to remove all referrers (i.e. `network.http.sendRefererHeader = 0`,
+you will most likely run into problems on a number of sites, for
+example:
+
+- anything that uses the default [Django authentication](https://code.djangoproject.com/ticket/16870)
+- [Launchpad logins](https://bugs.launchpad.net/launchpad/+bug/560246)
+- [AMD driver downloads](https://bugzilla.mozilla.org/show_bug.cgi?id=970092#c7)
+- some [CDN-hosted images](https://www.capbridge.com/visit/shuttle-service/)
+
+The first two have been worked-around successfully by setting
+`network.http.referer.spoofSource` to `true`, an advanced setting
+which always sends the destination URL as the referrer, thereby not leaking
+anything about the original page.
+
+Unfortunately, the last two are examples of the kind of breakage that can
+only be fixed through a whitelist (an approach supported by the [smart
+referer add-on](https://addons.mozilla.org/firefox/addon/smart-referer/)) or
+by temporarily using a different [browser
+profile](https://support.mozilla.org/kb/profile-manager-create-and-remove-firefox-profiles).
+
+# My Recommended Settings
+
+As with my
+[cookie recommendations](https://feeding.cloud.geek.nz/posts/tweaking-cookies-for-privacy-in-firefox/),
+I recommend strengthening your referrer settings but not disabling (or
+spoofing) it entirely.
+
+While spoofing does solve many the breakage problems mentioned above, it
+also effectively disables the anti-CSRF protections that some sites may rely
+on and that have tangible user benefits. A better approach is to limit the
+amount of information that leaks through cross-origin requests.
+
+If you are willing to live with some amount of breakage, you can simply
+restrict referrers to the same site by setting:
+
+    network.http.referer.XOriginPolicy = 2
+
+or to sites which belong to the same organization (i.e. same
+[ETLD/public suffix](https://en.wikipedia.org/wiki/Public_Suffix_List))
+using:
+
+    network.http.referer.XOriginPolicy = 1
+
+This prevent leaks to third-parties while giving websites all of the
+information that they can already see in their own server logs.
+
+On the other hand, if you prefer a weaker but more compatible solution, you
+can trim cross-origin referrers down to just the scheme, hostname and port:
+
+    network.http.referer.XOriginTrimmingPolicy = 2
+
+I have not yet found user-visible breakage using this last configuration.
+Let me know if you find any!
+
+[[!tag firefox]] [[!tag debian]] [[!tag nzoss]] [[!tag mozilla]] [[!tag privacy]]

Update the name of the phishing pref
https://bugzilla.mozilla.org/show_bug.cgi?id=1025965
diff --git a/posts/how-safe-browsing-works-in-firefox.mdwn b/posts/how-safe-browsing-works-in-firefox.mdwn
index e7ae193..ea7c734 100644
--- a/posts/how-safe-browsing-works-in-firefox.mdwn
+++ b/posts/how-safe-browsing-works-in-firefox.mdwn
@@ -44,7 +44,7 @@ show up instead, which you can see for yourself here:
 
 The first two warnings can be toggled using the `browser.safebrowsing.malware.enabled`
 preference (in `about:config`) whereas the last one is controlled by
-`browser.safebrowsing.enabled`.
+`browser.safebrowsing.phishing.enabled`.
 
 ## List updates
 

Fix formatting in comment
diff --git a/posts/setting-up-raid-on-existing/comment_14_6a8e87411d6241078da66b68fd2d7d8d._comment b/posts/setting-up-raid-on-existing/comment_14_6a8e87411d6241078da66b68fd2d7d8d._comment
index c214d6f..1a88a57 100644
--- a/posts/setting-up-raid-on-existing/comment_14_6a8e87411d6241078da66b68fd2d7d8d._comment
+++ b/posts/setting-up-raid-on-existing/comment_14_6a8e87411d6241078da66b68fd2d7d8d._comment
@@ -4,5 +4,5 @@
  subject="Thanks for the great guide"
  date="2016-09-21T14:20:31Z"
  content="""
-One addendum though. In my case at least grub threw an error regarding null devices or something (I don't recall exactly what it was). If that happens you need to \"blockdev --flushbufs [device]\" for your involved devices. After that everything worked perfectly.
+One addendum though. In my case at least grub threw an error regarding null devices or something (I don't recall exactly what it was). If that happens you need to `blockdev --flushbufs [device]` for your involved devices. After that everything worked perfectly.
 """]]

Comment moderation
diff --git a/posts/setting-up-raid-on-existing/comment_14_6a8e87411d6241078da66b68fd2d7d8d._comment b/posts/setting-up-raid-on-existing/comment_14_6a8e87411d6241078da66b68fd2d7d8d._comment
new file mode 100644
index 0000000..c214d6f
--- /dev/null
+++ b/posts/setting-up-raid-on-existing/comment_14_6a8e87411d6241078da66b68fd2d7d8d._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ ip="87.230.109.38"
+ claimedauthor="Rincewind"
+ subject="Thanks for the great guide"
+ date="2016-09-21T14:20:31Z"
+ content="""
+One addendum though. In my case at least grub threw an error regarding null devices or something (I don't recall exactly what it was). If that happens you need to \"blockdev --flushbufs [device]\" for your involved devices. After that everything worked perfectly.
+"""]]

Fix indentation of pageinfo block
This was missed in 8a2c430101db9f2cc79870b9c34879e178d0244e.
diff --git a/local.css b/local.css
index 76de16b..068fd89 100644
--- a/local.css
+++ b/local.css
@@ -264,7 +264,8 @@ iframe[src='//ad.aloodo.com/track/'] {
 @media all and (max-width: 40em) {
     .pageheader,
     #pagebody,
-    .sidebar {
+    .sidebar,
+    #pageinfo {
         padding-left: 1em;
         padding-right: 1em;
     }

Fix typo in CSS declaration
diff --git a/local.css b/local.css
index ede914b..76de16b 100644
--- a/local.css
+++ b/local.css
@@ -1,6 +1,5 @@
 /* ikiwiki local style sheet */
-.blogform, .trail, .inlinefooter .pagelicense, .inlinefooter .tags, .inlinefooter .actions,
- {
+.blogform, .trail, .inlinefooter .pagelicense, .inlinefooter .tags, .inlinefooter .actions {
     display: none;
 }
 

Remove navigation menu items
diff --git a/local.css b/local.css
index 42f6abd..ede914b 100644
--- a/local.css
+++ b/local.css
@@ -1,5 +1,6 @@
 /* ikiwiki local style sheet */
-.blogform, .trail, .inlinefooter .pagelicense, .inlinefooter .tags, .inlinefooter .actions {
+.blogform, .trail, .inlinefooter .pagelicense, .inlinefooter .tags, .inlinefooter .actions,
+ {
     display: none;
 }
 
@@ -37,8 +38,7 @@ body {
     color: #FFF;
 }
 
-    .pageheader a, 
-    .pagefooter a {
+    .pageheader a {
         color: #A4D2FF;
     }
 
@@ -60,6 +60,12 @@ body {
         font-weight: bold;
     }
 
+    .pageheader .actions a[href^='/ikiwiki.cgi?do=comment'],
+    .pageheader .actions a[href^='/ikiwiki.cgi?do=edit'],
+    .pageheader .actions a[href^='./#comments'] {
+        display: none;
+    }
+
 #searchform {
     top: 1.6em;
 }

Make local over-rides mobile friendly.
diff --git a/local.css b/local.css
index e493fc2..42f6abd 100644
--- a/local.css
+++ b/local.css
@@ -1,73 +1,304 @@
 /* ikiwiki local style sheet */
-body, .pageheader .actions ul li {
-  background-color: #EEEED9;
-  text-rendering: optimizeLegibility;
+.blogform, .trail, .inlinefooter .pagelicense, .inlinefooter .tags, .inlinefooter .actions {
+    display: none;
 }
 
-a {
-  color: #5187bd;
+body {
+    background-color: #277459;
+    color: #FFF;
+    line-height: 1.2;
+    text-rendering: optimizeLegibility;
 }
 
-code, pre {
-  background-color: #ddddbe;
+    body a {
+        color: #bee8da;
+    }
+
+/* PAGE WRAPPER */
+
+.page {
+    max-width: 60em;
+    margin-right: 19em;
+    border-bottom: 2em solid #335577;
+    background: #EEEED9;
+    color: #333;
 }
 
-.header {
-  font-weight: bold;
+    .page a {
+        color: #5187bd;
+    }
+
+/* HEADER */
+
+.pageheader {
+    border: none;
+    padding: 2em;
+    background-color: #335577;
+    color: #FFF;
 }
 
-.pageheader, .pagefooter {
-  border: none;
-  background-color: #335577;
-  color: white;
+    .pageheader a, 
+    .pagefooter a {
+        color: #A4D2FF;
+    }
+
+    .pageheader .header {
+        padding-top: 1em;
+    }
+
+    .pageheader .parentlinks {
+        display: block;
+        margin-right: 12em;
+    }
+
+        .pageheader .parentlinks a::after {
+            content: ' ';
+        }
+
+    .pageheader .title {
+        margin-bottom: 0.2em;
+        font-weight: bold;
+    }
+
+#searchform {
+    top: 1.6em;
 }
 
-.pageheader a, .pagefooter a {
-  color: #6db6ff;
+#searchform input {
+    padding: 2px 16px 2px 10px;
+    font-size: inherit;
 }
 
-#footer, #pageinfo {
-  margin: 0;
+.pageheader .actions > ul > li {
+        margin: 0;
+        padding: 0;
+        background: transparent;
+        border: none;
 }
 
+.pageheader .actions > ul > li > a {
+    display: block;
+    float: right;
+    padding: 0 0 0.4em 1em;
+}
+
+/* SIDEBAR */
+
 .sidebar {
-  background-color: #558866;
-  width: 220px;
-  color: white !important;
+    width: 15em;
+    margin: 0 -19em 0 2em;
+    padding: 2em;
+    border: 0;
+    background-color: #277459;
+    color: #FFF !important;
 }
 
-.sidebar a {
-  color: #65f5d8;
+    .sidebar :first-child {
+        margin-top: 0;
+    }
+
+    .sidebar a {
+        color: #bee8da !important;
+    }
+
+/* PAGE BODY
+   - wraps #content and #comments
+*/
+
+#pagebody {
+    padding: 2em;
 }
 
-.sidebar img {
-  margin: 0 10px 0 0;
+    #pagebody code, 
+    #pagebody pre,
+    #pagebody blockquote {
+        background-color: #ddddbe;
+        font-size: 1.05em;
+    }
+
+    #pagebody pre,
+    #pagebody blockquote {
+            padding: 0.5em;
+    }
+
+#content {
+    margin: 0;
+    padding: 0;
+    max-width: 60em;
 }
 
-.blogform, .trail, .inlinefooter .pagelicense, .inlinefooter .tags, .inlinefooter .actions {
-  display: none;
+    #content :first-child {
+        margin-top: 0;
+    }
+
+.inlinepage {
+    margin-bottom: 2em;
+    border: 0;
+    border-bottom: 1px solid #277459;
+    padding-bottom: 2em;
 }
 
-.page {
-  max-width: 75em;
+#content .inlinepage:last-child {
+    margin-bottom: 0;
+    border-bottom: 0;
+    padding-bottom: 0;
 }
 
-#pagebody {
-  width: 60em;
+#comments {
+    margin: 2em 0 0 0;
+    padding: 0;
+    border-top: 1px solid #277459;
 }
 
-.inlinepage {
-  margin: 0 0 4em 0;
-  padding: 0;
-  border: none;
+.feedlink {
+    margin: 2em 0em;
+}
+
+.comment {
+    margin: 0 0 2em 0;
+    border: none;
+    border-bottom: 1px solid #ddddbe;
+    padding-bottom: 2em;

(Diff truncated)
Disable the metadata_csum ext4 option to make it compatible with older e2fsprogs
Without this, post-Jessie versions of mkfs.ext4 will create a filesystem that
cannot be opened on Jessie or Xenial.
diff --git a/posts/encrypted-system-backup-to-dvd.mdwn b/posts/encrypted-system-backup-to-dvd.mdwn
index f0efc14..85abf06 100644
--- a/posts/encrypted-system-backup-to-dvd.mdwn
+++ b/posts/encrypted-system-backup-to-dvd.mdwn
@@ -53,7 +53,7 @@ Make sure you have at least 4.3 GB of free disk space on `/` and then run:
     dd if=/dev/zero of=/backup.dat bs=1M count=4096
     cryptmount --generate-key 32 backup
     cryptmount --prepare backup
-    mkfs.ext4 -m 0 /dev/mapper/backup
+    mkfs.ext4 -m 0 -O ^metadata_csum /dev/mapper/backup
     cryptmount --release backup
 
 Alternatively, if you're using a double-layer DVD then use this `dd` line:

Mount DVD backup read-only
diff --git a/posts/encrypted-system-backup-to-dvd.mdwn b/posts/encrypted-system-backup-to-dvd.mdwn
index 0e4bfc6..f0efc14 100644
--- a/posts/encrypted-system-backup-to-dvd.mdwn
+++ b/posts/encrypted-system-backup-to-dvd.mdwn
@@ -16,12 +16,11 @@ Install [cryptmount](http://cryptmount.sourceforge.net/):
     apt-get install cryptmount
 
 
-and setup two encrypted mount points in `/etc/cryptmount/cmtab`:  
+and setup two encrypted mount points in `/etc/cryptmount/cmtab`:
 
-
-    backup {  
-      dev=/backup.dat  
-      dir=/backup  
+    backup {
+      dev=/backup.dat
+      dir=/backup
       fstype=ext4
       mountoptions=defaults,noatime
 
@@ -30,13 +29,13 @@ and setup two encrypted mount points in `/etc/cryptmount/cmtab`:
       keycipher=aes-xts-plain64
       keyformat=builtin
       cipher=aes-xts-plain64
-    }  
-      
-    testbackup {  
+    }
+
+    testbackup {
       dev=/media/cdrom/backup.dat
-      dir=/backup  
+      dir=/backup
       fstype=ext4
-      mountoptions=defaults,noatime
+      mountoptions=defaults,noatime,ro
 
       keyfile=/media/cdrom/backup.key
       keyhash=sha512
@@ -45,9 +44,6 @@ and setup two encrypted mount points in `/etc/cryptmount/cmtab`:
       cipher=aes-xts-plain64
     }
 
-
-  
-
 ### Initialize the encrypted filesystem
 
 Make sure you have at least 4.3 GB of free disk space on `/` and then run:  

Add my gnome-session debugging post
diff --git a/posts/debugging-gnome-session-problems-on-ubuntu-1404.mdwn b/posts/debugging-gnome-session-problems-on-ubuntu-1404.mdwn
new file mode 100644
index 0000000..755932e
--- /dev/null
+++ b/posts/debugging-gnome-session-problems-on-ubuntu-1404.mdwn
@@ -0,0 +1,112 @@
+[[!meta title="Debugging gnome-session problems on Ubuntu 14.04"]]
+[[!meta date="2016-08-24T22:00:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+After upgrading an Ubuntu 14.04 ("trusty") machine to the latest 16.04
+[Hardware Enablement](https://wiki.ubuntu.com/Kernel/LTSEnablementStack)
+packages, I ran into login problems. I could log into my user account and
+see the GNOME desktop for a split second before getting thrown back into the
+LightDM login manager.
+
+The solution I found was to install this missing package:
+
+    apt install libwayland-egl1-mesa-lts-xenial
+
+# Looking for clues in the logs
+
+The first place I looked was the log file for the login manager
+(`/var/log/lightdm/lightdm.log`) where I found the following:
+
+    DEBUG: Session pid=12743: Running command /usr/sbin/lightdm-session gnome-session --session=gnome
+    DEBUG: Creating shared data directory /var/lib/lightdm-data/username
+    DEBUG: Session pid=12743: Logging to .xsession-errors
+
+This told me that the login manager runs the `gnome-session` command and
+gets it to create a session of type *gnome*. That command line is defined
+in `/usr/share/xsessions/gnome.desktop` (look for `Exec=`):
+
+    [Desktop Entry]
+    Name=GNOME
+    Comment=This session logs you into GNOME
+    Exec=gnome-session --session=gnome
+    TryExec=gnome-shell
+    X-LightDM-DesktopName=GNOME
+
+I couldn't see anything unexpected there, but it did point to another log
+file (`~/.xsession-errors`) which contained the following:
+
+    Script for ibus started at run_im.
+    Script for auto started at run_im.
+    Script for default started at run_im.
+    init: Le processus gnome-session (GNOME) main (11946) s'est achevé avec l'état 1
+    init: Déconnecté du bus D-Bus notifié
+    init: Le processus logrotate main (11831) a été tué par le signal TERM
+    init: Le processus update-notifier-crash (/var/crash/_usr_bin_unattended-upgrade.0.crash) main (11908) a été tué par le signal TERM
+
+Seaching for French error messages isn't as useful as searching for English
+ones, so I took a look at `/var/log/syslog` and found this:
+
+    gnome-session[4134]: WARNING: App 'gnome-shell.desktop' exited with code 127
+    gnome-session[4134]: WARNING: App 'gnome-shell.desktop' exited with code 127
+    gnome-session[4134]: WARNING: App 'gnome-shell.desktop' respawning too quickly
+    gnome-session[4134]: CRITICAL: We failed, but the fail whale is dead. Sorry....
+
+It looks like `gnome-session` is executing `gnome-shell` and that this last
+command is terminating prematurely. This would explain why `gnome-session`
+exits immediately after login.
+
+# Increasing the amount of logging
+
+In order to get more verbose debugging information out of `gnome-session`, I
+created a new type of session (*GNOME debug*) by copying the regular *GNOME*
+session:
+
+    cp /usr/share/xsessions/gnome.desktop /usr/share/xsessions/gnome-debug.desktop
+
+and then adding `--debug` to the command line inside `gnome-debug.desktop`:
+
+    [Desktop Entry]
+    Name=GNOME debug
+    Comment=This session logs you into GNOME debug
+    Exec=gnome-session --debug --session=gnome
+    TryExec=gnome-shell
+    X-LightDM-DesktopName=GNOME debug
+
+After restarting LightDM (`service lightdm restart`), I clicked the GNOME
+logo next to the password field and chose *GNOME debug* before trying to
+login again.
+
+This time, I had a lot more information in `~/.xsession-errors`:
+
+    gnome-session[12878]: DEBUG(+): GsmAutostartApp: starting gnome-shell.desktop: command=/usr/bin/gnome-shell startup-id=10d41f1f5c81914ec61471971137183000000128780000
+    gnome-session[12878]: DEBUG(+): GsmAutostartApp: started pid:13121
+    ...
+    /usr/bin/gnome-shell: error while loading shared libraries: libwayland-egl.so.1: cannot open shared object file: No such file or directory
+    gnome-session[12878]: DEBUG(+): GsmAutostartApp: (pid:13121) done (status:127)
+    gnome-session[12878]: WARNING: App 'gnome-shell.desktop' exited with code 127
+
+which suggests that `gnome-shell` won't start because of a missing library.
+
+# Finding the missing library
+
+To find the missing library, I used the [apt-file](https://launchpad.net/ubuntu/+source/apt-file) command:
+
+    apt-file update
+    apt-file search libwayland-egl.so.1
+
+and found that this file is provided by the following packages:
+
+- libhybris
+- libwayland-egl1-mesa
+- libwayland-egl1-mesa-dbg
+- libwayland-egl1-mesa-lts-utopic
+- libwayland-egl1-mesa-lts-vivid
+- libwayland-egl1-mesa-lts-wily
+- libwayland-egl1-mesa-lts-xenial
+
+Since I installed the LTS Enablement stack, the package I needed to install to fix this
+was [libwayland-egl1-mesa-lts-xenial](https://launchpad.net/ubuntu/trusty/+package/libwayland-egl1-mesa-lts-xenial).
+
+I filed [a bug for this on Launchpad](https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-intel-lts-xenial/+bug/1616734).
+
+[[!tag nzoss]] [[!tag debian]] [[!tag gnome]] [[!tag ubuntu]]

Keep translation out of the feeds
diff --git a/translations/remplacer-un-disque-raid-defectueux.mdwn b/translations/remplacer-un-disque-raid-defectueux.mdwn
index 83462a4..90ca74b 100644
--- a/translations/remplacer-un-disque-raid-defectueux.mdwn
+++ b/translations/remplacer-un-disque-raid-defectueux.mdwn
@@ -114,5 +114,3 @@ et j'ai ensuite exécuter un test *SMART* complet sur le nouveau
 disque :
 
     smartctl -t long /dev/sdb
-
-[[!tag nzoss]] [[!tag sysadmin]] [[!tag debian]] [[!tag raid]]

Comment moderation
diff --git a/posts/replacing-a-failed-raid-drive/comment_3_b7db48df0ed125b21c3b314843cfd61d._comment b/posts/replacing-a-failed-raid-drive/comment_3_b7db48df0ed125b21c3b314843cfd61d._comment
new file mode 100644
index 0000000..f2f57af
--- /dev/null
+++ b/posts/replacing-a-failed-raid-drive/comment_3_b7db48df0ed125b21c3b314843cfd61d._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="francois@665656f0ba400877c9b12e8fbb086e45aa01f7c0"
+ nickname="francois"
+ subject="Re: traduction en fr"
+ date="2016-08-20T22:07:12Z"
+ content="""
+Je viens de faire une traduction rapide de cet article que j'ai mis ici : <https://feeding.cloud.geek.nz/translations/remplacer-un-disque-raid-defectueux/>
+"""]]