Recent changes to this wiki:

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/>
+"""]]

creating index page translations
diff --git a/translations.mdwn b/translations.mdwn
new file mode 100644
index 0000000..24c6344
--- /dev/null
+++ b/translations.mdwn
@@ -0,0 +1 @@
+[[!map pages="translations/* and ! translations/*/*"]]

Add a French translation for my RAID article
Hopefully in a different location so that it won't show up in feeds or on
the homepage.
diff --git a/translations/remplacer-un-disque-raid-defectueux.mdwn b/translations/remplacer-un-disque-raid-defectueux.mdwn
new file mode 100644
index 0000000..83462a4
--- /dev/null
+++ b/translations/remplacer-un-disque-raid-defectueux.mdwn
@@ -0,0 +1,118 @@
+[[!meta title="Remplacer un disque RAID défectueux"]]
+[[!meta date="2016-08-20T15:00:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+Traduction de l'article original anglais à
+<https://feeding.cloud.geek.nz/posts/replacing-a-failed-raid-drive/>.
+
+Voici la procédure que j'ai suivi pour remplacer un disque RAID défectueux
+sur une machine Debian.
+
+# Remplacer le disque
+
+Après avoir remarqué que `/dev/sdb` a été expulsé de mon RAID, j'ai utilisé
+[smartmontools](https://packages.debian.org/jessie/smartmontools) pour
+identifier le numéro de série du disque à retirer :
+
+    smartctl -a /dev/sdb
+
+Cette information en main, j'ai fermé l'ordinateur, retiré le disque
+défectueux et mis un nouveau disque vide à la place.
+
+# Initialiser le nouveau disque
+
+Après avoir démarré avec le nouveau disque vide, j'ai copié la table
+de partitions avec [parted](https://packages.debian.org/jessie/parted).
+
+Premièrement, j'ai examiné la table de partitions sur le disque dur
+non-défectueux :
+
+    $ parted /dev/sda
+    unit s
+    print
+
+et créé une nouvelle table de partitions sur le disque de
+remplacement :
+
+    $ parted /dev/sdb
+    unit s
+    mktable gpt
+
+Ensuite j'ai utilisé la commande `mkpart` pour mes 4 partitions et je
+leur ai toutes donné la même taille que les partitions équivalentes
+sur `/dev/sda`.
+
+Finalement, j'ai utilisé les commandes `toggle 1 bios_grub` (partition
+d'amorce) et `toggle X raid` (où *X* est le numéro de la partition)
+pour toutes les partitions RAID, avant de vérifier avec la commande
+`print` que les deux tables de partitions sont maintenant identiques.
+
+# Resynchroniser/recréer les RAID
+
+Pour synchroniser les données du bon disque (`/dev/sda`) vers celui
+de remplacement (`/dev/sdb`), j'ai exécuté les commandes suivantes
+sur mes partitions RAID1 :
+
+    mdadm /dev/md0 -a /dev/sdb2
+    mdadm /dev/md2 -a /dev/sdb4
+
+et j'ai gardé un oeil sur le statut de la synchronisation avec :
+
+    watch -n 2 cat /proc/mdstat
+
+Pour [accélérer le processus](http://www.cyberciti.biz/tips/linux-raid-increase-resync-rebuild-speed.html),
+j'ai utilisé le truc suivant :
+
+    blockdev --setra 65536 "/dev/md0"
+    blockdev --setra 65536 "/dev/md2"
+    echo 300000 > /proc/sys/dev/raid/speed_limit_min
+    echo 1000000 > /proc/sys/dev/raid/speed_limit_max
+
+Ensuite, j'ai recréé ma partition *swap* RAID0 comme suit :
+
+    mdadm /dev/md1 --create --level=0 --raid-devices=2 /dev/sda3 /dev/sdb3
+    mkswap /dev/md1
+
+Par que la partition *swap* est toute neuve (il n'est pas possible de
+restorer une partition RAID0, il faut la re-créer complètement), j'ai dû
+faire deux choses:
+
+- remplacer le *UUID* pour *swap* dans `/etc/fstab`, avec le *UUID* donné
+  par la commande `mkswap` (ou bien en utilisant la command `blkid` et en
+  prenant le *UUID* pour `/dev/md1`)
+- remplacer le *UUID* de `/dev/md1` dans `/etc/mdadm/mdadm.conf` avec
+  celui retourné pour `/dev/md1` par la commande `mdadm --detail --scan`
+
+# S'assurer que l'on peut démarrer avec le disque de remplacement
+
+Pour être certain de bien pouvoir démarrer la machine avec n'importe quel
+des deux disques, j'ai réinstallé le *boot loader* grub sur le nouveau
+disque :
+
+    grub-install /dev/sdb
+
+avant de redémarrer avec les deux disques connectés. Ceci confirme que ma
+configuration fonctionne bien.
+
+Ensuite, j'ai démarré sans le disque `/dev/sda` pour m'assurer que tout
+fonctionnerait bien si ce disque décidait de mourir et de me laisser
+seulement avec le nouveau (`/dev/sdb`).
+
+Ce test brise évidemment la synchronisation entre les deux disques, donc
+j'ai dû redémarrer avec les deux disques connectés et puis ré-ajouter
+`/dev/sda` à tous les RAID1 :
+
+    mdadm /dev/md0 -a /dev/sda2
+    mdadm /dev/md2 -a /dev/sda4
+
+Une fois le tout fini, j'ai redémarrer à nouveau avec les deux disques
+pour confirmer que tout fonctionne bien :
+
+    cat /proc/mdstat
+
+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]]

Revert "Add a French translation for my RAID article"
This reverts commit 6e254003639bdee6d4510ba7e881f1eb9876219b.
diff --git a/posts/replacing-a-failed-raid-drive/remplacer-un-disque-raid-defectueux.mdwn b/posts/replacing-a-failed-raid-drive/remplacer-un-disque-raid-defectueux.mdwn
deleted file mode 100644
index 83462a4..0000000
--- a/posts/replacing-a-failed-raid-drive/remplacer-un-disque-raid-defectueux.mdwn
+++ /dev/null
@@ -1,118 +0,0 @@
-[[!meta title="Remplacer un disque RAID défectueux"]]
-[[!meta date="2016-08-20T15:00:00.000-07:00"]]
-[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
-
-Traduction de l'article original anglais à
-<https://feeding.cloud.geek.nz/posts/replacing-a-failed-raid-drive/>.
-
-Voici la procédure que j'ai suivi pour remplacer un disque RAID défectueux
-sur une machine Debian.
-
-# Remplacer le disque
-
-Après avoir remarqué que `/dev/sdb` a été expulsé de mon RAID, j'ai utilisé
-[smartmontools](https://packages.debian.org/jessie/smartmontools) pour
-identifier le numéro de série du disque à retirer :
-
-    smartctl -a /dev/sdb
-
-Cette information en main, j'ai fermé l'ordinateur, retiré le disque
-défectueux et mis un nouveau disque vide à la place.
-
-# Initialiser le nouveau disque
-
-Après avoir démarré avec le nouveau disque vide, j'ai copié la table
-de partitions avec [parted](https://packages.debian.org/jessie/parted).
-
-Premièrement, j'ai examiné la table de partitions sur le disque dur
-non-défectueux :
-
-    $ parted /dev/sda
-    unit s
-    print
-
-et créé une nouvelle table de partitions sur le disque de
-remplacement :
-
-    $ parted /dev/sdb
-    unit s
-    mktable gpt
-
-Ensuite j'ai utilisé la commande `mkpart` pour mes 4 partitions et je
-leur ai toutes donné la même taille que les partitions équivalentes
-sur `/dev/sda`.
-
-Finalement, j'ai utilisé les commandes `toggle 1 bios_grub` (partition
-d'amorce) et `toggle X raid` (où *X* est le numéro de la partition)
-pour toutes les partitions RAID, avant de vérifier avec la commande
-`print` que les deux tables de partitions sont maintenant identiques.
-
-# Resynchroniser/recréer les RAID
-
-Pour synchroniser les données du bon disque (`/dev/sda`) vers celui
-de remplacement (`/dev/sdb`), j'ai exécuté les commandes suivantes
-sur mes partitions RAID1 :
-
-    mdadm /dev/md0 -a /dev/sdb2
-    mdadm /dev/md2 -a /dev/sdb4
-
-et j'ai gardé un oeil sur le statut de la synchronisation avec :
-
-    watch -n 2 cat /proc/mdstat
-
-Pour [accélérer le processus](http://www.cyberciti.biz/tips/linux-raid-increase-resync-rebuild-speed.html),
-j'ai utilisé le truc suivant :
-
-    blockdev --setra 65536 "/dev/md0"
-    blockdev --setra 65536 "/dev/md2"
-    echo 300000 > /proc/sys/dev/raid/speed_limit_min
-    echo 1000000 > /proc/sys/dev/raid/speed_limit_max
-
-Ensuite, j'ai recréé ma partition *swap* RAID0 comme suit :
-
-    mdadm /dev/md1 --create --level=0 --raid-devices=2 /dev/sda3 /dev/sdb3
-    mkswap /dev/md1
-
-Par que la partition *swap* est toute neuve (il n'est pas possible de
-restorer une partition RAID0, il faut la re-créer complètement), j'ai dû
-faire deux choses:
-
-- remplacer le *UUID* pour *swap* dans `/etc/fstab`, avec le *UUID* donné
-  par la commande `mkswap` (ou bien en utilisant la command `blkid` et en
-  prenant le *UUID* pour `/dev/md1`)
-- remplacer le *UUID* de `/dev/md1` dans `/etc/mdadm/mdadm.conf` avec
-  celui retourné pour `/dev/md1` par la commande `mdadm --detail --scan`
-
-# S'assurer que l'on peut démarrer avec le disque de remplacement
-
-Pour être certain de bien pouvoir démarrer la machine avec n'importe quel
-des deux disques, j'ai réinstallé le *boot loader* grub sur le nouveau
-disque :
-
-    grub-install /dev/sdb
-
-avant de redémarrer avec les deux disques connectés. Ceci confirme que ma
-configuration fonctionne bien.
-
-Ensuite, j'ai démarré sans le disque `/dev/sda` pour m'assurer que tout
-fonctionnerait bien si ce disque décidait de mourir et de me laisser
-seulement avec le nouveau (`/dev/sdb`).
-
-Ce test brise évidemment la synchronisation entre les deux disques, donc
-j'ai dû redémarrer avec les deux disques connectés et puis ré-ajouter
-`/dev/sda` à tous les RAID1 :
-
-    mdadm /dev/md0 -a /dev/sda2
-    mdadm /dev/md2 -a /dev/sda4
-
-Une fois le tout fini, j'ai redémarrer à nouveau avec les deux disques
-pour confirmer que tout fonctionne bien :
-
-    cat /proc/mdstat
-
-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]]

Add a French translation for my RAID article
diff --git a/posts/replacing-a-failed-raid-drive/remplacer-un-disque-raid-defectueux.mdwn b/posts/replacing-a-failed-raid-drive/remplacer-un-disque-raid-defectueux.mdwn
new file mode 100644
index 0000000..83462a4
--- /dev/null
+++ b/posts/replacing-a-failed-raid-drive/remplacer-un-disque-raid-defectueux.mdwn
@@ -0,0 +1,118 @@
+[[!meta title="Remplacer un disque RAID défectueux"]]
+[[!meta date="2016-08-20T15:00:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+Traduction de l'article original anglais à
+<https://feeding.cloud.geek.nz/posts/replacing-a-failed-raid-drive/>.
+
+Voici la procédure que j'ai suivi pour remplacer un disque RAID défectueux
+sur une machine Debian.
+
+# Remplacer le disque
+
+Après avoir remarqué que `/dev/sdb` a été expulsé de mon RAID, j'ai utilisé
+[smartmontools](https://packages.debian.org/jessie/smartmontools) pour
+identifier le numéro de série du disque à retirer :
+
+    smartctl -a /dev/sdb
+
+Cette information en main, j'ai fermé l'ordinateur, retiré le disque
+défectueux et mis un nouveau disque vide à la place.
+
+# Initialiser le nouveau disque
+
+Après avoir démarré avec le nouveau disque vide, j'ai copié la table
+de partitions avec [parted](https://packages.debian.org/jessie/parted).
+
+Premièrement, j'ai examiné la table de partitions sur le disque dur
+non-défectueux :
+
+    $ parted /dev/sda
+    unit s
+    print
+
+et créé une nouvelle table de partitions sur le disque de
+remplacement :
+
+    $ parted /dev/sdb
+    unit s
+    mktable gpt
+
+Ensuite j'ai utilisé la commande `mkpart` pour mes 4 partitions et je
+leur ai toutes donné la même taille que les partitions équivalentes
+sur `/dev/sda`.
+
+Finalement, j'ai utilisé les commandes `toggle 1 bios_grub` (partition
+d'amorce) et `toggle X raid` (où *X* est le numéro de la partition)
+pour toutes les partitions RAID, avant de vérifier avec la commande
+`print` que les deux tables de partitions sont maintenant identiques.
+
+# Resynchroniser/recréer les RAID
+
+Pour synchroniser les données du bon disque (`/dev/sda`) vers celui
+de remplacement (`/dev/sdb`), j'ai exécuté les commandes suivantes
+sur mes partitions RAID1 :
+
+    mdadm /dev/md0 -a /dev/sdb2
+    mdadm /dev/md2 -a /dev/sdb4
+
+et j'ai gardé un oeil sur le statut de la synchronisation avec :
+
+    watch -n 2 cat /proc/mdstat
+
+Pour [accélérer le processus](http://www.cyberciti.biz/tips/linux-raid-increase-resync-rebuild-speed.html),
+j'ai utilisé le truc suivant :
+
+    blockdev --setra 65536 "/dev/md0"
+    blockdev --setra 65536 "/dev/md2"
+    echo 300000 > /proc/sys/dev/raid/speed_limit_min
+    echo 1000000 > /proc/sys/dev/raid/speed_limit_max
+
+Ensuite, j'ai recréé ma partition *swap* RAID0 comme suit :
+
+    mdadm /dev/md1 --create --level=0 --raid-devices=2 /dev/sda3 /dev/sdb3
+    mkswap /dev/md1
+
+Par que la partition *swap* est toute neuve (il n'est pas possible de
+restorer une partition RAID0, il faut la re-créer complètement), j'ai dû
+faire deux choses:
+
+- remplacer le *UUID* pour *swap* dans `/etc/fstab`, avec le *UUID* donné
+  par la commande `mkswap` (ou bien en utilisant la command `blkid` et en
+  prenant le *UUID* pour `/dev/md1`)
+- remplacer le *UUID* de `/dev/md1` dans `/etc/mdadm/mdadm.conf` avec
+  celui retourné pour `/dev/md1` par la commande `mdadm --detail --scan`
+
+# S'assurer que l'on peut démarrer avec le disque de remplacement
+
+Pour être certain de bien pouvoir démarrer la machine avec n'importe quel
+des deux disques, j'ai réinstallé le *boot loader* grub sur le nouveau
+disque :
+
+    grub-install /dev/sdb
+
+avant de redémarrer avec les deux disques connectés. Ceci confirme que ma
+configuration fonctionne bien.
+
+Ensuite, j'ai démarré sans le disque `/dev/sda` pour m'assurer que tout
+fonctionnerait bien si ce disque décidait de mourir et de me laisser
+seulement avec le nouveau (`/dev/sdb`).
+
+Ce test brise évidemment la synchronisation entre les deux disques, donc
+j'ai dû redémarrer avec les deux disques connectés et puis ré-ajouter
+`/dev/sda` à tous les RAID1 :
+
+    mdadm /dev/md0 -a /dev/sda2
+    mdadm /dev/md2 -a /dev/sda4
+
+Une fois le tout fini, j'ai redémarrer à nouveau avec les deux disques
+pour confirmer que tout fonctionne bien :
+
+    cat /proc/mdstat
+
+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_2_2cedd0522a3f9562da399c8b485e8039._comment b/posts/replacing-a-failed-raid-drive/comment_2_2cedd0522a3f9562da399c8b485e8039._comment
new file mode 100644
index 0000000..ed67486
--- /dev/null
+++ b/posts/replacing-a-failed-raid-drive/comment_2_2cedd0522a3f9562da399c8b485e8039._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ ip="62.147.235.149"
+ subject="traduction en fr"
+ date="2016-08-20T09:12:00Z"
+ content="""
+Bonjour,
+
+Je suis très interressé par cet article mais ne comprend pas bien l'anglais. existe t'il une traduction fr quelque part.
+
+Merci.
+"""]]

Comment moderation
diff --git a/posts/the-perils-of-raid-and-full-disk-encryption-on-ubuntu/comment_1_b9dffe355ea3051446d6ca3c33647fec._comment b/posts/the-perils-of-raid-and-full-disk-encryption-on-ubuntu/comment_1_b9dffe355ea3051446d6ca3c33647fec._comment
new file mode 100644
index 0000000..d57e26e
--- /dev/null
+++ b/posts/the-perils-of-raid-and-full-disk-encryption-on-ubuntu/comment_1_b9dffe355ea3051446d6ca3c33647fec._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ ip="190.6.88.85"
+ claimedauthor="julio"
+ subject="worked fine in ubuntu server 16.04 64bit, not in 32bit"
+ date="2016-08-10T21:14:13Z"
+ content="""
+I have tried this patch in both versions of Ubuntu server 16.04 (32 and 64 bit) in a Virtual Box vm. I found that the 64 bit editions it's fine, but the 32 bit edition does not boot up. It stops with the message \"cryptsetup: lvm is not available\" Perhaps there is a way to solve this, but is far from my knowledge. Thanks for the patch.
+
+Kind regards
+"""]]

Add two missing sizes available on iTunes
diff --git a/posts/extracting-album-covers-from-the-itunes-store.mdwn b/posts/extracting-album-covers-from-the-itunes-store.mdwn
index 0499122..89de05e 100644
--- a/posts/extracting-album-covers-from-the-itunes-store.mdwn
+++ b/posts/extracting-album-covers-from-the-itunes-store.mdwn
@@ -8,6 +8,8 @@ visit the page and right-click on the cover image, you will get a **170 px
 by 170 px** image. Change the `170x170` in the URL to one of the following
 values to get a higher resolution image:
 
+- `64x64`
+- `100x100`
 - `170x170`
 - `340x340`
 - `600x600`

Comment moderation
diff --git a/posts/replacing-a-failed-raid-drive/comment_1_897ab4b5e589ef0b5f3ea8909fbe0c3e._comment b/posts/replacing-a-failed-raid-drive/comment_1_897ab4b5e589ef0b5f3ea8909fbe0c3e._comment
new file mode 100644
index 0000000..c194425
--- /dev/null
+++ b/posts/replacing-a-failed-raid-drive/comment_1_897ab4b5e589ef0b5f3ea8909fbe0c3e._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ ip="24.178.215.44"
+ subject="Command to copy partition table setup to another drive"
+ date="2016-07-25T14:48:09Z"
+ content="""
+Here's a quick tip for copying the partition table setup from one drive to the other:
+
+(sda is source, sdb is destination)
+
+sfdisk -d /dev/sda | sfdisk --force /dev/sdb
+"""]]

Comment moderation
diff --git a/posts/cleaning-up-obsolete-config-files-debian-ubuntu/comment_2_f7abad12da38bcde1db4c61048f71079._comment b/posts/cleaning-up-obsolete-config-files-debian-ubuntu/comment_2_f7abad12da38bcde1db4c61048f71079._comment
new file mode 100644
index 0000000..bd44919
--- /dev/null
+++ b/posts/cleaning-up-obsolete-config-files-debian-ubuntu/comment_2_f7abad12da38bcde1db4c61048f71079._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ ip="2001:470:71:1b:224:1dff:fed1:8e63"
+ claimedauthor="klg"
+ subject="Transitional packages "
+ date="2016-06-13T00:05:18Z"
+ content="""
+I found that on my system all cases when your rm-and-reinstall procedure failed to clear the file off the obsolete list was exactly because of what you suspected—some other package than the one given by `dpkg -S` had installed the file in the first place.  So for the record, `dpkg -W` can tell you which package to look for:
+
+    dpkg-query -W '-f=${Package}\n${Conffiles}\n' | awk '/^[^ ]/{pkg=$1}/ obsolete$/{print pkg,$0}'
+
+"""]]

Add a new RAID post
diff --git a/posts/replacing-a-failed-raid-drive.mdwn b/posts/replacing-a-failed-raid-drive.mdwn
new file mode 100644
index 0000000..33622d6
--- /dev/null
+++ b/posts/replacing-a-failed-raid-drive.mdwn
@@ -0,0 +1,106 @@
+[[!meta title="Replacing a failed RAID drive"]]
+[[!meta date="2016-07-22T22:00:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+Here's the complete procedure I followed to replace a failed drive from a
+RAID array on a Debian machine.
+
+# Replace the failed drive
+
+After seeing that `/dev/sdb` had been kicked out of my RAID array, I used
+[smartmontools](https://packages.debian.org/jessie/smartmontools) to
+identify the serial number of the drive to pull out:
+
+    smartctl -a /dev/sdb
+
+Armed with this information, I shutdown the computer, pulled the bad drive
+out and put the new blank one in.
+
+# Initialize the new drive
+
+After booting with the new blank drive in, I copied the partition table
+using [parted](https://packages.debian.org/jessie/parted).
+
+First, I took a look at what the partition table looks like on the good
+drive:
+
+    $ parted /dev/sda
+    unit s
+    print
+
+and created a new empty one on the replacement drive:
+
+    $ parted /dev/sdb
+    unit s
+    mktable gpt
+
+then I ran `mkpart` for all 4 partitions and made them all the same size as
+the matching ones on `/dev/sda`.
+
+Finally, I ran `toggle 1 bios_grub` (boot partition) and `toggle X raid`
+(where *X* is the partition number) for all RAID partitions, before
+verifying using `print` that the two partition tables were now the same.
+
+# Resync/recreate the RAID arrays
+
+To sync the data from the good drive (`/dev/sda`) to the replacement one
+(`/dev/sdb`), I ran the following on my RAID1 partitions:
+
+    mdadm /dev/md0 -a /dev/sdb2
+    mdadm /dev/md2 -a /dev/sdb4
+
+and kept an eye on the status of this sync using:
+
+    watch -n 2 cat /proc/mdstat
+
+In order to [speed up the
+sync](http://www.cyberciti.biz/tips/linux-raid-increase-resync-rebuild-speed.html),
+I used the following trick:
+
+    blockdev --setra 65536 "/dev/md0"
+    blockdev --setra 65536 "/dev/md2"
+    echo 300000 > /proc/sys/dev/raid/speed_limit_min
+    echo 1000000 > /proc/sys/dev/raid/speed_limit_max
+
+Then, I recreated my RAID0 swap partition like this:
+
+    mdadm /dev/md1 --create --level=0 --raid-devices=2 /dev/sda3 /dev/sdb3
+    mkswap /dev/md1
+
+Because the swap partition is brand new (you can't restore a RAID0, you need
+to re-create it), I had to update two things:
+
+- replace the UUID for the swap mount in `/etc/fstab`, with the one returned
+  by `mkswap` (or running `blkid` and looking for `/dev/md1`)
+- replace the UUID for `/dev/md1` in `/etc/mdadm/mdadm.conf` with the one
+  returned for `/dev/md1` by `mdadm --detail --scan`
+
+# Ensuring that I can boot with the replacement drive
+
+In order to be able to boot from both drives, I reinstalled the grub boot
+loader onto the replacement drive:
+
+    grub-install /dev/sdb
+
+before rebooting with both drives to first make sure that my new config
+works.
+
+Then I booted without `/dev/sda` to make sure that everything would be fine
+should that drive fail and leave me with just the new one (`/dev/sdb`).
+
+This test obviously gets the two drives out of sync, so I rebooted with both
+drives plugged in and then had to re-add `/dev/sda` to the RAID1 arrays:
+
+    mdadm /dev/md0 -a /dev/sda2
+    mdadm /dev/md2 -a /dev/sda4
+
+Once that finished, I rebooted again with both drives plugged in to confirm
+that everything is fine:
+
+    cat /proc/mdstat
+
+Then I ran a full SMART test over the new replacement drive:
+
+    smartctl -t long /dev/sdb
+
+[[!tag nzoss]] [[!tag sysadmin]] [[!tag debian]] [[!tag raid]]

How to search for old owners of config files
diff --git a/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn b/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn
index 3e2f8a4..be819ae 100644
--- a/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn
+++ b/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn
@@ -73,4 +73,8 @@ Not sure why I had to do this but I suspect that these files used to be
 shipped by one of the apparmor packages and then eventually migrated to the
 `evince` and `ntp` packages directly and dpkg got confused.
 
+If you're in a similar circumstance, you want want to search for the file you're
+trying to get rid of on Google and then you might end up on <http://apt-browse.org/>
+which could lead you to the old package that used to own this file.
+
 [[!tag sysadmin]] [[!tag debian]] [[!tag nzoss]]

Improve grep call to avoid picking up files with "obsolete" in their name
This was suggested by Antonio, a blog reader.
diff --git a/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn b/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn
index 548c361..3e2f8a4 100644
--- a/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn
+++ b/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn
@@ -17,7 +17,7 @@ easy to find and somewhat incomplete.
 
 These are the obsolete conffiles I started with:
 
-    $ dpkg-query -W -f='${Conffiles}\n' | grep obsolete
+    $ dpkg-query -W -f='${Conffiles}\n' | grep 'obsolete$'
      /etc/apparmor.d/abstractions/evince ae2a1e8cf5a7577239e89435a6ceb469 obsolete
      /etc/apparmor.d/tunables/ntpd 5519e4c01535818cb26f2ef9e527f191 obsolete
      /etc/apparmor.d/usr.bin.evince 08a12a7e468e1a70a86555e0070a7167 obsolete
@@ -59,7 +59,7 @@ because purging the packages that they come from didn't help:
     $ dpkg -S /etc/apparmor.d/abstractions/evince
     evince: /etc/apparmor.d/abstractions/evince
     $ apt purge evince
-    $ dpkg-query -W -f='${Conffiles}\n' | grep obsolete
+    $ dpkg-query -W -f='${Conffiles}\n' | grep 'obsolete$'
      /etc/apparmor.d/abstractions/evince ae2a1e8cf5a7577239e89435a6ceb469 obsolete
      /etc/apparmor.d/usr.bin.evince 08a12a7e468e1a70a86555e0070a7167 obsolete
 

Comment moderation
diff --git a/posts/cleaning-up-obsolete-config-files-debian-ubuntu/comment_1_86722798c9f52b651feb4a9ab358faef._comment b/posts/cleaning-up-obsolete-config-files-debian-ubuntu/comment_1_86722798c9f52b651feb4a9ab358faef._comment
new file mode 100644
index 0000000..236bfab
--- /dev/null
+++ b/posts/cleaning-up-obsolete-config-files-debian-ubuntu/comment_1_86722798c9f52b651feb4a9ab358faef._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ ip="2001:a62:25a:d01:d85b:48f8:e4c1:4fea"
+ subject="Let's make it obsolete files"
+ date="2016-06-12T05:40:32Z"
+ content="""
+Often I forget to clean up things like /etc/ssh/ssh_host_ecdsa_key (or dsa) or similar pieces that should be. Maybe you can include those (and other) as well.
+
+Thanks for your insightful post.
+"""]]

Add post on cleaning up obsolete conffiles
diff --git a/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn b/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn
new file mode 100644
index 0000000..548c361
--- /dev/null
+++ b/posts/cleaning-up-obsolete-config-files-debian-ubuntu.mdwn
@@ -0,0 +1,76 @@
+[[!meta title="Cleaning up obsolete config files on Debian and Ubuntu"]]
+[[!meta date="2016-06-11T14:40:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+As part of regular operating system hygiene, I run a [cron
+job](https://github.com/fmarier/root-scripts/blob/master/apt-cron) which
+updates package metadata and looks for obsolete packages and configuration
+files.
+
+While there is already some easily available information on how to [purge
+unneeded or obsolete
+packages](https://raphaelhertzog.com/2011/01/31/debian-cleanup-tip-1-get-rid-of-useless-configuration-files/)
+and how to [clean up config files properly in maintainer scripts](https://raphaelhertzog.com/2010/10/07/the-right-way-to-remove-an-obsolete-conffile-in-a-debian-package/
+), the guidance on [how to delete obsolete config
+files](http://comments.gmane.org/gmane.linux.debian.devel.mentors/61287) is not
+easy to find and somewhat incomplete.
+
+These are the obsolete conffiles I started with:
+
+    $ dpkg-query -W -f='${Conffiles}\n' | grep obsolete
+     /etc/apparmor.d/abstractions/evince ae2a1e8cf5a7577239e89435a6ceb469 obsolete
+     /etc/apparmor.d/tunables/ntpd 5519e4c01535818cb26f2ef9e527f191 obsolete
+     /etc/apparmor.d/usr.bin.evince 08a12a7e468e1a70a86555e0070a7167 obsolete
+     /etc/apparmor.d/usr.sbin.ntpd a00aa055d1a5feff414bacc89b8c9f6e obsolete
+     /etc/bash_completion.d/initramfs-tools 7eeb7184772f3658e7cf446945c096b1 obsolete
+     /etc/bash_completion.d/insserv 32975fe14795d6fce1408d5fd22747fd obsolete
+     /etc/dbus-1/system.d/com.redhat.NewPrinterNotification.conf 8df3896101328880517f530c11fff877 obsolete
+     /etc/dbus-1/system.d/com.redhat.PrinterDriversInstaller.conf d81013f5bfeece9858706aed938e16bb obsolete
+
+
+To get rid of the `/etc/bash_completion.d/` files, I first determined what
+packages they were registered to:
+
+    $ dpkg -S /etc/bash_completion.d/initramfs-tools
+    initramfs-tools: /etc/bash_completion.d/initramfs-tools
+    $ dpkg -S /etc/bash_completion.d/insserv
+    initramfs-tools: /etc/bash_completion.d/insserv
+
+and then followed
+[Paul Wise's instructions](https://lists.debian.org/debian-mentors/2013/05/msg00115.html):
+
+    $ rm /etc/bash_completion.d/initramfs-tools /etc/bash_completion.d/insserv
+    $ apt install --reinstall initramfs-tools insserv
+
+For some reason that didn't work for the `/etc/dbus-1/system.d/` files
+and I had to purge and reinstall the relevant package:
+
+    $ dpkg -S /etc/dbus-1/system.d/com.redhat.NewPrinterNotification.conf
+    system-config-printer-common: /etc/dbus-1/system.d/com.redhat.NewPrinterNotification.conf
+    $ dpkg -S /etc/dbus-1/system.d/com.redhat.PrinterDriversInstaller.conf
+    system-config-printer-common: /etc/dbus-1/system.d/com.redhat.PrinterDriversInstaller.conf
+    
+    $ apt purge system-config-printer-common
+    $ apt install system-config-printer
+
+The files in `/etc/apparmor.d/` were even more complicated to deal with
+because purging the packages that they come from didn't help:
+
+    $ dpkg -S /etc/apparmor.d/abstractions/evince
+    evince: /etc/apparmor.d/abstractions/evince
+    $ apt purge evince
+    $ dpkg-query -W -f='${Conffiles}\n' | grep obsolete
+     /etc/apparmor.d/abstractions/evince ae2a1e8cf5a7577239e89435a6ceb469 obsolete
+     /etc/apparmor.d/usr.bin.evince 08a12a7e468e1a70a86555e0070a7167 obsolete
+
+I was however able to get rid of them by also purging the apparmor profile
+packages that are installed on my machine:
+
+    $ apt purge apparmor-profiles apparmor-profiles-extra evince ntp
+    $ apt install apparmor-profiles apparmor-profiles-extra evince ntp
+
+Not sure why I had to do this but I suspect that these files used to be
+shipped by one of the apparmor packages and then eventually migrated to the
+`evince` and `ntp` packages directly and dpkg got confused.
+
+[[!tag sysadmin]] [[!tag debian]] [[!tag nzoss]]

Comment moderation
diff --git a/posts/simple-remote-mail-queue-monitoring/comment_1_48a1e348d883cf336e82e3741987c16d._comment b/posts/simple-remote-mail-queue-monitoring/comment_1_48a1e348d883cf336e82e3741987c16d._comment
new file mode 100644
index 0000000..f674cd9
--- /dev/null
+++ b/posts/simple-remote-mail-queue-monitoring/comment_1_48a1e348d883cf336e82e3741987c16d._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ ip="178.236.196.236"
+ claimedauthor="Marius Gedminas"
+ url="https://gedmin.as"
+ subject="Healthchecks"
+ date="2016-06-08T06:48:41Z"
+ content="""
+Recently I've discovered [healthchecks.io](https://healthchecks.io), which is a free (and also FOSS) service that can check whether your mail server can deliver email.
+
+The way it works: you configure a cron script on your server to send email to `<uuid>@healtchecks.io`, and if that email doesn't arrive for a set period (say, 24 hours, if you want one daily check), healtchecks.io will drop you a notification.
+"""]]

Lowercase the post title
diff --git a/posts/simple-remote-mail-queue-monitoring.mdwn b/posts/simple-remote-mail-queue-monitoring.mdwn
index c305d95..8296325 100644
--- a/posts/simple-remote-mail-queue-monitoring.mdwn
+++ b/posts/simple-remote-mail-queue-monitoring.mdwn
@@ -1,4 +1,4 @@
-[[!meta title="Simple Remote Mail Queue Monitoring"]]
+[[!meta title="Simple remote mail queue monitoring"]]
 [[!meta date="2016-06-07T22:30:00.000-07:00"]]
 [[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
 

Add remote mailq monitoring post
diff --git a/posts/simple-remote-mail-queue-monitoring.mdwn b/posts/simple-remote-mail-queue-monitoring.mdwn
new file mode 100644
index 0000000..c305d95
--- /dev/null
+++ b/posts/simple-remote-mail-queue-monitoring.mdwn
@@ -0,0 +1,63 @@
+[[!meta title="Simple Remote Mail Queue Monitoring"]]
+[[!meta date="2016-06-07T22:30:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+In order to monitor some of the [machines I
+maintain](https://feeding.cloud.geek.nz/posts/usual-server-setup/), I rely
+on a simple email setup using
+[logcheck](https://packages.debian.org/sid/logcheck). Unfortunately that
+system completely breaks down if mail delivery stops.
+
+This is the simple setup I've come up with to ensure that mail doesn't
+pile up on the remote machine.
+
+# Server setup
+
+The first thing I did on the server-side is to follow [Sean Whitton's
+advice](https://spwhitton.name//blog/entry/postfixexpiry/) and configure
+postfix so that it keeps undelivered emails for 10 days (instead of 5 days,
+the default):
+
+    postconf -e maximal_queue_lifetime=10d
+
+Then I created a new user:
+
+    adduser mailq-check
+
+with a password straight out of `pwgen -s 32`.
+
+I gave [ssh
+permission](https://feeding.cloud.geek.nz/posts/hardening-ssh-servers/) to
+that user:
+
+    adduser mailq-check sshuser
+
+and then authorized my new ssh key (see next section):
+
+    sudo -u mailq-check -i
+    mkdir ~/.ssh/
+    cat - > ~/.ssh/authorized_keys
+
+# Laptop setup
+
+On my laptop, the machine from where I monitor the server's mail queue, I
+first created a new password-less ssh key:
+
+    ssh-keygen -t ed25519 -f .ssh/egilsstadir-mailq-check
+    cat ~/.ssh/egilsstadir-mailq-check.pub
+
+which I then installed on the server.
+
+Then I added this cronjob in `/etc/cron.d/egilsstadir-mailq-check`:
+
+    0 2 * * * francois /usr/bin/ssh -i /home/francois/.ssh/egilsstadir-mailq-check mailq-check@egilsstadir mailq | grep -v "Mail queue is empty"
+
+and that's it. I get a (locally delivered) email whenever the mail queue on
+the server is non-empty.
+
+There is a race condition built into this setup since it's possible that the
+server will want to send an email at 2am. However, all that does is send a
+spurious warning email in that case and so it's a pretty small price to pay
+for a dirt simple setup that's unlikely to break.
+
+[[!tag sysadmin]] [[!tag debian]] [[!tag nzoss]]

Add one more security option
diff --git a/posts/using-openvpn-on-android-lollipop.mdwn b/posts/using-openvpn-on-android-lollipop.mdwn
index adce3f1..ecc7bb6 100644
--- a/posts/using-openvpn-on-android-lollipop.mdwn
+++ b/posts/using-openvpn-on-android-lollipop.mdwn
@@ -62,6 +62,10 @@ Authentication/Encryption:
 - Encryption cipher: `AES-256-CBC`
 - Packet authentication: `SHA384` (**not** `SHA-384`)
 
+Advanced:
+
+- Persistent tun: `YES`
+
 That's it. Everything else should work with the defaults.
 
 [[!tag security]] [[!tag android]] [[!tag debian]] [[!tag nzoss]] [[!tag openvpn]]

Remove unnecessary comment and fix formatting in another
diff --git a/posts/prefetching-resources-to-prime-browser/comment_1_6a8540d2335fa6c1dcf948c4a247c6aa._comment b/posts/prefetching-resources-to-prime-browser/comment_1_6a8540d2335fa6c1dcf948c4a247c6aa._comment
index ccb654e..6bed93a 100644
--- a/posts/prefetching-resources-to-prime-browser/comment_1_6a8540d2335fa6c1dcf948c4a247c6aa._comment
+++ b/posts/prefetching-resources-to-prime-browser/comment_1_6a8540d2335fa6c1dcf948c4a247c6aa._comment
@@ -7,5 +7,5 @@
  content="""
 Well written, thanks.
 
-However, you may find useful my blog post about prefetching resources, see: http://zinoui.com/blog/prefetching-resources
+However, you may find useful my blog post about prefetching resources, see: <http://zinoui.com/blog/prefetching-resources>
 """]]
diff --git a/posts/setting-default-git-branch-in-bare/comment_1_567cc077118fdb41e5a695525da07c09._comment b/posts/setting-default-git-branch-in-bare/comment_1_567cc077118fdb41e5a695525da07c09._comment
deleted file mode 100644
index f4ee5e6..0000000
--- a/posts/setting-default-git-branch-in-bare/comment_1_567cc077118fdb41e5a695525da07c09._comment
+++ /dev/null
@@ -1,10 +0,0 @@
-[[!comment format=mdwn
- username="http://www.nemodreaming.com"
- nickname="nemoDreamer"
- subject=""
- date="2009-09-03T03:54:55.533+12:00"
- content="""
-thanks a bunch for this! setting up git repo on mediatemple grid, and this came in very handy ;)
-
-
-"""]]

Comment moderation
diff --git a/posts/prefetching-resources-to-prime-browser/comment_1_6a8540d2335fa6c1dcf948c4a247c6aa._comment b/posts/prefetching-resources-to-prime-browser/comment_1_6a8540d2335fa6c1dcf948c4a247c6aa._comment
new file mode 100644
index 0000000..ccb654e
--- /dev/null
+++ b/posts/prefetching-resources-to-prime-browser/comment_1_6a8540d2335fa6c1dcf948c4a247c6aa._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ ip="79.100.55.171"
+ claimedauthor="Dimitar Ivanov"
+ url="http://zinoui.com"
+ subject="Prefetching resources"
+ date="2016-05-29T11:49:01Z"
+ content="""
+Well written, thanks.
+
+However, you may find useful my blog post about prefetching resources, see: http://zinoui.com/blog/prefetching-resources
+"""]]

Fix formatting
diff --git a/posts/using-openvpn-on-ios-and-osx.mdwn b/posts/using-openvpn-on-ios-and-osx.mdwn
index 6afaf67..c5e7641 100644
--- a/posts/using-openvpn-on-ios-and-osx.mdwn
+++ b/posts/using-openvpn-on-ios-and-osx.mdwn
@@ -76,23 +76,23 @@ Here are the settings you'll need to change when setting up a new VPN
 connection:
 
 - **General**
- - Remote server: `hafnarfjordur.fmarier.org`
+   - Remote server: `hafnarfjordur.fmarier.org`
 - **Authentication**
- - Type: SSL/TLS client
- - CA: `ca.crt`
- - Cert: `osx.crt`
- - Key: `osx.key`
- - Tls-Auth: `ta.key`
- - direction: 1
+   - Type: SSL/TLS client
+   - CA: `ca.crt`
+   - Cert: `osx.crt`
+   - Key: `osx.key`
+   - Tls-Auth: `ta.key`
+   - direction: 1
 - **Options**
- - peer certificate: require server nsCertType
- - compression: turn LZO on
+   - peer certificate: require server nsCertType
+   - compression: turn LZO on
 - **Networking**
- - send all traffic on VPN
+   - send all traffic on VPN
 - **Advanced**
- - add the following extra OpenVPN configuration commands:
+   - add the following extra OpenVPN configuration commands:
 
-            cipher AES-256-CBC
-            auth SHA384
+         cipher AES-256-CBC
+         auth SHA384
 
 [[!tag openvpn]]

Link to alternative OpenVPN clients from my main post
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 f54c8e9..a7c7b16 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
@@ -173,6 +173,8 @@ then click the "Avanced" button and set the following:
      * Key File: `/etc/openvpn/ta.key`
      * Key Direction: `1`
 
+There are also compatible clients on [Android](https://feeding.cloud.geek.nz/posts/using-openvpn-on-android-lollipop/), [iOS and OSX](https://feeding.cloud.geek.nz/posts/using-openvpn-on-ios-and-osx/).
+
 # Debugging
 
 If you run into problems, simply take a look at the logs while attempting to

Add OpenVPN post for iOS and OSX
diff --git a/posts/using-openvpn-on-ios-and-osx.mdwn b/posts/using-openvpn-on-ios-and-osx.mdwn
new file mode 100644
index 0000000..6afaf67
--- /dev/null
+++ b/posts/using-openvpn-on-ios-and-osx.mdwn
@@ -0,0 +1,98 @@
+[[!meta title="Using OpenVPN on iOS and OSX"]]
+[[!meta date="2016-05-26T22:50:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+I have written instructions on how to connect to [your own OpenVPN
+server](https://feeding.cloud.geek.nz/posts/creating-a-linode-based-vpn-setup-using_openvpn_on_debian_or_ubuntu/)
+using Network Manager as well as
+[Android](https://feeding.cloud.geek.nz/posts/using-openvpn-on-android-lollipop/).
+
+Here is how to do it on iOS and OSX assuming you have followed my
+instructions for the server setup.
+
+# Generate new keys
+
+From the easy-rsa directory you created while generating the server keys, create a new keypair for your phone:
+
+    ./build-key iphone   # "iphone" as Name, no password
+
+and for your laptop:
+
+    ./build-key osx      # "osx" as Name, no password
+
+# Using OpenVPN Connect on iOS
+
+The app you need to install from the App Store is [OpenVPN
+Connect](https://itunes.apple.com/us/app/openvpn-connect/id590379981).
+
+Once it's installed, connect your phone to your computer and [transfer the
+following files using iTunes](https://support.apple.com/kb/PH12318):
+
+- `ca.crt`
+- `iphone.crt`
+- `iphone.key`
+- `iphone.ovpn`
+- `ta.key`
+
+You should then be able to select it after launching the app. See the
+[official FAQ](https://docs.openvpn.net/docs/openvpn-connect/openvpn-connect-ios-faq.html)
+if you run into any problems.
+
+`iphone.ovpn` is a configuration file that you need to supply since the
+OpenVPN Connect app doesn't have a configuration interface. You can use [this
+script](https://gist.github.com/trovao/18e428b5a758df24455b) to generate it
+or write it from scratch [using this
+template](https://openvpn.net/index.php/open-source/documentation/howto.html#client).
+
+On Linux, you can also create a configuration file using [Network Manager 1.2](https://blogs.gnome.org/lkundrak/2016/04/20/networkmanager-1-2-is-here/),
+use the following command:
+
+    nmcli connection export hafnarfjordur > iphone.ovpn
+
+though that didn't quite work in my experience.
+
+Here is the config I successfully used to connect to my server:
+
+    client
+    remote hafnarfjordur.fmarier.org 1194
+    ca ca.crt
+    cert iphone.crt
+    key iphone.key
+    cipher AES-256-CBC
+    auth SHA384
+    comp-lzo yes
+    proto udp
+    tls-remote server
+    remote-cert-tls server
+    ns-cert-type server
+    tls-auth ta.key 1
+
+# Using Viscosity on Mac OSX
+
+One of the possible OpenVPN clients you can use on OSX is
+[Viscosity](https://www.sparklabs.com/viscosity/).
+
+Here are the settings you'll need to change when setting up a new VPN
+connection:
+
+- **General**
+ - Remote server: `hafnarfjordur.fmarier.org`
+- **Authentication**
+ - Type: SSL/TLS client
+ - CA: `ca.crt`
+ - Cert: `osx.crt`
+ - Key: `osx.key`
+ - Tls-Auth: `ta.key`
+ - direction: 1
+- **Options**
+ - peer certificate: require server nsCertType
+ - compression: turn LZO on
+- **Networking**
+ - send all traffic on VPN
+- **Advanced**
+ - add the following extra OpenVPN configuration commands:
+
+            cipher AES-256-CBC
+            auth SHA384
+
+[[!tag openvpn]]

Suggest backing up the config file too
diff --git a/posts/encrypted-system-backup-to-dvd.mdwn b/posts/encrypted-system-backup-to-dvd.mdwn
index a08fd55..0e4bfc6 100644
--- a/posts/encrypted-system-backup-to-dvd.mdwn
+++ b/posts/encrypted-system-backup-to-dvd.mdwn
@@ -79,12 +79,11 @@ and then copy the files you want to `/backup/` before unmounting that partition:
     cryptmount -u backup
 
 
-Finally, use your favourite DVD-burning program to burn these two files:  
+Finally, use your favourite DVD-burning program to burn these files:
 
   * `/backup.dat`
   * `/backup.key`
-
-  
+  * `/etc/cryptmount/cmtab`
 
 ### Test your backup
 

Use a more modern mount point for the optical drive
diff --git a/posts/encrypted-system-backup-to-dvd.mdwn b/posts/encrypted-system-backup-to-dvd.mdwn
index 79ffca0..a08fd55 100644
--- a/posts/encrypted-system-backup-to-dvd.mdwn
+++ b/posts/encrypted-system-backup-to-dvd.mdwn
@@ -33,12 +33,12 @@ and setup two encrypted mount points in `/etc/cryptmount/cmtab`:
     }  
       
     testbackup {  
-      dev=/cdrom/backup.dat  
+      dev=/media/cdrom/backup.dat
       dir=/backup  
       fstype=ext4
       mountoptions=defaults,noatime
 
-      keyfile=/cdrom/backup.key
+      keyfile=/media/cdrom/backup.key
       keyhash=sha512
       keycipher=aes-xts-plain64
       keyformat=builtin

Mention dual-layer DVDs
diff --git a/posts/encrypted-system-backup-to-dvd.mdwn b/posts/encrypted-system-backup-to-dvd.mdwn
index 9d1c432..79ffca0 100644
--- a/posts/encrypted-system-backup-to-dvd.mdwn
+++ b/posts/encrypted-system-backup-to-dvd.mdwn
@@ -60,8 +60,10 @@ Make sure you have at least 4.3 GB of free disk space on `/` and then run:
     mkfs.ext4 -m 0 /dev/mapper/backup
     cryptmount --release backup
 
+Alternatively, if you're using a double-layer DVD then use this `dd` line:
+
+    dd if=/dev/zero of=/backup.dat bs=1M count=8000
 
-  
 
 ### Burn the data to a DVD
 

Fix typo in stylesheet
diff --git a/local.css b/local.css
index 88c0ec2..e493fc2 100644
--- a/local.css
+++ b/local.css
@@ -49,7 +49,7 @@ code, pre {
 }
 
 .page {
-  max-width: 75em'
+  max-width: 75em;
 }
 
 #pagebody {

Put a maximum width on the page to eliminate the middle gap
Use a variable unit instead of pixels.
diff --git a/local.css b/local.css
index ffe05b6..88c0ec2 100644
--- a/local.css
+++ b/local.css
@@ -48,8 +48,12 @@ code, pre {
   display: none;
 }
 
+.page {
+  max-width: 75em'
+}
+
 #pagebody {
-  width: 800px;
+  width: 60em;
 }
 
 .inlinepage {

Add one more OpenVPN security option
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 d95f130..f54c8e9 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
@@ -166,10 +166,12 @@ then click the "Avanced" button and set the following:
 * TLS Authentication
    * Subject Match: `server`
    * Verify peer (server) certificate usage signature: `YES`
-   * Remote peer certificate TLS type: `Server`
+     * Remote peer certificate TLS type: `Server`
+   * Verify peer (server) certificate nsCertType designation: `YES`
+     * Remove peer certificate nsCert designation: `Server`
    * Use additional TLS authentication: `YES`
-   * Key File: `/etc/openvpn/ta.key`
-   * Key Direction: `1`
+     * Key File: `/etc/openvpn/ta.key`
+     * Key Direction: `1`
 
 # Debugging
 

Linkify links in comment
diff --git a/posts/using-dnssec-and-dnscrypt-in-debian/comment_4_545afce8af12bdc4be67837bd8f4cbc0._comment b/posts/using-dnssec-and-dnscrypt-in-debian/comment_4_545afce8af12bdc4be67837bd8f4cbc0._comment
index 287bd7b..8ece79b 100644
--- a/posts/using-dnssec-and-dnscrypt-in-debian/comment_4_545afce8af12bdc4be67837bd8f4cbc0._comment
+++ b/posts/using-dnssec-and-dnscrypt-in-debian/comment_4_545afce8af12bdc4be67837bd8f4cbc0._comment
@@ -3,7 +3,7 @@
  subject="comment 4"
  date="2016-04-26T19:26:33Z"
  content="""
-There's some documentation on https://wiki.debian.org/HowTo/dnsmasq
+There's some documentation on <https://wiki.debian.org/HowTo/dnsmasq>
 
-Unfortunately this setup still leaks the client IP address to the resolver. There's no way to use dnscrypt over Tor yet: https://github.com/jedisct1/dnscrypt-proxy/issues/234
+Unfortunately this setup still leaks the client IP address to the resolver. There's no way to use dnscrypt over Tor yet: <https://github.com/jedisct1/dnscrypt-proxy/issues/234>
 """]]

Comment moderation
diff --git a/posts/using-dnssec-and-dnscrypt-in-debian/comment_5_2ab8705fa57287d2979ad846f184129c._comment b/posts/using-dnssec-and-dnscrypt-in-debian/comment_5_2ab8705fa57287d2979ad846f184129c._comment
new file mode 100644
index 0000000..b7b7d9e
--- /dev/null
+++ b/posts/using-dnssec-and-dnscrypt-in-debian/comment_5_2ab8705fa57287d2979ad846f184129c._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ ip="79.248.243.100"
+ claimedauthor="Jonathan"
+ subject="Why encrypt DNS?"
+ date="2016-04-27T12:18:51Z"
+ content="""
+Why encrypt DNS when your browser still leaks the domain name via SNI extension, even though it runs over https?
+https://wikipedia.org/wiki/Server_Name_Indication
+"""]]

Comment moderation
diff --git a/posts/using-dnssec-and-dnscrypt-in-debian/comment_4_545afce8af12bdc4be67837bd8f4cbc0._comment b/posts/using-dnssec-and-dnscrypt-in-debian/comment_4_545afce8af12bdc4be67837bd8f4cbc0._comment
new file mode 100644
index 0000000..287bd7b
--- /dev/null
+++ b/posts/using-dnssec-and-dnscrypt-in-debian/comment_4_545afce8af12bdc4be67837bd8f4cbc0._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ ip="87.198.117.114"
+ subject="comment 4"
+ date="2016-04-26T19:26:33Z"
+ content="""
+There's some documentation on https://wiki.debian.org/HowTo/dnsmasq
+
+Unfortunately this setup still leaks the client IP address to the resolver. There's no way to use dnscrypt over Tor yet: https://github.com/jedisct1/dnscrypt-proxy/issues/234
+"""]]

Comment moderation
diff --git a/posts/using-dnssec-and-dnscrypt-in-debian/comment_3_20b2089026a443843ce44d29b4636fce._comment b/posts/using-dnssec-and-dnscrypt-in-debian/comment_3_20b2089026a443843ce44d29b4636fce._comment
new file mode 100644
index 0000000..badb16c
--- /dev/null
+++ b/posts/using-dnssec-and-dnscrypt-in-debian/comment_3_20b2089026a443843ce44d29b4636fce._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="francois@665656f0ba400877c9b12e8fbb086e45aa01f7c0"
+ nickname="francois"
+ subject="Re: comment 2"
+ date="2016-04-26T17:39:49Z"
+ content="""
+> Not sure if dnscrypt-proxy caches but it doesn't seem that useful as general advise if it doesn't and everyone uses a proxy in Iceland.
+
+I don't believe that `dnsproxy-crypt` caches (the name implies it doesn't), but Unbound does.
+"""]]

Comment moderation
diff --git a/posts/using-dnssec-and-dnscrypt-in-debian/comment_2_0630500f8395ee80699898e5cfbd02cc._comment b/posts/using-dnssec-and-dnscrypt-in-debian/comment_2_0630500f8395ee80699898e5cfbd02cc._comment
new file mode 100644
index 0000000..ee3bed0
--- /dev/null
+++ b/posts/using-dnssec-and-dnscrypt-in-debian/comment_2_0630500f8395ee80699898e5cfbd02cc._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ ip="80.187.102.79"
+ claimedauthor="Philipp Kern"
+ subject="comment 2"
+ date="2016-04-26T08:05:53Z"
+ content="""
+There is a reason why every ISP provides a recursor: latency. Every new connection that uses a name (unless cached locally with a caching resolver), every newly launched binary that connects somewhere needs to bear DNS latency. Not sure if dnscrypt-proxy caches but it doesn't seem that useful as general advise if it doesn't and everyone uses a proxy in Iceland.
+"""]]

Comment moderation
diff --git a/posts/using-dnssec-and-dnscrypt-in-debian/comment_1_d0e1658e877938c1c61402818043e57f._comment b/posts/using-dnssec-and-dnscrypt-in-debian/comment_1_d0e1658e877938c1c61402818043e57f._comment
new file mode 100644
index 0000000..4187d88
--- /dev/null
+++ b/posts/using-dnssec-and-dnscrypt-in-debian/comment_1_d0e1658e877938c1c61402818043e57f._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ ip="203.167.144.68"
+ claimedauthor="Ewen McNeill"
+ subject="Captive portals"
+ date="2016-04-26T04:06:48Z"
+ content="""
+FWIW, my usual solution to captive portals is to add some exceptions to the DNS resolution/HTTP proxy, which forces enough requests to go \"directly\" to be able to log into the captive portal.  Eg, the domain of the place I'm staying in, and the domain of whatever Wifi provider they're using.  Then I trigger the captive port by, eg, trying to go to the domain of the place I'm staying in.  Over time one could accumulate a list of such exceptions required (and it seems like something that could be crowd sourced).
+
+For better privacy one would perhaps want to selectively enable these exceptions based on the current location (and/or selectively disable them if at known locations like home/work/etc when it's not needed).
+
+Ewen
+
+PS: If your names are resolved from a location far away from you, you'll also generally get CDN nodes which are far away from you.  Which may lead to poor performance.  YMMV.
+"""]]

Add DNSCrypt blogpost and update old Unbound post
diff --git a/posts/setting-up-your-own-dnssec-aware.mdwn b/posts/setting-up-your-own-dnssec-aware.mdwn
index 3e7bc0a..a5b458b 100644
--- a/posts/setting-up-your-own-dnssec-aware.mdwn
+++ b/posts/setting-up-your-own-dnssec-aware.mdwn
@@ -6,91 +6,91 @@ Now that the root DNS servers are [signed,](http://www.root-dnssec.org/2010/07/1
 
 ## Installing Unbound
 
-Being already packaged in [Debian](http://packages.debian.org/source/unstable/unbound) and [Ubuntu](https://launchpad.net/ubuntu/+source/unbound), unbound is only an apt-get away:  
+Being already packaged in [Debian](http://packages.debian.org/source/unstable/unbound) and [Ubuntu](https://launchpad.net/ubuntu/+source/unbound), unbound is only an `apt-get` away:
 
 
     apt-get install unbound
 
-
-though if you are running [lenny](http://www.debian.org/releases/lenny/), I suggest you grab the latest [backport](http://backports.debian.org/Instructions/).  
-  
-Once unbound is installed, follow [these instructions](http://www.unbound.net/documentation/howto_anchor.html) to enable DNSSEC.  
-  
-
 ## Optional settings
 
-In my `/etc/unbound/unbound.conf`, I enabled the following security options:  
-
+In `/etc/unbound/unbound.conf.d/francois.conf`, I enabled the following security options:
 
-    harden-referral-path: yes  
-    use-caps-for-id: yes
+    harden-below-nxdomain: yes
+    harden-referral-path: yes
+    harden-algo-downgrade: no # false positives with improperly configured zones
+    use-caps-for-id: no # makes lots of queries fail
+    hide-identity: yes
+    hide-version: yes
 
+and turned on prefetching to hopefully keep in cache the sites I visit regularly:
 
-and turned on prefetching to hopefully keep in cache the sites I visit regularly:  
 
-
-    prefetch: yes  
+    prefetch: yes
     prefetch-key: yes
-
-
-Finally, I also enabled statistics:  
-
-
-    extended-statistics: yes  
-    control-enable: yes  
+    msg-cache-size: 128k
+    msg-cache-slabs: 2
+    rrset-cache-size: 8m
+    rrset-cache-slabs: 2
+    key-cache-size: 32m
+    key-cache-slabs: 2
+    cache-min-ttl: 3600
+    num-threads: 2
+
+Finally, I also enabled the control interface:
+
+    control-enable: yes
     control-interface: 127.0.0.1
 
+and increased the amount of debugging information:
+
+    val-log-level: 2
+    use-syslog: yes
+    verbosity: 1
 
-and ran `sudo unbound-control-setup` to generate the necessary keys.  
+before running `sudo unbound-control-setup` to generate the necessary keys.
   
-Once unbound is restarted (`sudo /etc/init.d/unbound restart`) stats can be queried to make sure that the DNS resolver is working:  
+Once unbound is restarted (`sudo service unbound restart`) stats can be queried to make sure that the DNS resolver is working:
 
 
     unbound-control stats
-
-
   
 
 ## Overriding DHCP settings
 
-In order to use my own unbound server for DNS lookups and not the one received via [DHCP](https://secure.wikimedia.org/wikipedia/en/wiki/Dhcp), I added this line to `/etc/dhcp/dhclient.conf`:  
+In order to use my own unbound server for DNS lookups and not the one received via [DHCP](https://secure.wikimedia.org/wikipedia/en/wiki/Dhcp), I added this line to `/etc/dhcp/dhclient.conf`:
 
 
     supersede domain-name-servers 127.0.0.1;
 
 
-and restarted dhclient:  
+and restarted dhclient:
 
 
-    sudo killall dhclient  
-    sudo killall dhclient  
+    sudo killall dhclient
+    sudo killall dhclient
     sudo /etc/init.d/network-manager restart
 
 
-If you're not using DHCP, then you simply need to put this in your `/etc/resolv.conf`:  
+If you're not using DHCP, then you simply need to put this in your `/etc/resolv.conf`:
 
 
     nameserver 127.0.0.1
-
-
   
 
 ## Testing DNSSEC resolution
 
-Once everything is configured properly, the best way I found to test that this setup was actually working is to use a web browser to visit these sites:  
+Once everything is configured properly, the best way I found to test that this setup was actually working is to use a web browser to visit these sites:
 
   * [http://www.dnssec.cz/](http://www.dnssec.cz/) should show a green key
   * [http://www.rhybar.cz/](http://www.rhybar.cz/) should not be reachable
 
-and using dig:  
+and using dig:
 
-<pre>
+```
 $ dig +dnssec A www.dnssec.cz | grep ad  
 ;; flags: qr rd ra <b>ad</b>; QUERY: 1, ANSWER: 2, AUTHORITY: 3, ADDITIONAL: 1
-</pre>
-
+```
   
 Are there any other ways of making sure that DNSSEC is fully functional?
 
-
 [[!tag catalyst]] [[!tag debian]] [[!tag sysadmin]] [[!tag security]] [[!tag ubuntu]] [[!tag nzoss]] [[!tag dns]] [[!tag dnssec]]
diff --git a/posts/using-dnssec-and-dnscrypt-in-debian.mdwn b/posts/using-dnssec-and-dnscrypt-in-debian.mdwn
new file mode 100644
index 0000000..3722667
--- /dev/null
+++ b/posts/using-dnssec-and-dnscrypt-in-debian.mdwn
@@ -0,0 +1,101 @@
+[[!meta title="Using DNSSEC and DNSCrypt in Debian"]]
+[[!meta date="2016-04-25T20:00:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+While there is real progress being made towards
+[eliminating insecure HTTP traffic](https://blog.mozilla.org/security/2015/04/30/deprecating-non-secure-http/),
+[DNS](https://en.wikipedia.org/wiki/Domain_Name_System) is a fundamental
+Internet service that still usually relies on unauthenticated cleartext.
+There are however a few efforts to try and fix this problem. Here is the
+setup I use on my Debian laptop to make use of both
+[DNSSEC](http://www.dnssec.net/) and [DNSCrypt](https://dnscrypt.org/).
+
+# DNSCrypt
+
+DNSCrypt was created to enable end-users to encrypt the traffic between
+themselves and their chosen DNS resolver.
+
+To switch away from your ISP's default DNS resolver to a DNSCrypt resolver,
+simply install the [`dnscrypt-proxy` package](https://packages.debian.org/stretch/dnscrypt-proxy) and then
+set it as the default resolver either in `/etc/resolv.conf`:
+
+    nameserver 127.0.2.1
+
+if you are using a static network configuration or in
+`/etc/dhcp/dhclient.conf`:
+
+    supersede domain-name-servers 127.0.2.1;
+
+if you rely on dynamic network configuration via [DHCP](https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol).
+
+There are two things you might want to keep in mind when choosing your
+[DNSCrypt resolver](https://github.com/jedisct1/dnscrypt-proxy/blob/master/dnscrypt-resolvers.csv):
+
+- whether or not they keep any logs of the DNS traffic
+- whether or not they support DNSSEC
+
+I have personally selected a resolver located in Iceland by setting the
+following in `/etc/default/dnscrypt-proxy`:
+
+    DNSCRYPT_PROXY_RESOLVER_NAME=ns0.dnscrypt.is
+
+# DNSSEC
+
+While DNSCrypt protects the confidentiality of our DNS queries, it doesn't
+give us any assurance that the results of such queries are the right ones.
+In order to authenticate results in that way and prevent DNS poisoning, a
+hierarchical cryptographic system was created: DNSSEC.
+
+In order to enable it, I have [setup a local unbound DNSSEC
+resolver](https://feeding.cloud.geek.nz/posts/setting-up-your-own-dnssec-aware/)
+on my machine and pointed `/etc/resolv.conf` (or
+`/etc/dhcp/dhclient.conf`) to my unbound installation at `127.0.0.1`.
+
+Then I put the following in `/etc/unbound/unbound.conf.d/dnscrypt.conf`:
+
+    server:
+        # Remove localhost from the donotquery list
+        do-not-query-localhost: no
+
+    forward-zone:

(Diff truncated)
Replace proprietary Android app with free one
diff --git a/posts/setting-wifi-regulatory-domain-linux-openwrt.mdwn b/posts/setting-wifi-regulatory-domain-linux-openwrt.mdwn
index 0ee2b9b..e65b8ad 100644
--- a/posts/setting-wifi-regulatory-domain-linux-openwrt.mdwn
+++ b/posts/setting-wifi-regulatory-domain-linux-openwrt.mdwn
@@ -54,10 +54,9 @@ selected regulatory domain:
 
 Once your devices are set to the right country, you should scan the local
 environment to pick the least congested wifi channel. You can use the
-[Kismet spectools](https://kismetwireless.net/spectools/) (free software)
+[Kismet spectools](https://kismetwireless.net/spectools/)
 if you have the hardware, otherwise
-[WifiAnalyzer](https://play.google.com/store/apps/details?id=com.farproc.wifi.analyzer)
-(proprietary) is a good choice on Android (remember to manually set the
-available channels in the settings).
+[WiFi Analyzer](https://f-droid.org/repository/browse/?fdid=com.vrem.wifianalyzer)
+is a good choice on Android.
 
 [[!tag debian]] [[!tag openwrt]] [[!tag gargoyle]]

diff --git a/francois.mdwn b/francois.mdwn
new file mode 100644
index 0000000..5cd76d4
--- /dev/null
+++ b/francois.mdwn
@@ -0,0 +1 @@
+[Francois Marier](https://fmarier.org>), the author of this blog.

Comment moderation
diff --git a/posts/tweaking-cookies-for-privacy-in-firefox/comment_6_d09044affb8feb97a847fabaa09a7d11._comment b/posts/tweaking-cookies-for-privacy-in-firefox/comment_6_d09044affb8feb97a847fabaa09a7d11._comment
new file mode 100644
index 0000000..9cf6493
--- /dev/null
+++ b/posts/tweaking-cookies-for-privacy-in-firefox/comment_6_d09044affb8feb97a847fabaa09a7d11._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="francois@665656f0ba400877c9b12e8fbb086e45aa01f7c0"
+ nickname="francois"
+ subject="Re: Exceptions"
+ date="2016-04-14T02:29:52Z"
+ content="""
+> Do \"network.cookie.lifetimePolicy\" and \"network.cookie.lifetime.days\" affect exception domains that I explicitly set to allow cookies?
+
+The exceptions are [applied before the other restrictions](https://dxr.mozilla.org/mozilla-central/rev/21bf1af375c1fa8565ae3bb2e89bd1a0809363d4/extensions/cookie/nsCookiePermission.cpp#192-202) and so the `network.cookie.lifetimePolicy` and `network.cookie.lifetime.days` preferences only have an effect for the [default case](https://dxr.mozilla.org/mozilla-central/rev/21bf1af375c1fa8565ae3bb2e89bd1a0809363d4/extensions/cookie/nsCookiePermission.cpp#229-256).
+"""]]

Comment moderation
diff --git a/posts/tweaking-cookies-for-privacy-in-firefox/comment_5_00259f6e77ea528509e02239c9b4bc7b._comment b/posts/tweaking-cookies-for-privacy-in-firefox/comment_5_00259f6e77ea528509e02239c9b4bc7b._comment
new file mode 100644
index 0000000..0918337
--- /dev/null
+++ b/posts/tweaking-cookies-for-privacy-in-firefox/comment_5_00259f6e77ea528509e02239c9b4bc7b._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ ip="80.73.206.122"
+ claimedauthor="Paul"
+ subject="Exceptions"
+ date="2016-04-06T09:48:11Z"
+ content="""
+Do \"network.cookie.lifetimePolicy\" and \"network.cookie.lifetime.days\" affect exception domains that I explicitly set to allow cookies?
+"""]]

Fix broken link
diff --git a/posts/how-safe-browsing-works-in-firefox.mdwn b/posts/how-safe-browsing-works-in-firefox.mdwn
index 596de31..e7ae193 100644
--- a/posts/how-safe-browsing-works-in-firefox.mdwn
+++ b/posts/how-safe-browsing-works-in-firefox.mdwn
@@ -223,8 +223,7 @@ about all parts of the Safe Browsing system, see the following papers:
 
 - [All Your IFrames Are Belong to Us](http://research.google.com/archive/provos-2008a.pdf)
 - [Content-Agnostic Malware Protection](https://www.cs.jhu.edu/~moheeb/aburajab-ndss-13.pdf)
-- [Ghost in the Browser](http://www.usenix.org/event/hotbots07/tech/full_papers/provos/provo
-s.pdf)
+- [Ghost in the Browser](http://www.usenix.org/event/hotbots07/tech/full_papers/provos/provos.pdf)
 
 [[!tag firefox]] [[!tag nzoss]] [[!tag mozilla]] [[!tag debian]]
 [[!tag privacy]] [[!tag security]]

Improve the first paragraph
diff --git a/posts/how-safe-browsing-works-in-firefox.mdwn b/posts/how-safe-browsing-works-in-firefox.mdwn
index 66fb8a8..596de31 100644
--- a/posts/how-safe-browsing-works-in-firefox.mdwn
+++ b/posts/how-safe-browsing-works-in-firefox.mdwn
@@ -3,18 +3,19 @@
 [[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
 
 Firefox has had support for Google's
-[Safe Browsing](https://developers.google.com/safe-browsing/) for quite some
-time. It started in 2005 as
-[a stand-alone Firefox extension](https://web.archive.org/web/20051218171531/http://www.google.com/tools/firefox/safebrowsing/index.html)
-only available in the US, then was opened up to the rest of the world in
-2006 before moving into the
-[Google Toolbar](https://web.archive.org/web/20060412192055/http://tools.google.com/firefox/toolbar/), being
+[Safe Browsing](https://developers.google.com/safe-browsing/) since 2005
+when it started as
+[a stand-alone Firefox extension](https://web.archive.org/web/20051218171531/http://www.google.com/tools/firefox/safebrowsing/index.html).
+At first it was only available in the USA, but it was opened up to the rest of the world in
+2006 and moved to the 
+[Google Toolbar](https://web.archive.org/web/20060412192055/http://tools.google.com/firefox/toolbar/).
+It then got 
 [integrated directly](https://bugzilla.mozilla.org/show_bug.cgi?id=329292)
 into
 [Firefox 2.0](http://website-archive.mozilla.org/www.mozilla.org/firefox_releasenotes/en-US/firefox/2.0/releasenotes/)
-and then
-[launched publicly](https://security.googleblog.com/2007/05/introducing-googles-anti-malware.html)
-in 2007.
+before the 
+[public launch](https://security.googleblog.com/2007/05/introducing-googles-anti-malware.html)
+of the service in 2007.
 
 Many people seem confused by this phishing and malware protection
 system and while there is a

Add first complete draft of my Safe Browsing post
diff --git a/posts/how-safe-browsing-works-in-firefox.mdwn b/posts/how-safe-browsing-works-in-firefox.mdwn
new file mode 100644
index 0000000..66fb8a8
--- /dev/null
+++ b/posts/how-safe-browsing-works-in-firefox.mdwn
@@ -0,0 +1,229 @@
+[[!meta title="How Safe Browsing works in Firefox"]]
+[[!meta date="2016-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/)"]]
+
+Firefox has had support for Google's
+[Safe Browsing](https://developers.google.com/safe-browsing/) for quite some
+time. It started in 2005 as
+[a stand-alone Firefox extension](https://web.archive.org/web/20051218171531/http://www.google.com/tools/firefox/safebrowsing/index.html)
+only available in the US, then was opened up to the rest of the world in
+2006 before moving into the
+[Google Toolbar](https://web.archive.org/web/20060412192055/http://tools.google.com/firefox/toolbar/), being
+[integrated directly](https://bugzilla.mozilla.org/show_bug.cgi?id=329292)
+into
+[Firefox 2.0](http://website-archive.mozilla.org/www.mozilla.org/firefox_releasenotes/en-US/firefox/2.0/releasenotes/)
+and then
+[launched publicly](https://security.googleblog.com/2007/05/introducing-googles-anti-malware.html)
+in 2007.
+
+Many people seem confused by this phishing and malware protection
+system and while there is a
+[pretty good explanation of how it works](https://support.mozilla.org/en-US/kb/how-does-phishing-and-malware-protection-work)
+on our support site, it doesn't go into technical details. This will
+hopefully be of interest to those who have more questions about it.
+
+# Browsing Protection
+
+The main part of the Safe Browsing system is the one that watches for bad
+URLs as you're browsing. Browsing protection currently protects users from:
+
+- [malware](https://www.stopbadware.org/badware) sites,
+- [deceptive sites](https://security.googleblog.com/2015/11/safe-browsing-protection-from-even-more.html)
+(including [phishing](https://support.google.com/websearch/answer/106318?hl=en&rd=1)
+and [social engineering](https://security.googleblog.com/2016/02/no-more-deceptive-download-buttons.html)
+sites), and
+- sites hosting [potentially unwanted software](https://security.googleblog.com/2015/07/more-visible-protection-against.html).
+
+If a Firefox user attempts to visit one of these sites, a warning page will
+show up instead, which you can see for yourself here:
+
+- [fake malware page](https://itisatrap.org/firefox/its-an-attack.html)
+- [fake unwanted software page](https://itisatrap.org/firefox/unwanted.html)
+- [fake phishing page](https://itisatrap.org/firefox/its-a-trap.html)
+
+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`.
+
+## List updates
+
+It would be too slow (and privacy-invasive) to contact a trusted server
+every time the browser wants to establish a connection with a web server.
+Instead, Firefox downloads a list of bad URLs every 30 minutes from the
+server (`browser.safebrowsing.provider.google.updateURL`) and does a
+[lookup against its local database](https://dxr.mozilla.org/mozilla-central/rev/494289c72ba3997183e7b5beaca3e0447ecaf96d/netwerk/base/nsBaseChannel.cpp#303-320)
+before displaying a page to the user.
+
+Downloading the entire list of sites flagged by Safe Browsing would be
+impractical due to
+[its size](https://www.google.com/transparencyreport/safebrowsing/notes/#size-of-blacklist)
+so the following transformations are applied:
+
+1. each URL on the list is [canonicalized](https://developers.google.com/safe-browsing/developers_guide_v2#Canonicalization),
+2. then [hashed](https://en.wikipedia.org/w/index.php?title=SHA256),
+3. of which only the first 32 bits of the hash are kept.
+
+The lists that are requested from the Safe Browsing server and used to flag
+pages as malware/unwanted or phishing can be found in
+`urlclassifier.malwareTable` and `urlclassifier.phishTable` respectively.
+
+If you want to see some debugging information in your terminal while Firefox
+is downloading updated lists, turn on `browser.safebrowsing.debug`.
+
+Once downloaded, the lists can be found in the cache directory:
+
+* `~/.cache/mozilla/firefox/XXXX/safebrowsing/` on Linux
+* `~/Library/Caches/Firefox/Profiles/XXXX/safebrowsing/` on Mac
+* `C:\Users\XXXX\AppData\Local\mozilla\firefox\profiles\XXXX\safebrowsing\` on Windows
+
+## Resolving partial hash conflicts
+
+Because the Safe Browsing database only contains partial hashes, it is
+possible for a safe page to share the same 32-bit hash prefix as a bad page.
+Therefore when a URL matches the local list, the browser needs to know
+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
+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
+are made.
+
+If the current URL doesn't match any of these full hashes, the load
+proceeds as normal. If it does match one of them, a warning interstitial
+page is shown and the
+[load is canceled](https://dxr.mozilla.org/mozilla-central/rev/494289c72ba3997183e7b5beaca3e0447ecaf96d/netwerk/base/nsChannelClassifier.cpp#689).
+
+# Download Protection
+
+The second part of the Safe Browsing system protects users against malicious
+downloads. It was
+[launched](https://security.googleblog.com/2011/04/protecting-users-from-malicious.html)
+in 2011, [implemented](https://bugzilla.mozilla.org/show_bug.cgi?id=662819) in
+[Firefox 31](https://www.mozilla.org/en-US/firefox/31.0/releasenotes/) on
+Windows and [enabled](https://bugzilla.mozilla.org/show_bug.cgi?id=1111741)
+in [Firefox 39](https://www.mozilla.org/en-US/firefox/39.0/releasenotes/) on
+Mac and Linux.
+
+It roughly works like this:
+
+1. Download the file.
+2. Check the main URL, referrer and redirect chain against a local
+blocklist (`urlclassifier.downloadBlockTable`) and block the download
+in case of a match.
+3. On Windows, if the binary is signed, check the signature against a local
+whitelist (`urlclassifier.downloadAllowTable`) of known good publishers and
+release the download if a match is found.
+4. If the file is not a
+[binary file](https://dxr.mozilla.org/mozilla-central/rev/494289c72ba3997183e7b5beaca3e0447ecaf96d/toolkit/components/downloads/ApplicationReputation.cpp#388-425)
+then release the download.
+5. Otherwise, send the binary file's
+[metadata](https://dxr.mozilla.org/mozilla-central/rev/494289c72ba3997183e7b5beaca3e0447ecaf96d/toolkit/components/downloads/ApplicationReputation.cpp#921-950)
+to the remote application reputation server
+(`browser.safebrowsing.downloads.remote.url`) and block the download if the
+server indicates that the file isn't safe.
+
+Blocked downloads can be unblocked by right-clicking on them in the download
+manager and selecting "Unblock".
+
+While the download protection feature is automatically disabled when malware
+protection (`browser.safebrowsing.malware.enabled`) is turned off, it can
+also be disabled independently via the
+`browser.safebrowsing.downloads.enabled` preference.
+
+Note that Step 5 is the only point at which any information about the
+download is shared with Google. That remote lookup can be suppressed via the
+`browser.safebrowsing.downloads.remote.enabled` preference for those users
+concerned about sending that metadata to a third party.
+
+## Types of malware
+
+The original application reputation service would protect users against
+"dangerous" downloads, but it has recently been expanded to also warn users
+about
+[unwanted software](https://chrome.googleblog.com/2014/08/thats-not-download-youre-looking-for.html)
+as well as software that's not commonly downloaded.
+
+These various warnings can be turned on and off in Firefox through the
+following preferences:
+
+* `browser.safebrowsing.downloads.remote.block_dangerous`
+* `browser.safebrowsing.downloads.remote.block_dangerous_host`
+* `browser.safebrowsing.downloads.remote.block_potentially_unwanted`
+* `browser.safebrowsing.downloads.remote.block_uncommon`
+
+and tested using [Google's test page](https://testsafebrowsing.appspot.com).
+
+If you want to see how often each "verdict" is returned by the server, you
+can have a look at the
+[telemetry results for Firefox Beta](https://telemetry.mozilla.org/new-pipeline/dist.html#!cumulative=0&end_date=2016-03-23&keys=__none__!__none__!__none__&max_channel_version=beta%252F46&measure=APPLICATION_REPUTATION_SERVER_VERDICT&min_channel_version=null&product=Firefox&sanitize=1&sort_keys=submissions&start_date=2016-03-07&table=1&trim=1&use_submission_date=0).
+
+# Privacy
+
+One of the most persistent misunderstandings about Safe Browsing is the idea
+that the browser needs to send all visited URLs to Google in order to verify
+whether or not they are safe.
+
+While this was
+[an option](https://www.google.com/tools/firefox/safebrowsing/faq.html#q11)
+in [version 1](https://wiki.mozilla.org/Safe_Browsing:_Server_Spec) of the Safe Browsing protocol (as disclosed in their
+[privacy policy](https://web.archive.org/web/20051230133135/http://www.google.com/tools/firefox/extensions_privacy.html)
+at the time), support for this
+["enhanced mode" was removed in Firefox 3](https://bugzilla.mozilla.org/show_bug.cgi?id=388652)
+and the version 1 server was
+[decommissioned in late 2011](https://security.googleblog.com/2011/05/safe-browsing-protocol-v2-transition.html)
+in favor of
+[version 2 of the Safe Browsing API](https://developers.google.com/safe-browsing/developers_guide_v2)
+which doesn't offer this type of real-time lookup.
+
+Google explicitly states that the information collected as part
+of operating the Safe Browsing service
+["is only used to flag malicious activity and is never used anywhere else at Google"](https://blog.chromium.org/2012/01/all-about-safe-browsing.html)
+and that
+["Safe Browsing requests won't be associated with your Google Account"](https://www.google.com/intl/en/chrome/browser/privacy/whitepaper.html#malware).
+In addition, Firefox adds a few privacy protections:
+
+- Query string parameters are
+[stripped](https://dxr.mozilla.org/mozilla-central/rev/494289c72ba3997183e7b5beaca3e0447ecaf96d/toolkit/components/downloads/ApplicationReputation.cpp#684-710)
+from URLs we check as part of the download protection feature.
+- Cookies set by the Safe Browsing servers to protect the service from
+abuse are stored in a
+[separate cookie jar](https://bugzilla.mozilla.org/show_bug.cgi?id=897516)
+so that they are not mixed with regular browsing/session cookies.

(Diff truncated)
Comment moderation
diff --git a/posts/restoring-single-table-from-postgres/comment_3_56277f98ca9523047ec0b51af8ed7526._comment b/posts/restoring-single-table-from-postgres/comment_3_56277f98ca9523047ec0b51af8ed7526._comment
new file mode 100644
index 0000000..7e0c14f
--- /dev/null
+++ b/posts/restoring-single-table-from-postgres/comment_3_56277f98ca9523047ec0b51af8ed7526._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ ip="212.91.77.38"
+ claimedauthor="gunzapper"
+ subject="text format"
+ date="2016-03-30T13:15:06Z"
+ 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
+
+works fine
+"""]]

Comment moderation
diff --git a/posts/querying-deleted-content-in-git/comment_2_fb64203f0e3bc1d5d6351f6e05a8804d._comment b/posts/querying-deleted-content-in-git/comment_2_fb64203f0e3bc1d5d6351f6e05a8804d._comment
new file mode 100644
index 0000000..3b0a3f8
--- /dev/null
+++ b/posts/querying-deleted-content-in-git/comment_2_fb64203f0e3bc1d5d6351f6e05a8804d._comment
@@ -0,0 +1,20 @@
+[[!comment format=mdwn
+ ip="96.81.84.65"
+ claimedauthor="Tom"
+ url="tomleo.com"
+ subject="Must use full path to file"
+ date="2016-03-16T21:01:04Z"
+ content="""
+This might be common sense but...
+
+-> pwd
+/home/foo
+
+-> git log -- bar
+
+This will return nothing
+
+-> git log -- baz/bar
+
+This will return the history of the file bar in the directory baz
+"""]]

Move aloodo script over to HTTPS
https://github.com/Aloodo/ad.aloodo.com/issues/8 got fixed.
diff --git a/sidebar.mdwn b/sidebar.mdwn
index 9066dd8..48e4aa6 100644
--- a/sidebar.mdwn
+++ b/sidebar.mdwn
@@ -25,4 +25,4 @@
 [[Tags]]:
 [[!pagestats pages="./tags/* and !tags/debian and !tags/catalyst and !tags/mozilla and !tags/ubuntu and !tags/nzoss and !tags/sysadmin and !tags/mahara" among="./posts/*"]]
 
-<script src="http://ad.aloodo.com/ad.js" defer></script>
+<script src="https://ad.aloodo.com/ad.js" async></script>

Add iTunes Store post
diff --git a/posts/extracting-album-covers-from-the-itunes-store.mdwn b/posts/extracting-album-covers-from-the-itunes-store.mdwn
new file mode 100644
index 0000000..0499122
--- /dev/null
+++ b/posts/extracting-album-covers-from-the-itunes-store.mdwn
@@ -0,0 +1,18 @@
+[[!meta title="Extracting Album Covers from the iTunes Store"]]
+[[!meta date="2016-02-28T16:50:00.000-08:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+The iTunes store is a good source of high-quality album cover art. If you
+search for the album on [Google Images](https://images.google.com), then
+visit the page and right-click on the cover image, you will get a **170 px
+by 170 px** image. Change the `170x170` in the URL to one of the following
+values to get a higher resolution image:
+
+- `170x170`
+- `340x340`
+- `600x600`
+- `1200x1200`
+- `1400x1400`
+
+Alternatively, use this [handy webapp](https://bendodson.com/code/itunes-artwork-finder/index.html) to
+query the iTunes search API and get to the source image directly.

Comment moderation
diff --git a/posts/setting-up-a-network-scanner-using-sane/comment_3_05ca7a3823313fd41377f09b1bd9fba2._comment b/posts/setting-up-a-network-scanner-using-sane/comment_3_05ca7a3823313fd41377f09b1bd9fba2._comment
new file mode 100644
index 0000000..233a5d4
--- /dev/null
+++ b/posts/setting-up-a-network-scanner-using-sane/comment_3_05ca7a3823313fd41377f09b1bd9fba2._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ ip="208.38.27.132"
+ claimedauthor="MSHYYC"
+ subject="Point of a network scanner is obvious"
+ date="2016-01-27T10:17:14Z"
+ content="""
+Printers are devices you have to physically move to as well and they are networked all the time. So it makes sense to network a scanner for similar reasons and more:
+
+* a scanner has to be networked to scan to a network destination like a shared drive or scan directly to email
+
+* It makes no sense to have a scanner for each person in an office, so you can share the scanner just like sharing a printer.  Otherwise the computer with the scanner connected has to be physically logged onto and used to scan instead of controlling it right from your own computer.  This can be handy if you are scanning and need to try multiple times to get the settings right too.
+
+Of course this mainly applies to scanners that do not have built in networking ability (usb only connections).  If they do have built in servers it makes less sense.
+"""]]