Recent changes to this wiki:

Comment moderation
diff --git a/posts/recovering-from-unbootable-ubuntu-encrypted-lvm-root-partition/comment_8_556ade9bd0b423bbba3a4791ce49b6c2._comment b/posts/recovering-from-unbootable-ubuntu-encrypted-lvm-root-partition/comment_8_556ade9bd0b423bbba3a4791ce49b6c2._comment
new file mode 100644
index 0000000..135bc6d
--- /dev/null
+++ b/posts/recovering-from-unbootable-ubuntu-encrypted-lvm-root-partition/comment_8_556ade9bd0b423bbba3a4791ce49b6c2._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ ip="88.153.228.176"
+ subject="recovering-from-unbootable-ubuntu-encrypted-lvm-root-partition"
+ date="2020-07-05T10:49:43Z"
+ content="""
+Hello,
+
+i have tried out your solution after failing about the one which did not help you also. 
+But seems i am stuck in this update nightmare: https://askubuntu.com/questions/1256247/ubuntu-20-kernel-upgrade-encrypted-volume-group-cannot-be-found-crypttab-em
+
+If you have any idea how to solve this i would be very greatful! 
+
+
+"""]]

Refer to the correct step
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index 52c35e1..cfbf1b9 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -118,7 +118,7 @@ to requests after running for a while:
 
 Note that if you'd like to be able to talk to contacts via the GMail XMPP
 server, you will unfortunately need to change the `s2s_use_starttls`
-setting in step 3 to the following:
+setting in step 4 to the following:
 
       s2s_use_starttls: optional
 

Fix formatting
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index d4db455..52c35e1 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -58,14 +58,16 @@ to solve the [Pidgin](http://pidgin.im) "Not authorized" connection problems.
 
 2. Set the following in `/etc/ejabberd/ejabberd.yml`:
 
-      acl:
-        admin:
-           user:
-               - "admin@fmarier.org"
-      hosts:
-        - "fmarier.org"
-      auth_password_format: scram
-      fqdn: "jabber-gw.fmarier.org"
+       acl:
+         admin:
+            user:
+                - "admin@fmarier.org"
+       
+       hosts:
+         - "fmarier.org"
+       
+       auth_password_format: scram
+       fqdn: "jabber-gw.fmarier.org"
 
 3. Copy the SSL certificate into the `/etc/ejabberd/` directory and set the
 permissions correctly:
@@ -75,21 +77,21 @@ permissions correctly:
 
 4. Improve the client-to-server and server-to-server TLS configuration:
 
-      define_macro:
-        # ...
-        'DH_FILE': "/etc/ejabberd/dhparams.pem"
+       define_macro:
+         # ...
+         'DH_FILE': "/etc/ejabberd/dhparams.pem"
+       
+       c2s_dhfile: 'DH_FILE'
+       s2s_dhfile: 'DH_FILE'
+       
+       listen:
+         -
+           port: 5222
+           ip: "::"
+           module: ejabberd_c2s
+           starttls_required: true
       
-      c2s_dhfile: 'DH_FILE'
-      s2s_dhfile: 'DH_FILE'
-      
-      listen:
-        -
-          port: 5222
-          ip: "::"
-          module: ejabberd_c2s
-          starttls_required: true
-      
-      s2s_use_starttls: required
+       s2s_use_starttls: required
 
 5. Create the required `dhparams.pem` file:
 

Switch to Apache authenticator and add echo.fmarier.org domain
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index 95184cc..d4db455 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -14,22 +14,23 @@ put everything together.
 My personal domain is `fmarier.org` and so I created the following DNS
 records:
 
+    echo                 CNAME    fmarier.org.
     jabber-gw            CNAME    fmarier.org.
     _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 TLS certificate for `jabber-gw.fmarier.org` and `fmarier.org`.
+Then I went to get a free TLS certificate for the above.
 
 ## Let's Encrypt
 
 The easiest way to get a certificate is to install [certbot](https://certbot.eff.org/):
 
-    apt install certbot
+    apt install certbot python3-certbot-apache
 
 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
+    certbot --duplicate certonly --apache -d jabber-gw.fmarier.org -d echo.fmarier.org -d fmarier.org
 
 Once you have the cert, you can merge the private and public keys
 into the file that ejabberd expects:

Remove CertSpotter (no longer free) and add ejabberd tag
diff --git a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
index 084aeb2..6d6f623 100644
--- a/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
+++ b/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot.mdwn
@@ -62,18 +62,9 @@ monitor my domains once a day:
 
     ssl-cert-check -s fmarier.org -p 443 -q -a -e francois@fmarier.org
 
-I also signed up with [Cert Spotter](https://sslmate.com/certspotter/) which
-watches the
-[Certificate Transparency](https://www.certificate-transparency.org/) log
-and notifies me of any newly-issued certificates for my domains.
-
-In other words, I get notified:
-
-- if my cronjob fails and a cert is about to expire, or
-- as soon as a new cert is issued.
-
 The whole thing seems to work well, but if there's anything I could be doing
 better, feel free to leave a comment!
 
 [[!tag nzoss]] [[!tag sysadmin]] [[!tag debian]] [[!tag mozilla]]
 [[!tag ubuntu]] [[!tag ssl]] [[!tag apache]] [[!tag letsencrypt]]
+[[!tag ejabberd]]

Add DB backups
diff --git a/posts/automated-mythtv-maintenance-tasks.mdwn b/posts/automated-mythtv-maintenance-tasks.mdwn
index 3773d04..43cce7c 100644
--- a/posts/automated-mythtv-maintenance-tasks.mdwn
+++ b/posts/automated-mythtv-maintenance-tasks.mdwn
@@ -6,7 +6,20 @@ Here is the daily/weekly cronjob I put together over the years to perform
 [MythTV](https://www.mythtv.org)-related maintenance tasks on my backend
 server.
 
-The first part runs a contrib script to [optimize the database
+The first part performs a [database backup](https://www.mythtv.org/wiki/User_Manual:Periodic_Maintenance#The_database):
+
+    5 1 * * *  mythtv  /usr/share/mythtv/mythconverg_backup.pl
+
+which I previously configured by putting the following in `/home/mythtv/.mythtv/backuprc`:
+
+    DBBackupDirectory=/var/backups/mythtv
+
+and creating a new directory for it:
+
+    mkdir /var/backups/mythtv
+    chown mythtv:mythtv /var/backups/mythtv
+
+The second part of `/etc/cron.d/mythtv-maintenance` runs a contrib script to [optimize the database
 tables](https://www.mythtv.org/wiki/User_Manual:Periodic_Maintenance#Optimize_the_Database):
 
     10 1 * * *  mythtv  /usr/bin/chronic /usr/share/doc/mythtv-backend/contrib/maintenance/optimize_mythdb.pl

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

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

Add MythTV cronjob post
diff --git a/posts/automated-mythtv-maintenance-tasks.mdwn b/posts/automated-mythtv-maintenance-tasks.mdwn
new file mode 100644
index 0000000..3773d04
--- /dev/null
+++ b/posts/automated-mythtv-maintenance-tasks.mdwn
@@ -0,0 +1,56 @@
+[[!meta title="Automated MythTV-related maintenance tasks"]]
+[[!meta date="2020-06-24T09:45:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+Here is the daily/weekly cronjob I put together over the years to perform
+[MythTV](https://www.mythtv.org)-related maintenance tasks on my backend
+server.
+
+The first part runs a contrib script to [optimize the database
+tables](https://www.mythtv.org/wiki/User_Manual:Periodic_Maintenance#Optimize_the_Database):
+
+    10 1 * * *  mythtv  /usr/bin/chronic /usr/share/doc/mythtv-backend/contrib/maintenance/optimize_mythdb.pl
+
+once a day. It requires the `libmythtv-perl` and `libxml-simple-perl` packages
+to be installed on Debian-based systems.
+
+It is quickly followed by a check of the recordings and [automatic repair of
+the seektable](https://www.mythtv.org/wiki/Repairing_the_Seektable) (when possible):
+
+    20 1 * * *  mythtv  /usr/bin/chronic /usr/bin/mythutil --checkrecordings --fixseektable
+
+Next, I force a scan of the music and video databases to pick up anything new
+that may have been added externally via
+[NFS](https://en.wikipedia.org/wiki/Network_File_System) mounts:
+
+    30 1 * * *  mythtv  /usr/bin/mythutil --quiet --scanvideos
+    31 1 * * *  mythtv  /usr/bin/mythutil --quiet --scanmusic
+
+Finally, I [defragment the XFS
+partition](https://www.mythtv.org/wiki/Optimizing_Performance#XFS-Specific_Tips)
+for two hours every day except Friday:
+
+    45 1 * * 1-4,6-7  root  /usr/sbin/xfs_fsr
+
+and resync the
+[RAID-1](https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_1) arrays
+once a week to ensure that they stay consistent and error-free:
+
+    15 3 * * 2  root  /usr/local/sbin/raid_parity_check md0
+    15 3 * * 4  root  /usr/local/sbin/raid_parity_check md2
+
+using a [trivial
+script](https://github.com/fmarier/root-scripts/blob/master/raid_parity_check).
+
+In addition to that cronjob, I also have
+[smartmontools](https://packages.debian.org/stable/smartmontools) run daily
+short and weekly long [SMART](https://en.wikipedia.org/wiki/S.M.A.R.T.)
+tests via this blurb in `/etc/smartd.conf`:
+
+    /dev/sda -a -d ata -o on -S on -s (S/../.././04|L/../../6/05)
+    /dev/sdb -a -d ata -o on -S on -s (S/../.././04|L/../../6/05)
+
+If there are any other automated maintenance tasks you do on your MythTV
+server, please leave a comment!
+
+[[!tag debian]] [[!tag mythtv]] [[!tag raid]] [[!tag xfs]] [[!tag smart]]

Note a way to confirm that the computer and the radio can talk
diff --git a/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn b/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
index f5e3ced..a4f8910 100644
--- a/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
+++ b/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
@@ -61,6 +61,10 @@ correctly:
 
         systemctl start ax25.service
 
+As the AX25 unit starts up and initializes the TNC using `tmd710_tncsetup`,
+you should see `STA` and `CON` indicators flash briefly in the top-right
+corner of the screen.
+
 # Connecting to a winlink gateway
 
 To monitor what is being received and transmitted:

Add a few obvious but important steps
diff --git a/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn b/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
index 5dafb5d..f5e3ced 100644
--- a/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
+++ b/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
@@ -31,6 +31,7 @@ along with the systemd script that comes with Pat:
 Once the packages are installed, it's time to configure everything
 correctly:
 
+0. Plug the radio onto the computer using a mini-USB cable.
 1. Power cycle the radio.
 2. Enable TNC in `packet12` mode (**band A***).
 3. Tune band A to [VECTOR
@@ -42,7 +43,9 @@ correctly:
 
         wl2k    CALLSIGN    9600    128    4    Winlink
 
-5. Set `HBAUD` to **`1200`** in `/etc/default/ax25`.
+5. Set `HBAUD` to **`1200`** in `/etc/default/ax25` and make sure that the
+   `DEV` variable is set to the correct `/dev/TTYUSBx` device (check the
+   output of `dmesg` after turning on the radio).
 6. Download and compile the [`tmd710_tncsetup`
    script](https://github.com/fmarier/tmd710_tncsetup/blob/master/tmd710_tncsetup.c)
    mentioned in a comment in `/etc/default/ax25`:
@@ -73,7 +76,12 @@ Then create aliases like these in `~/.wl2k/config.json`:
       },
     }
 
-and use them to connect to your preferred Winlink gateways.
+and use them to connect to your preferred Winlink gateways by starting pat
+using the following:
+
+    pat http
+
+and then opening the interface in a webbrowser: <http://localhost:8080/>
 
 # Troubleshooting
 

Point to my new tmd710_tncsetup repository
diff --git a/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn b/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
index d97037a..5dafb5d 100644
--- a/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
+++ b/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
@@ -44,7 +44,7 @@ correctly:
 
 5. Set `HBAUD` to **`1200`** in `/etc/default/ax25`.
 6. Download and compile the [`tmd710_tncsetup`
-   script](http://www.trinityos.com/HAM/CentosDigitalModes/usr/src/misc/D710/tmd710_tncsetup.c)
+   script](https://github.com/fmarier/tmd710_tncsetup/blob/master/tmd710_tncsetup.c)
    mentioned in a comment in `/etc/default/ax25`:
 
         gcc -o tmd710_tncsetup tmd710_tncsetup.c

Remove unnecessary work-around
My PR got merged in the 5.7 kernels:
https://github.com/neilbrown/gnubee-tools/pull/24
diff --git a/posts/backing-up-to-gnubee2.mdwn b/posts/backing-up-to-gnubee2.mdwn
index c98a9c7..2226a34 100644
--- a/posts/backing-up-to-gnubee2.mdwn
+++ b/posts/backing-up-to-gnubee2.mdwn
@@ -30,8 +30,6 @@ directory](https://github.com/neilbrown/gnubee-tools/issues/23) and so I
 tightened the security of some of the default mount points by putting the following
 in `/etc/rc.local`:
 
-    mount -o remount,nodev,nosuid /etc/network
-    mount -o remount,nodev,nosuid /lib/modules
     chmod 755 /etc/network
     exit 0
 

Fix typo
diff --git a/posts/backing-up-to-gnubee2.mdwn b/posts/backing-up-to-gnubee2.mdwn
index 53ff816..c98a9c7 100644
--- a/posts/backing-up-to-gnubee2.mdwn
+++ b/posts/backing-up-to-gnubee2.mdwn
@@ -147,7 +147,7 @@ On each machine, I added the following to `/root/.ssh/config`:
 
 The reason for setting the ssh cipher and disabling compression is to [speed
 up the ssh connection](https://gist.github.com/KartikTalwar/4393116) as much
-as possible given that the [GnuBee has avery small RAM
+as possible given that the [GnuBee has a very small RAM
 bandwidth](https://groups.google.com/d/msg/gnubee/5_nKjgmKSoY/a0ER5fEcBAAJ).
 
 Another performance-related change I made on the GnuBee was switching to the [internal sftp

Fix mistake in hosts file
diff --git a/posts/backing-up-to-gnubee2.mdwn b/posts/backing-up-to-gnubee2.mdwn
index 43a42bb..53ff816 100644
--- a/posts/backing-up-to-gnubee2.mdwn
+++ b/posts/backing-up-to-gnubee2.mdwn
@@ -20,7 +20,7 @@ I changed the default hostname:
 
 - `/etc/hostname`: `foobar`
 - `/etc/mailname`: `foobar.example.com`
-- `/etc/hosts`: `127.0.0.1  foobar.example.com vogar localhost`
+- `/etc/hosts`: `127.0.0.1  foobar.example.com foobar localhost`
 
 and then installed the `avahi-daemon` package to be able to reach this box
 using `foobar.local`.

Fix last CSS change
diff --git a/local.css b/local.css
index 25f2108..91e9d6f 100644
--- a/local.css
+++ b/local.css
@@ -4,7 +4,7 @@ img {
     height: auto;
 }
 
-.blogform, .trail, .inlinefooter .pagelicense, .inlinefooter .tags, .inlinefooter .actions, .comments .comment .actions {
+.blogform, .trail, .inlinefooter .pagelicense, .inlinefooter .tags, .inlinefooter .actions, #comments .comment .actions {
     display: none;
 }
 

Hide unnecessary "Remove comment" buttons
diff --git a/local.css b/local.css
index 69f70db..25f2108 100644
--- a/local.css
+++ b/local.css
@@ -4,7 +4,7 @@ img {
     height: auto;
 }
 
-.blogform, .trail, .inlinefooter .pagelicense, .inlinefooter .tags, .inlinefooter .actions {
+.blogform, .trail, .inlinefooter .pagelicense, .inlinefooter .tags, .inlinefooter .actions, .comments .comment .actions {
     display: none;
 }
 

Comment moderation
diff --git a/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox/comment_6_702c0ae4816e6cac81929847b9148cf1._comment b/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox/comment_6_702c0ae4816e6cac81929847b9148cf1._comment
new file mode 100644
index 0000000..ba1d87f
--- /dev/null
+++ b/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox/comment_6_702c0ae4816e6cac81929847b9148cf1._comment
@@ -0,0 +1,18 @@
+[[!comment format=mdwn
+ ip="77.98.107.200"
+ claimedauthor="Eric W"
+ subject="Using Linux"
+ date="2020-06-10T14:54:39Z"
+ content="""
+Well, the good news is that the CPS for the 868, 878 & 578 will run under Wine. There are a couple of caveats in as much as version of Wine should be the latest version as this now auto-creates virtual com ports up to com 33. Plugging in the programming lead will automatically create an extra com port - in my case com34, but check your own settings.
+
+All functions are available, including firmware updates etc.
+
+** NOTE FOR 878 ONLY: Although the CPS works well enough in itself, it will NOT read the com port, so you can't read/write to the radio. I've attempted to find ways around this problem, but I'm not a coder and as yet not found a resolution.
+
+Overall it works well in Wine, though you do need to be careful when editing any files you export from the radio. Apparently Linux uses a different 'end of line' format that isn't compatible with Windows and can result in file import errors. Once edited, I suggest re-importing your edited CSV into a text editor such as Xed, which has the facility to save files with a Linux or Windows line ending - choose Windows version and all is well
+
+It really is a pity that the 878 wont find the working com port, otherwise I would 100% recommend using Linux/Wine for these radios.
+
+Eric - G6FGY (UK)
+"""]]

Update security configuration options for ejabberd 18
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index 2ca0678..95184cc 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -55,13 +55,12 @@ to solve the [Pidgin](http://pidgin.im) "Not authorized" connection problems.
 
       apt install ejabberd
 
-2. Set the following in `/etc/ejabberd/ejabberd.yml` (don't forget the
-trailing dots!):
+2. Set the following in `/etc/ejabberd/ejabberd.yml`:
 
       acl:
         admin:
            user:
-               - "admin": "fmarier.org"
+               - "admin@fmarier.org"
       hosts:
         - "fmarier.org"
       auth_password_format: scram
@@ -73,41 +72,27 @@ permissions correctly:
       chown root:ejabberd /etc/ejabberd/ejabberd.pem
       chmod 640 /etc/ejabberd/ejabberd.pem
 
-4. [Improve](https://bettercrypto.org/) the client-to-server TLS configuration
-by adding `starttls_required` to this block:
+4. Improve the client-to-server and server-to-server TLS configuration:
 
+      define_macro:
+        # ...
+        'DH_FILE': "/etc/ejabberd/dhparams.pem"
+      
+      c2s_dhfile: 'DH_FILE'
+      s2s_dhfile: 'DH_FILE'
+      
       listen:
         -
           port: 5222
           ip: "::"
           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/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/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"
+      s2s_use_starttls: required
 
-5. Create the required dh2048.pem file:
+5. Create the required `dhparams.pem` file:
 
-       openssl dhparam -out /etc/ssl/ejabberd/dh2048.pem 2048
+       openssl dhparam -out /etc/ejabberd/dhparams.pem 2048
 
 6. Restart the ejabberd daemon:
 
@@ -178,8 +163,9 @@ federate with yours by putting the following in
 
     access:
       s2s:
-        trusted_servers: allow
-        all: deny
+        - allow: trusted_servers
+        - deny
+    
     s2s_access: s2s
 
 The above was all I needed in order to be able to use the

Update for buster
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index bf36d02..2ca0678 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -4,7 +4,7 @@
 
 In order to get closer to my goal of reducing my dependence on centralized
 services, I decided to setup my own XMPP / Jabber server on a server
-running [Debian wheezy](http://www.debian.org/releases/wheezy/). I chose
+running [Debian buster](http://www.debian.org/releases/buster/). I chose
 [ejabberd](http://www.ejabberd.im/) since it was recommended by the
 [RTC Quick Start](http://www.rtcquickstart.org/) website and here's how I
 put everything together.
@@ -22,15 +22,9 @@ Then I went to get a free TLS certificate for `jabber-gw.fmarier.org` and `fmari
 
 ## 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`:
+The easiest way to get a certificate is to install [certbot](https://certbot.eff.org/):
 
-    deb http://httpredir.debian.org/debian jessie-backports main contrib non-free
-
-and then installing the package:
-
-    apt update && apt install certbot
+    apt install certbot
 
 Then, shutdown your existing webserver if you have one running and request
 a cert like this:
@@ -56,10 +50,10 @@ with an
 [additional customization](http://www.die-welt.net/2013/05/wheezy-ejabberd-pidgin-and-srv-records/)
 to solve the [Pidgin](http://pidgin.im) "Not authorized" connection problems.
 
-1. Install the [package](http://packages.debian.org/wheezy/ejabberd), using
+1. Install the [package](http://packages.debian.org/stable/ejabberd), using
 "admin" as the username for the administrative user:
 
-      apt-get install ejabberd
+      apt install ejabberd
 
 2. Set the following in `/etc/ejabberd/ejabberd.yml` (don't forget the
 trailing dots!):
@@ -117,7 +111,7 @@ by adding `starttls_required` to this block:
 
 6. Restart the ejabberd daemon:
 
-       /etc/init.d/ejabberd restart
+       systemctl restart ejabberd.service
 
 7. Create a new user account for yourself:
 
@@ -134,7 +128,7 @@ 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
+Note that if you'd like to be able to talk to contacts via the GMail XMPP
 server, you will unfortunately need to change the `s2s_use_starttls`
 setting in step 3 to the following:
 

Mention what's needed to whitelist JMP.chat
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index 4601649..bf36d02 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -180,7 +180,7 @@ federate with yours by putting the following in
         server:
           - "cheogram.com"
           - "conference.soprani.ca"
-          - "conversations.im"
+          - "jmp.chat"
 
     access:
       s2s:
@@ -188,4 +188,7 @@ federate with yours by putting the following in
         all: deny
     s2s_access: s2s
 
+The above was all I needed in order to be able to use the
+[JMP](https://jmp.chat/) SMS-to-XMPP service.
+
 [[!tag debian]] [[!tag ubuntu]] [[!tag nzoss]] [[!tag sysadmin]] [[!tag xmpp]] [[!tag letsencrypt]] [[!tag ejabberd]]

Remove defunct free TLS certificate provider
diff --git a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
index 75177d6..4601649 100644
--- a/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
+++ b/posts/running-your-own-xmpp-server-debian-ubuntu.mdwn
@@ -48,20 +48,6 @@ and then restart the service:
 
 I wrote a [cronjob to renew this certificate automatically using certbot](https://feeding.cloud.geek.nz/posts/automatically-renewing-letsencrypt-certs-on-debian-using-certbot/).
 
-## 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"
-
-I downloaded the signed certificate as well as the
-[StartSSL intermediate certificate](https://startssl.com/certs/) and
-[combined them](http://hyperstruct.net/2007/06/20/installing-the-startcom-ssl-certificate-in-ejabberd/)
-this way:
-
-    cat ssl.crt ssl.key sub.class1.server.ca.pem > ejabberd.pem
-
 # ejabberd installation
 
 Installing ejabberd on Debian is pretty simple and I mostly followed the

Add post about MythTV locale setting
diff --git a/posts/fixing-locale-problem-mythtv-30.mdwn b/posts/fixing-locale-problem-mythtv-30.mdwn
new file mode 100644
index 0000000..e9c4644
--- /dev/null
+++ b/posts/fixing-locale-problem-mythtv-30.mdwn
@@ -0,0 +1,65 @@
+[[!meta title="Fixing locale problem in MythTV 30"]]
+[[!meta date="2020-05-28T15:30:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+After upgrading to MythTV 30, I noticed that the interface of mythfrontend
+switched from the French language to English, despite having the following
+in my `~/.xsession` for the `mythtv` user:
+
+    export LANG=fr_CA.UTF-8
+    exec ~/bin/start_mythtv
+
+I noticed a few related error messages in `/var/log/syslog`:
+
+    mythbackend[6606]: I CoreContext mythcorecontext.cpp:272 (Init) Assumed character encoding: fr_CA.UTF-8
+    mythbackend[6606]: N CoreContext mythcorecontext.cpp:1780 (InitLocale) Setting QT default locale to FR_US
+    mythbackend[6606]: I CoreContext mythcorecontext.cpp:1813 (SaveLocaleDefaults) Current locale FR_US
+    mythbackend[6606]: E CoreContext mythlocale.cpp:110 (LoadDefaultsFromXML) No locale defaults file for FR_US, skipping
+    mythpreviewgen[9371]: N CoreContext mythcorecontext.cpp:1780 (InitLocale) Setting QT default locale to FR_US
+    mythpreviewgen[9371]: I CoreContext mythcorecontext.cpp:1813 (SaveLocaleDefaults) Current locale FR_US
+    mythpreviewgen[9371]: E CoreContext mythlocale.cpp:110 (LoadDefaultsFromXML) No locale defaults file for FR_US, skipping
+
+Searching for that non-existent `fr_US` locale, I found that [others have
+this in their logs](https://mythtv-fr.org/forums/viewtopic.php?id=2202) 
+and that it's [apparently set by
+QT](https://bugreports.qt.io/browse/QTBUG-8452?focusedCommentId=149446&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel)
+as a combination of the language and country codes.
+
+I therefore looked in the database and found the following:
+
+    MariaDB [mythconverg]> SELECT value, data FROM settings WHERE value = 'Language';
+    +----------+------+
+    | value    | data |
+    +----------+------+
+    | Language | FR   |
+    +----------+------+
+    1 row in set (0.000 sec)
+
+    MariaDB [mythconverg]> SELECT value, data FROM settings WHERE value = 'Country';
+    +---------+------+
+    | value   | data |
+    +---------+------+
+    | Country | US   |
+    +---------+------+
+    1 row in set (0.000 sec)
+
+which explains the non-sensical `FR-US` locale.
+
+I fixed the country setting like this
+
+    MariaDB [mythconverg]> UPDATE settings SET data = 'CA' WHERE value = 'Country';
+    Query OK, 1 row affected (0.093 sec)
+    Rows matched: 1  Changed: 1  Warnings: 0
+
+After logging out and logging back in, the user interface of the frontend is now
+using the `fr_CA` locale again and the database setting looks good:
+
+    MariaDB [mythconverg]> SELECT value, data FROM settings WHERE value = 'Country';
+    +---------+------+
+    | value   | data |
+    +---------+------+
+    | Country | CA   |
+    +---------+------+
+    1 row in set (0.000 sec)
+
+[[!tag mythtv]]

Comment moderation
diff --git a/posts/backing-up-to-s3-with-duplicity/comment_1_0471bf8b0d6af376a11b2f03bdafdd27._comment b/posts/backing-up-to-s3-with-duplicity/comment_1_0471bf8b0d6af376a11b2f03bdafdd27._comment
new file mode 100644
index 0000000..4446e05
--- /dev/null
+++ b/posts/backing-up-to-s3-with-duplicity/comment_1_0471bf8b0d6af376a11b2f03bdafdd27._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ ip="2403:5800:3100:142::2494"
+ claimedauthor="Hamish"
+ subject="ListAllMyBuckets"
+ date="2020-05-28T03:37:17Z"
+ content="""
+What error do you get if you don't grant ListAllMyBuckets?
+
+I've been running duplicity to S3 without that permission for years and never encountered an issue. Though I see lots of other web sites saying the same thing. I'm actually using the duply frontend to duplicity but I think it's unlikely that makes a difference.
+"""]]

Hide mailq-check user from the GDM list
diff --git a/posts/simple-remote-mail-queue-monitoring.mdwn b/posts/simple-remote-mail-queue-monitoring.mdwn
index 91c0a2a..03b4de7 100644
--- a/posts/simple-remote-mail-queue-monitoring.mdwn
+++ b/posts/simple-remote-mail-queue-monitoring.mdwn
@@ -38,6 +38,14 @@ and then authorized my new ssh key (see next section):
     mkdir ~/.ssh/
     cat - > ~/.ssh/authorized_keys
 
+If your server also allows users to login using [GDM](https://wiki.gnome.org/Projects/GDM),
+then you'll probably want to hide that user from the list of available
+users by putting the following in `/var/lib/AccountsService/users/mailq-check`:
+
+    [User]
+    XSession=
+    SystemAccount=true
+
 # Laptop setup
 
 On my laptop, the machine from where I monitor the server's mail queue, I

Optimize image
diff --git a/posts/printing-hard-to-print-pdfs-on-linux/insufficient-printer-memory.png b/posts/printing-hard-to-print-pdfs-on-linux/insufficient-printer-memory.png
index 1ea243e..328da55 100644
Binary files a/posts/printing-hard-to-print-pdfs-on-linux/insufficient-printer-memory.png and b/posts/printing-hard-to-print-pdfs-on-linux/insufficient-printer-memory.png differ

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

Add blog post about unprintable PDFs
diff --git a/posts/printing-hard-to-print-pdfs-on-linux.mdwn b/posts/printing-hard-to-print-pdfs-on-linux.mdwn
new file mode 100644
index 0000000..27c2a7d
--- /dev/null
+++ b/posts/printing-hard-to-print-pdfs-on-linux.mdwn
@@ -0,0 +1,58 @@
+[[!meta title="Printing hard-to-print PDFs on Linux"]]
+[[!meta date="2020-05-23T20:05:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+I recently found a few PDFs which I was unable to print due to
+those files causing [insufficient printer memory
+errors](https://support.hp.com/us-en/product/model/9365402/document/c05049204):
+
+![](/posts/printing-hard-to-print-pdfs-on-linux/insufficient-printer-memory.png)
+
+I found a [detailed
+explanation](https://tex.stackexchange.com/questions/71001/why-do-some-vector-graphics-included-into-a-document-force-rasterization-of-the#71050)
+of what might be causing this which pointed the finger at transparent
+images, a PDF 1.4 feature which apparently requires a more recent version of
+[PostScript](https://en.wikipedia.org/wiki/PostScript) than what my printer
+supports.
+
+Using [Okular](https://okular.kde.org/)'s *Force rasterization* option
+(accessible via the print dialog) does work by essentially rendering
+everything ahead of time and outputing a big image to be sent to the
+printer. The quality is not very good however.
+
+# Converting a PDF to DjVu
+
+The [best solution I found](https://superuser.com/a/1489923) makes use of a
+different file format: [.djvu](https://en.wikipedia.org/wiki/DjVu)
+
+Such files are not PDFs, but can still be opened in [Evince](https://wiki.gnome.org/Apps/Evince) and
+[Okular](https://okular.kde.org/), as well as in the dedicated
+[DjVuLibre](http://djvu.sourceforge.net/) application.
+
+As an example, I was unable to print page 11 of [this
+paper](https://arxiv.org/pdf/2002.04049.pdf). Using `pdfinfo`, I found that
+it is in PDF 1.5 format and so the transparency effects could be the cause
+of the out-of-memory printer error.
+
+Here's how I converted it to a high-quality DjVu file I could print without
+problems using Evince:
+
+    pdf2djvu -d 1200 2002.04049.pdf > 2002.04049-1200dpi.djvu
+
+# Converting a PDF to PDF 1.3
+
+I also tried the DjVu trick on a [different unprintable
+PDF](https://www.boardgamegeek.com/filepage/113639/dead-winter-official-faq-v11),
+but it failed to print, even after lowering the resolution to 600dpi:
+
+    pdf2djvu -d 600 dow-faq_v1.1.pdf > dow-faq_v1.1-600dpi.djvu
+
+In this case, I used a different technique and simply converted the PDF to
+version 1.3 (from version 1.6 according to `pdfinfo`):
+
+    ps2pdf13 -r1200x1200 dow-faq_v1.1.pdf dow-faq_v1.1-1200dpi.pdf
+
+This eliminates the problematic transparency and rasterizes the elements
+that version 1.3 doesn't support.
+
+[[!tag debian]] [[!tag printing]]
diff --git a/posts/printing-hard-to-print-pdfs-on-linux/insufficient-printer-memory.png b/posts/printing-hard-to-print-pdfs-on-linux/insufficient-printer-memory.png
new file mode 100644
index 0000000..1ea243e
Binary files /dev/null and b/posts/printing-hard-to-print-pdfs-on-linux/insufficient-printer-memory.png differ

Add Apache SSI post
diff --git a/posts/displaying-ip-address-apache-server-side-includes.mdwn b/posts/displaying-ip-address-apache-server-side-includes.mdwn
new file mode 100644
index 0000000..bc95e85
--- /dev/null
+++ b/posts/displaying-ip-address-apache-server-side-includes.mdwn
@@ -0,0 +1,97 @@
+[[!meta title="Displaying client IP address using Apache Server-Side Includes"]]
+[[!meta date="2020-05-18T14:50:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+If you use a [Dynamic DNS
+setup](https://feeding.cloud.geek.nz/posts/dynamic-dns-on-own-domain/) to
+reach machines which are not behind a stable IP address, you will likely
+have a need to probe these machines' public IP addresses. One option is to
+use an insecure service like Oracle's <http://checkip.dyndns.com/> which
+echoes back your client IP, but you can also do this on your own server if
+you have one.
+
+There are multiple options to do this, like writing a CGI or PHP script, but
+those are fairly heavyweight if that's all you need [mod_cgi](https://httpd.apache.org/docs/current/mod/mod_cgi.html) or
+[PHP](https://cwiki.apache.org/confluence/display/HTTPD/PHP) for. Instead, I
+decided to use Apache's built-in [Server-Side
+Includes](https://httpd.apache.org/docs/current/howto/ssi.html).
+
+## Apache configuration
+
+Start by turning on the [include
+filter](https://httpd.apache.org/docs/current/mod/mod_include.html) by
+adding the following in `/etc/apache2/conf-available/ssi.conf`:
+
+    AddType text/html .shtml
+    AddOutputFilter INCLUDES .shtml
+
+and making that configuration file active:
+
+    a2enconf ssi
+
+Then, find the vhost file where you want to enable SSI and add the following
+options to a `Location` or `Directory` section:
+
+    <Location /ssi_files>
+        Options +IncludesNOEXEC
+        SSLRequireSSL
+        Header set Content-Security-Policy: "default-src 'none'"
+        Header set X-Content-Type-Options: "nosniff"
+    </Location>
+
+before adding the necessary modules:
+
+    a2enmod headers
+    a2enmod include
+
+and restarting Apache:
+
+    apache2ctl configtest && systemctl restart apache2.service
+
+## Create an `shtml` page
+
+With the web server ready to process SSI instructions, the following HTML
+blurb can be used to display the client IP address:
+
+    <!--#echo var="REMOTE_ADDR" -->
+
+or any other [built-in
+variable](https://httpd.apache.org/docs/current/expr.html#vars).
+
+Note that you don't need to write a valid HTML for the variable to be
+substituted and so the above one-liner is all I use on my server.
+
+## Security concerns
+
+The first thing to note is that the configuration section uses the
+`IncludesNOEXEC` option in order to disable [arbitrary command
+execution](https://httpd.apache.org/docs/current/howto/ssi.html#exec) via
+SSI. In addition, you can also make sure that the `cgi` module is disabled
+since that's a dependency of the more dangerous side of SSI:
+
+    a2dismod cgi
+
+Of course, if you rely on this IP address to be accurate, for example
+because you'll be putting it in your DNS, then you should make sure that you
+**only serve this page over HTTPS**, which can be enforced via the
+[`SSLRequireSSL`
+directive](https://httpd.apache.org/docs/current/mod/mod_ssl.html#sslrequiressl).
+
+I included two other headers in the above vhost config
+([`Content-Security-Policy`](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
+and
+[`X-Content-Type-Options`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options))
+in order to limit the damage that could be done in case a malicious file was
+accidentally dropped in that directory.
+
+Finally, I suggest making sure that **only the `root` user has writable
+access to the directory** which has server-side includes enabled:
+
+    $ ls -la /var/www/ssi_includes/
+    total 12
+    drwxr-xr-x  2 root     root     4096 May 18 15:58 .
+    drwxr-xr-x 16 root     root     4096 May 18 15:40 ..
+    -rw-r--r--  1 root     root        0 May 18 15:46 index.html
+    -rw-r--r--  1 root     root       32 May 18 15:58 whatsmyip.shtml
+
+[[!tag apache]] [[!tag dns]] [[!tag debian]]
diff --git a/posts/dynamic-dns-on-own-domain.mdwn b/posts/dynamic-dns-on-own-domain.mdwn
index 6fed580..fd95874 100644
--- a/posts/dynamic-dns-on-own-domain.mdwn
+++ b/posts/dynamic-dns-on-own-domain.mdwn
@@ -76,6 +76,10 @@ Note that you do need to change the default update interval or the
 `checkip.dyndns.com` server [will ban your IP
 address](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=489997).
 
+Alternatively, just [setup your own lightweight IP address echoing
+service](https://feeding.cloud.geek.nz/posts/displaying-ip-address-apache-server-side-includes/)
+and avoid the problem entirely.
+
 # Testing
 
 To test that the client software is working, wait 6 minutes (there is an

Remove Brave and VoIP.ms referral links
As described in d612135d6e5cb20b475c055cbbf27b0dfdae5fee, using referral links
might involve following some jurisdiction-specific rules. This is too much
hassle for the amount of (minimal or non-existent) money.
This reverts commits 71fe2a2c12ce7d6bf3761b339337a249d6f15130 and
07aa6e5862282a2aebfb1ffa95320582fab9aed0.
diff --git a/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn b/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn
index 6608027..da4f9e7 100644
--- a/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn
+++ b/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn
@@ -32,7 +32,7 @@ Note that this test page makes use of a Google TURN server which is locked
 to particular HTTP referrers and so you'll need to disable privacy features
 that might interfere with this:
 
-- [Brave](https://brave.com/clo187): Disable Shields entirely for that page
+- [Brave](https://brave.com/): Disable Shields entirely for that page
   (Simple view) or *allow all cookies* for that page (Advanced view).
 
 ![](/posts/how-to-get-direct-webrtc-connection-between-computers/brave-shields-cookies.png)
diff --git a/posts/making-sip-calls-voipms-without-pstn.mdwn b/posts/making-sip-calls-voipms-without-pstn.mdwn
index 09fbc0d..ee96aee 100644
--- a/posts/making-sip-calls-voipms-without-pstn.mdwn
+++ b/posts/making-sip-calls-voipms-without-pstn.mdwn
@@ -2,7 +2,7 @@
 [[!meta date="2020-03-05T19:00:00.000-08:00"]]
 [[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
 
-If you want to reach a [VoIP.ms](https://voip.ms/en/invite/MjE0NTI2) subscriber from
+If you want to reach a [VoIP.ms](https://voip.ms/) subscriber from
 [Asterisk](https://www.asterisk.org/) without using the
 [PSTN](https://en.wikipedia.org/wiki/Public_switched_telephone_network),
 there is a way to do so via [SIP
diff --git a/posts/passwordless-restricted-guest-account-ubuntu.mdwn b/posts/passwordless-restricted-guest-account-ubuntu.mdwn
index 5ad5b4a..d1bcfe4 100644
--- a/posts/passwordless-restricted-guest-account-ubuntu.mdwn
+++ b/posts/passwordless-restricted-guest-account-ubuntu.mdwn
@@ -36,7 +36,7 @@ gnome-control-center. I set the following in the privacy section:
 
 ![](/posts/passwordless-restricted-guest-account-ubuntu/privacy-settings.png)
 
-Then I replaced Firefox with [Brave](https://brave.com/clo187) in the sidebar,
+Then I replaced Firefox with [Brave](https://brave.com) in the sidebar,
 set it as the default browser in gnome-control-center:
 
 ![](/posts/passwordless-restricted-guest-account-ubuntu/default-applications.png)
diff --git a/posts/sip-encryption-on-voip-ms.mdwn b/posts/sip-encryption-on-voip-ms.mdwn
index 7a13599..0d99118 100644
--- a/posts/sip-encryption-on-voip-ms.mdwn
+++ b/posts/sip-encryption-on-voip-ms.mdwn
@@ -2,7 +2,7 @@
 [[!meta date="2019-07-06T16:00:00.000-07:00"]]
 [[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
 
-My [VoIP provider](https://voip.ms/en/invite/MjE0NTI2) recently added [support for
+My [VoIP provider](https://voip.ms) recently added [support for
 TLS/SRTP-based call
 encryption](https://wiki.voip.ms/article/Call_Encryption_-_TLS/SRTP). Here's
 what I did to enable this feature on my
diff --git a/posts/using-gogo-wifi-linux.mdwn b/posts/using-gogo-wifi-linux.mdwn
index 961d4ba..8dfe92f 100644
--- a/posts/using-gogo-wifi-linux.mdwn
+++ b/posts/using-gogo-wifi-linux.mdwn
@@ -12,7 +12,7 @@ however possible to work-around this restriction by faking your browser
 
 I tried the [User-Agent Switcher for
 Chrome](https://chrome.google.com/webstore/detail/user-agent-switcher-for-c/djflhoibgkdhkhhcedjiklpkjnoahfmg)
-extension on Chrome and [Brave](https://brave.com/clo187) but it didn't work
+extension on Chrome and [Brave](https://brave.com/) but it didn't work
 for some reason.
 
 What did work was using Firefox and adding the following prefs in

Use a referral URL when linking to VoIP.ms
diff --git a/posts/making-sip-calls-voipms-without-pstn.mdwn b/posts/making-sip-calls-voipms-without-pstn.mdwn
index ee96aee..09fbc0d 100644
--- a/posts/making-sip-calls-voipms-without-pstn.mdwn
+++ b/posts/making-sip-calls-voipms-without-pstn.mdwn
@@ -2,7 +2,7 @@
 [[!meta date="2020-03-05T19:00:00.000-08:00"]]
 [[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
 
-If you want to reach a [VoIP.ms](https://voip.ms/) subscriber from
+If you want to reach a [VoIP.ms](https://voip.ms/en/invite/MjE0NTI2) subscriber from
 [Asterisk](https://www.asterisk.org/) without using the
 [PSTN](https://en.wikipedia.org/wiki/Public_switched_telephone_network),
 there is a way to do so via [SIP
diff --git a/posts/sip-encryption-on-voip-ms.mdwn b/posts/sip-encryption-on-voip-ms.mdwn
index 0d99118..7a13599 100644
--- a/posts/sip-encryption-on-voip-ms.mdwn
+++ b/posts/sip-encryption-on-voip-ms.mdwn
@@ -2,7 +2,7 @@
 [[!meta date="2019-07-06T16:00:00.000-07:00"]]
 [[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
 
-My [VoIP provider](https://voip.ms) recently added [support for
+My [VoIP provider](https://voip.ms/en/invite/MjE0NTI2) recently added [support for
 TLS/SRTP-based call
 encryption](https://wiki.voip.ms/article/Call_Encryption_-_TLS/SRTP). Here's
 what I did to enable this feature on my

Add snapshot listing command and cleanup local cache during backup
diff --git a/posts/backing-up-to-gnubee2.mdwn b/posts/backing-up-to-gnubee2.mdwn
index e251d69..43a42bb 100644
--- a/posts/backing-up-to-gnubee2.mdwn
+++ b/posts/backing-up-to-gnubee2.mdwn
@@ -181,6 +181,11 @@ to reuse on all of my computers:
     	RESTIC_PASSWORD=$PASSWORD restic --quiet -r $REMOTE_URL ls latest
     	exit 0
     
+    # Show list of available snapshots
+    elif [ "$1" = "--list-snapshots" ]; then
+	    RESTIC_PASSWORD=$GPG_PASSWORD restic --quiet -r $REMOTE_URL snapshots
+	    exit 0
+    
     # Restore the given file
     elif [ "$1" = "--file-to-restore" ]; then
     	if [ "$2" = "" ]; then
@@ -217,8 +222,8 @@ to reuse on all of my computers:
     /sbin/fdisk -l /dev/sda > $PARTITION_FILE
     /sbin/fdisk -l /dev/sdb > $PARTITION_FILE
     
-    # Do the actual backup using Duplicity
-    RESTIC_PASSWORD=$PASSWORD restic --quiet -r $REMOTE_URL backup / --exclude-file $EXCLUDE_FILE
+    # Do the actual backup
+    RESTIC_PASSWORD=$PASSWORD restic --quiet --cleanup-cache -r $REMOTE_URL backup / --exclude-file $EXCLUDE_FILE
 
 I run it with the following cronjob in `/etc/cron.d/backups`:
 

Use hdparm to spin down idle disks
diff --git a/posts/backing-up-to-gnubee2.mdwn b/posts/backing-up-to-gnubee2.mdwn
index 5f1136b..e251d69 100644
--- a/posts/backing-up-to-gnubee2.mdwn
+++ b/posts/backing-up-to-gnubee2.mdwn
@@ -64,6 +64,30 @@ and added the following to `/etc/fstab`:
 
     /dev/md127 /mnt/data/ ext4 noatime,nodiratime 0 2
 
+To reduce unnecessary noise and reduce power consumption, I also installed
+[hdparm](https://sourceforge.net/projects/hdparm/):
+
+    apt install hdparm
+
+and configured all spinning drives to spin down after being idle for 10
+minutes by putting the following in `/etc/hdparm.conf`:
+
+    /dev/sdb {
+           spindown_time = 120
+    }
+    
+    /dev/sdc {
+           spindown_time = 120
+    }
+    
+    /dev/sdd {
+           spindown_time = 120
+    }
+
+and then reloaded the configuration:
+
+     /usr/lib/pm-utils/power.d/95hdparm-apm resume
+
 Finally I setup [smartmontools](https://www.smartmontools.org/) by putting
 the following in `/etc/smartd.conf`:
 

Add a note that a user shell is not needed anymore
diff --git a/posts/backing-up-to-gnubee2.mdwn b/posts/backing-up-to-gnubee2.mdwn
index adfcba8..5f1136b 100644
--- a/posts/backing-up-to-gnubee2.mdwn
+++ b/posts/backing-up-to-gnubee2.mdwn
@@ -96,6 +96,7 @@ the GnuBee:
     adduser machine1
     adduser machine1 sshuser
     adduser machine1 sftponly
+    chsh machine1 -s /bin/false
 
 and then matching directories under `/mnt/data/home/`:
 
diff --git a/posts/hardening-ssh-servers.mdwn b/posts/hardening-ssh-servers.mdwn
index 436ae94..be2ac3f 100644
--- a/posts/hardening-ssh-servers.mdwn
+++ b/posts/hardening-ssh-servers.mdwn
@@ -126,6 +126,7 @@ sftp:
 Then for each user, we need to do the following:
 
     adduser user1 sftp-only
+    chsh user1 -s /bin/false
     mkdir -p /mnt/data/home/user1
     chown user1:user1 /mnt/data/home/user1
     chmod 700 /mnt/data/home/user1

Update my restricted shell ssh instructions and use them on the GnuBee
diff --git a/posts/backing-up-to-gnubee2.mdwn b/posts/backing-up-to-gnubee2.mdwn
index e70567a..adfcba8 100644
--- a/posts/backing-up-to-gnubee2.mdwn
+++ b/posts/backing-up-to-gnubee2.mdwn
@@ -88,15 +88,20 @@ same backup finished in about half the time.
 
 ### User and ssh setup
 
-I created a user account for each machine needing to backup onto the GnuBee:
+After [hardening the ssh
+setup](https://feeding.cloud.geek.nz/posts/hardening-ssh-servers/) as I
+usually do, I created a user account for each machine needing to backup onto
+the GnuBee:
 
     adduser machine1
     adduser machine1 sshuser
+    adduser machine1 sftponly
 
-and then a matching directory under `/mnt/data/`:
+and then matching directories under `/mnt/data/home/`:
 
-    mkdir /mnt/data/machine1
-    chown machine1:machine1 /mnt/data/machine1    
+    mkdir /mnt/data/home/machine1
+    chown machine1:machine1 /mnt/data/home/machine1
+    chmod 700 /mnt/data/home/machine1
 
 Then I created a custom ssh key for each machine:
 
@@ -120,14 +125,12 @@ up the ssh connection](https://gist.github.com/KartikTalwar/4393116) as much
 as possible given that the [GnuBee has avery small RAM
 bandwidth](https://groups.google.com/d/msg/gnubee/5_nKjgmKSoY/a0ER5fEcBAAJ).
 
-On the GnuBee, I switched to the [internal sftp
+Another performance-related change I made on the GnuBee was switching to the [internal sftp
 server](https://serverfault.com/questions/660160/openssh-difference-between-internal-sftp-and-sftp-server#660325)
 by putting the following in `/etc/ssh/sshd_config`:
 
     Subsystem      sftp    internal-sftp
 
-to hopefully improve the performance.
-
 ### Restic script
 
 After reading through the excellent [restic
@@ -139,7 +142,7 @@ to reuse on all of my computers:
     # Configure for each host
     PASSWORD="XXXX"  # use `pwgen -s 64` to generate a good random password
     BACKUP_HOME="/root/backup"
-    REMOTE_URL="sftp:foobar.local:/mnt/data/machine1"
+    REMOTE_URL="sftp:foobar.local:"
     RETENTION_POLICY="--keep-daily 7 --keep-weekly 4 --keep-monthly 12 --keep-yearly 2"
     
     # Internal variables
diff --git a/posts/hardening-ssh-servers.mdwn b/posts/hardening-ssh-servers.mdwn
index 17f136a..436ae94 100644
--- a/posts/hardening-ssh-servers.mdwn
+++ b/posts/hardening-ssh-servers.mdwn
@@ -89,22 +89,57 @@ servers and use small
 [scripts](https://github.com/fmarier/user-scripts/blob/master/spascp)
 to connect to them.
 
-# Using restricted shells
+# Restricting shell access
 
 For those users who only need an ssh account on the server in order to
-transfer files (using `scp` or `rsync`), it's a good idea to set their shell
-(via [chsh](http://linux.die.net/man/1/chsh)) to a restricted one like
-[rssh](http://www.pizzashack.org/rssh/).
-
-Should they attempt to log into the server, these users will be greeted with
-the following error message:
-
-    This account is restricted by rssh.
-    Allowed commands: rsync 
-    
-    If you believe this is in error, please contact your system administrator.
-    
-    Connection to server.example.com closed.
+transfer files (using `scp` or `rsync`), it's a good idea to restrict their
+access further. I used to switch these users' shell (via [chsh](http://linux.die.net/man/1/chsh)) to a restricted one like
+[rssh](http://www.pizzashack.org/rssh/), but that project has been
+[abandoned](https://tracker.debian.org/news/1033905/removed-234-12-from-unstable/).
+
+I now use a [different
+approach](https://www.allthingsdigital.nl/2013/05/12/setting-up-an-sftp-only-account-with-openssh/)
+which consists of using an essentially empty chroot for these users and
+limiting them to `internal-sftp` by putting the following in
+`/etc/ssh/sshd_config`:
+
+    Match Group sftponly
+      ForceCommand internal-sftp
+      ChrootDirectory /mnt/data
+
+creating a group:
+
+    adduser sftponly
+
+and a base chroot directory:
+
+    mkdir -p /mnt/data/home
+
+Note that the base directory, and each parent directory all the way to the
+root directory, must be owned by `root:root` (user **and** group) otherwise
+you'll see an unhelpful error message like this when you try to connect via
+sftp:
+
+    $ sftp user1@server.example
+    client_loop: send disconnect: Broken pipe
+
+Then for each user, we need to do the following:
+
+    adduser user1 sftp-only
+    mkdir -p /mnt/data/home/user1
+    chown user1:user1 /mnt/data/home/user1
+    chmod 700 /mnt/data/home/user1
+
+before restarting the ssh daemon:
+
+    systemctl restart sshd.service
+
+Should one of these users attempt to connect via ssh instead of stp, they
+will see the following:
+
+    $ ssh user1@server.example
+    This service allows sftp connections only.
+    Connection to server.example closed.
 
 # Restricting authorized keys to certain IP addresses
 

Switch to internal-sftp server for ssh
diff --git a/posts/backing-up-to-gnubee2.mdwn b/posts/backing-up-to-gnubee2.mdwn
index fd28a06..e70567a 100644
--- a/posts/backing-up-to-gnubee2.mdwn
+++ b/posts/backing-up-to-gnubee2.mdwn
@@ -120,6 +120,14 @@ up the ssh connection](https://gist.github.com/KartikTalwar/4393116) as much
 as possible given that the [GnuBee has avery small RAM
 bandwidth](https://groups.google.com/d/msg/gnubee/5_nKjgmKSoY/a0ER5fEcBAAJ).
 
+On the GnuBee, I switched to the [internal sftp
+server](https://serverfault.com/questions/660160/openssh-difference-between-internal-sftp-and-sftp-server#660325)
+by putting the following in `/etc/ssh/sshd_config`:
+
+    Subsystem      sftp    internal-sftp
+
+to hopefully improve the performance.
+
 ### Restic script
 
 After reading through the excellent [restic
diff --git a/posts/backing-up-to-gnubee2/comment_1_fc4bfe71d22f6d6f3682674e1a839fbf._comment b/posts/backing-up-to-gnubee2/comment_1_fc4bfe71d22f6d6f3682674e1a839fbf._comment
deleted file mode 100644
index c4da712..0000000
--- a/posts/backing-up-to-gnubee2/comment_1_fc4bfe71d22f6d6f3682674e1a839fbf._comment
+++ /dev/null
@@ -1,7 +0,0 @@
-[[!comment format=mdwn
- ip="72.239.48.49"
- subject="further hardening"
- date="2020-05-05T11:25:39Z"
- content="""
-consider using/mentioning the sshd internal-sftp option for further security from backup accounts
-"""]]
diff --git a/posts/hardening-ssh-servers.mdwn b/posts/hardening-ssh-servers.mdwn
index 7680ac3..17f136a 100644
--- a/posts/hardening-ssh-servers.mdwn
+++ b/posts/hardening-ssh-servers.mdwn
@@ -47,6 +47,12 @@ which can be done by commenting out this line:
 
     #Subsystem     sftp    /usr/lib/openssh/sftp-server
 
+On the other hand, if you do need it, it's generally better to replace it
+with the [internal sftp
+server](https://serverfault.com/questions/660160/openssh-difference-between-internal-sftp-and-sftp-server#660325):
+
+    Subsystem     sftp    internal-sftp
+
 # Whitelist approach to giving users ssh access
 
 To ensure that only a few users have ssh access to the server and that newly

Comment moderation
diff --git a/posts/backing-up-to-gnubee2/comment_1_fc4bfe71d22f6d6f3682674e1a839fbf._comment b/posts/backing-up-to-gnubee2/comment_1_fc4bfe71d22f6d6f3682674e1a839fbf._comment
new file mode 100644
index 0000000..c4da712
--- /dev/null
+++ b/posts/backing-up-to-gnubee2/comment_1_fc4bfe71d22f6d6f3682674e1a839fbf._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ ip="72.239.48.49"
+ subject="further hardening"
+ date="2020-05-05T11:25:39Z"
+ content="""
+consider using/mentioning the sshd internal-sftp option for further security from backup accounts
+"""]]

Comment moderation
diff --git a/posts/lxc-setup-on-debian-stretch/comment_2_ba09c54f7093eda0e92cb3c0859e81cc._comment b/posts/lxc-setup-on-debian-stretch/comment_2_ba09c54f7093eda0e92cb3c0859e81cc._comment
new file mode 100644
index 0000000..9e5ae05
--- /dev/null
+++ b/posts/lxc-setup-on-debian-stretch/comment_2_ba09c54f7093eda0e92cb3c0859e81cc._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ ip="167.62.217.58"
+ claimedauthor="Sergio_L"
+ subject="How about bridging"
+ date="2020-04-24T19:09:30Z"
+ content="""
+Thank you very much for the article, following it was the first time I got my containers to have internet access, I was trying to expose them to my DHCP before with no success (using debian stretch) so If you feel like adding that option to your article I'll be very grateful! 
+"""]]
diff --git a/posts/using-gogo-wifi-linux/comment_1_bc941207d2f8703bf0e0c20c2d5f988c._comment b/posts/using-gogo-wifi-linux/comment_1_bc941207d2f8703bf0e0c20c2d5f988c._comment
new file mode 100644
index 0000000..f6bdb21
--- /dev/null
+++ b/posts/using-gogo-wifi-linux/comment_1_bc941207d2f8703bf0e0c20c2d5f988c._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ ip="2601:646:202:a820:2ceb:9c42:581:3448"
+ claimedauthor="Stefano Rivera"
+ url="https://stefanorivera.com/"
+ subject="comment 1"
+ date="2020-04-28T21:19:43Z"
+ content="""
+Hrm, I've never found that necessary on Gogo on Delta.
+
+I just browse directly to http://airborne.gogoinflight.com/
+Or, more recently, https://airbornesecure.gogoinflight.com/
+"""]]

Add link to ionice, nice, and nocache blog post.
diff --git a/posts/backing-up-to-gnubee2.mdwn b/posts/backing-up-to-gnubee2.mdwn
index c316cb3..fd28a06 100644
--- a/posts/backing-up-to-gnubee2.mdwn
+++ b/posts/backing-up-to-gnubee2.mdwn
@@ -189,6 +189,8 @@ I run it with the following cronjob in `/etc/cron.d/backups`:
     30 8 * * *    root  ionice nice nocache /root/backup/backup-machine1-to-foobar
     30 2 * * Sun  root  ionice nice nocache /root/backup/backup-machine1-to-foobar --prune
 
+in a way that [doesn't impact the rest of the system too much](https://feeding.cloud.geek.nz/posts/three-wrappers-to-run-commands-without-impacting-the-rest-of-the-system/).
+
 Finally, I printed a copy of each of my backup script, using
 [enscript](https://www.gnu.org/software/enscript/), to stash in a safe place:
 

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

Add GnuBee backup post
diff --git a/posts/backing-up-to-gnubee2.mdwn b/posts/backing-up-to-gnubee2.mdwn
new file mode 100644
index 0000000..c316cb3
--- /dev/null
+++ b/posts/backing-up-to-gnubee2.mdwn
@@ -0,0 +1,200 @@
+[[!meta title="Backing up to a GnuBee PC 2"]]
+[[!meta date="2020-05-02T18:05:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+After [installing Debian buster on my
+GnuBee](https://feeding.cloud.geek.nz/posts/installing-debian-buster-on-gnubee2/), 
+I set it up for receiving backups from my other computers.
+
+## Software setup
+
+I started by configuring it [like a typical
+server](https://feeding.cloud.geek.nz/posts/usual-server-setup/) but without
+a few packages that either take a lot of memory or CPU:
+
+- [fail2ban](https://packages.debian.org/buster/fail2ban)
+- [rkhunter](https://packages.debian.org/buster/rkhunter)
+- [sysstat](https://packages.debian.org/buster/sysstat)
+
+I changed the default hostname:
+
+- `/etc/hostname`: `foobar`
+- `/etc/mailname`: `foobar.example.com`
+- `/etc/hosts`: `127.0.0.1  foobar.example.com vogar localhost`
+
+and then installed the `avahi-daemon` package to be able to reach this box
+using `foobar.local`.
+
+I noticed the presence of a [world-writable
+directory](https://github.com/neilbrown/gnubee-tools/issues/23) and so I
+tightened the security of some of the default mount points by putting the following
+in `/etc/rc.local`:
+
+    mount -o remount,nodev,nosuid /etc/network
+    mount -o remount,nodev,nosuid /lib/modules
+    chmod 755 /etc/network
+    exit 0
+
+## Hardware setup
+
+My OS drive (`/dev/sda`) is a small SSD so that the GnuBee can run silently when the
+spinning disks aren't needed. To hold the backup data on the other hand, I
+got three 4-TB drives drives which I setup in a
+[RAID-5](https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_5) array.
+If the data were valuable, I'd use
+[RAID-6](https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_6) instead
+since it can survive two drives failing at the same time, but in this case
+since it's only holding backups, I'd have to lose the original machine at
+the same time as two of the 3 drives, a very unlikely scenario.
+
+I created new gpt partition tables on `/dev/sdb`, `/dev/sdbc`, `/dev/sdd`
+and used `fdisk` to create a single partition of `type 29` (Linux RAID) on
+each of them.
+
+Then I created the RAID array:
+
+    mdadm /dev/md127 --create -n 3 --level=raid5 -a /dev/sdb1 /dev/sdc1 /dev/sdd1
+
+and waited more than 24 hours for that operation to finish. Next, I
+formatted the array:
+
+    mkfs.ext4 -m 0 /dev/md127
+
+and added the following to `/etc/fstab`:
+
+    /dev/md127 /mnt/data/ ext4 noatime,nodiratime 0 2
+
+Finally I setup [smartmontools](https://www.smartmontools.org/) by putting
+the following in `/etc/smartd.conf`:
+
+    /dev/sda -a -o on -S on -s (S/../.././02|L/../../6/03)
+    /dev/sdb -a -o on -S on -s (S/../.././02|L/../../6/03)
+    /dev/sdc -a -o on -S on -s (S/../.././02|L/../../6/03)
+    /dev/sdd -a -o on -S on -s (S/../.././02|L/../../6/03)
+
+and restarting the daemon:
+
+    systemctl restart smartd.service
+
+## Backup setup
+
+I started by using [duplicity](http://duplicity.nongnu.org/) since I have
+been using that tool for many years, but a 190GB backup took around 15 hours
+on the GnuBee with gigabit ethernet.
+
+After a [friend](https://stumbles.id.au/) suggested it, I took a look at
+[restic](https://restic.net) and I have to say that I am impressed. The
+same backup finished in about half the time.
+
+### User and ssh setup
+
+I created a user account for each machine needing to backup onto the GnuBee:
+
+    adduser machine1
+    adduser machine1 sshuser
+
+and then a matching directory under `/mnt/data/`:
+
+    mkdir /mnt/data/machine1
+    chown machine1:machine1 /mnt/data/machine1    
+
+Then I created a custom ssh key for each machine:
+
+    ssh-keygen -f /root/.ssh/foobar_backups -t ed25519
+
+and placed it in `/home/machine1/.ssh/authorized_keys` on the GnuBee.
+
+On each machine, I added the following to `/root/.ssh/config`:
+
+    Host foobar.local
+        User machine1
+        Compression no
+        Ciphers aes128-ctr
+        IdentityFile /root/backup/foobar_backups
+        IdentitiesOnly yes
+        ServerAliveInterval 60
+        ServerAliveCountMax 240
+
+The reason for setting the ssh cipher and disabling compression is to [speed
+up the ssh connection](https://gist.github.com/KartikTalwar/4393116) as much
+as possible given that the [GnuBee has avery small RAM
+bandwidth](https://groups.google.com/d/msg/gnubee/5_nKjgmKSoY/a0ER5fEcBAAJ).
+
+### Restic script
+
+After reading through the excellent [restic
+documentation](https://restic.readthedocs.io/en/stable/), I wrote the
+following backup script, based on my [old duplicity
+script](https://sources.debian.org/src/duplicity/0.8.11.1612-1/debian/examples/system-backup/),
+to reuse on all of my computers:
+
+    # Configure for each host
+    PASSWORD="XXXX"  # use `pwgen -s 64` to generate a good random password
+    BACKUP_HOME="/root/backup"
+    REMOTE_URL="sftp:foobar.local:/mnt/data/machine1"
+    RETENTION_POLICY="--keep-daily 7 --keep-weekly 4 --keep-monthly 12 --keep-yearly 2"
+    
+    # Internal variables
+    SSH_IDENTITY="IdentityFile=$BACKUP_HOME/foobar_backups"
+    EXCLUDE_FILE="$BACKUP_HOME/exclude"
+    PKG_FILE="$BACKUP_HOME/dpkg-selections"
+    PARTITION_FILE="$BACKUP_HOME/partitions"
+    
+    # If the list of files has been requested, only do that
+    if [ "$1" = "--list-current-files" ]; then
+    	RESTIC_PASSWORD=$PASSWORD restic --quiet -r $REMOTE_URL ls latest
+    	exit 0
+    
+    # Restore the given file
+    elif [ "$1" = "--file-to-restore" ]; then
+    	if [ "$2" = "" ]; then
+    		echo "You must specify a file to restore"
+    		exit 2
+    	fi
+    	RESTORE_DIR="$(mktemp -d ./restored_XXXXXXXX)"
+    	RESTIC_PASSWORD=$PASSWORD restic --quiet -r $REMOTE_URL restore latest --target "$RESTORE_DIR" --include "$2" || exit 1
+    	echo "$2 was restored to $RESTORE_DIR"
+    	exit 0
+    
+    # Delete old backups
+    elif [ "$1" = "--prune" ]; then
+        # Expire old backups
+        RESTIC_PASSWORD=$PASSWORD restic --quiet -r $REMOTE_URL forget $RETENTION_POLICY
+    
+        # Delete files which are no longer necessary (slow)
+        RESTIC_PASSWORD=$PASSWORD restic --quiet -r $REMOTE_URL prune
+        exit 0
+    
+    # Catch invalid arguments
+    elif [ "$1" != "" ]; then
+    	echo "Invalid argument: $1"
+    	exit 1
+    fi
+    
+    # Check the integrity of existing backups
+    RESTIC_PASSWORD=$PASSWORD restic --quiet -r $REMOTE_URL check || exit 1
+    
+    # Dump list of Debian packages
+    dpkg --get-selections > $PKG_FILE
+    
+    # Dump partition tables from harddrives
+    /sbin/fdisk -l /dev/sda > $PARTITION_FILE
+    /sbin/fdisk -l /dev/sdb > $PARTITION_FILE
+    
+    # Do the actual backup using Duplicity
+    RESTIC_PASSWORD=$PASSWORD restic --quiet -r $REMOTE_URL backup / --exclude-file $EXCLUDE_FILE
+
+I run it with the following cronjob in `/etc/cron.d/backups`:
+
+    30 8 * * *    root  ionice nice nocache /root/backup/backup-machine1-to-foobar
+    30 2 * * Sun  root  ionice nice nocache /root/backup/backup-machine1-to-foobar --prune
+
+Finally, I printed a copy of each of my backup script, using
+[enscript](https://www.gnu.org/software/enscript/), to stash in a safe place:
+

(Diff truncated)
Something else is needed to turn off etckeeper auto-commits
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index ec41847..a29424f 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -48,6 +48,11 @@ and this in `/etc/.git/config`:
     [commit]
         gpgsign = false
 
+Note that in order to fully turn off auto-commits, it's also necessary
+to run the following:
+
+    systemctl disable etckeeper.timer
+
 To get more control over the various packages I install, I change the
 default debconf level to medium:
 

Add instructions for fixing the serial console output
diff --git a/posts/installing-debian-buster-on-gnubee2.mdwn b/posts/installing-debian-buster-on-gnubee2.mdwn
index 7a22444..04185d0 100644
--- a/posts/installing-debian-buster-on-gnubee2.mdwn
+++ b/posts/installing-debian-buster-on-gnubee2.mdwn
@@ -230,4 +230,21 @@ Finally, I cleaned up a deprecated and no-longer-needed package:
 
 and removed its invocation from `/etc/rc.local` and `/etc/cron.d/ntp`.
 
+## Fixing the serial console
+
+The serial console, [automatically started by
+systemd](https://github.com/systemd/systemd/issues/15611), seems to get
+corrupted every now and then. If you see garbled output (i.e. binary
+characters instead of text), then you are running into this problem.
+
+The fix, [suggested by Jernej
+Jakob](https://groups.google.com/d/msg/gnubee/N4fxGgwOyiQ/pntsYccgBAAJ), is
+to override the default systemd unit file by creating a
+`/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf` with the
+following contents:
+
+    [Service]
+    ExecStart=
+    ExecStart=-/sbin/agetty -o '-p -- \\u' 57600 %I $TERM
+
 [[!tag debian]] [[!tag gnubee]]

Mention how to exit from `screen`
diff --git a/posts/installing-debian-buster-on-gnubee2.mdwn b/posts/installing-debian-buster-on-gnubee2.mdwn
index 32a97db..7a22444 100644
--- a/posts/installing-debian-buster-on-gnubee2.mdwn
+++ b/posts/installing-debian-buster-on-gnubee2.mdwn
@@ -33,6 +33,9 @@ you can use it to monitor the flashing process:
 
 otherwise keep an eye on the [LEDs and wait until they are fully done
 flashing](https://github.com/gnubee-git/GnuBee_Docs/wiki/Install-firmware#via-usb-stick).
+When you want to [exit
+screen](https://stackoverflow.com/questions/4847691/how-do-i-get-out-of-a-screen-without-typing-exit#),
+use `Ctrl-a` then `k`.
 
 ## Getting ssh access to LibreCMC
 

Add a note about using mosh and pagekite together
diff --git a/posts/letting-someone-ssh-into-your-laptop-using-pagekite.mdwn b/posts/letting-someone-ssh-into-your-laptop-using-pagekite.mdwn
index 90562b2..1e475df 100644
--- a/posts/letting-someone-ssh-into-your-laptop-using-pagekite.mdwn
+++ b/posts/letting-someone-ssh-into-your-laptop-using-pagekite.mdwn
@@ -88,4 +88,33 @@ before restarting the pagekite daemon using:
 
     systemctl restart pagekite
 
-[[!tag mozilla]] [[!tag debian]] [[!tag sysadmin]] [[!tag ssh]] [[!tag nzoss]] [[!tag pagekite]]
+# Using mosh and pagekite
+
+[Mosh](https://mosh.org/) is a nice way to interface with ssh over
+high-latency netowrks. However, it's not possible to tunnel mosh directly
+through pagekited since [pagekite only supports
+TCP](https://groups.google.com/d/topic/pagekite-discuss/YUfhVfWyYsU/discussion).
+
+I ended up with a hybrid setup where I don't have to expose the ssh service
+to the local network (and therefore remember to disable it when I'm done)
+but I do have to open a UDP port on my firewall for mosh.
+
+First, I assigned a stable IP to my laptop on my router, based on its MAC
+address. I also had to disable [MAC address spoofing in Network Manager](https://blogs.gnome.org/thaller/2016/08/26/mac-address-spoofing-in-networkmanager-1-4-0/) (setting it to permanent).
+
+This is what my `/etc/NetworkManager/system-connections/Ethernet automatique` config looks like:
+
+    [ethernet]
+    cloned-mac-address=preserve
+    
+    [ipv4]
+    method=auto
+    
+    [ipv6]
+    addr-gen-mode=stable-privacy
+    ip6-privacy=2
+    method=auto
+
+Then I forwarded port 9000 (UDP) traffic to the static IP address above.
+
+[[!tag mozilla]] [[!tag debian]] [[!tag sysadmin]] [[!tag ssh]] [[!tag pagekite]]

Limit Planet Sysadmin feed further, just in case
diff --git a/tags/sysadmin.mdwn b/tags/sysadmin.mdwn
index 04240f9..56369d8 100644
--- a/tags/sysadmin.mdwn
+++ b/tags/sysadmin.mdwn
@@ -1,4 +1,4 @@
 [[!meta title="pages tagged sysadmin"]]
 
 [[!inline pages="tagged(sysadmin)" actions="no" archive="yes"
-feedshow=10 feedpages=created_after(posts/debugging-openwrt-routers-by-shipping)]]
+feedshow=10 feedpages=created_after(posts/secure-ssh-agent-usage)]]

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

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

Add a DMARC post.
diff --git a/posts/disabling-mail-sending-from-domain.mdwn b/posts/disabling-mail-sending-from-domain.mdwn
new file mode 100644
index 0000000..e097240
--- /dev/null
+++ b/posts/disabling-mail-sending-from-domain.mdwn
@@ -0,0 +1,33 @@
+[[!meta title="Disabling mail sending from your domain"]]
+[[!meta date="2020-04-23T22:10:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+I noticed that I was receiving some bounced email notifications from a
+domain I own (`cloud.geek.nz`) to host my blog. These notifications were all
+for spam messages spoofing the `From` address since I do not use that domain
+for email.
+
+I decided to try setting a strict [DMARC
+policy](https://dmarcly.com/blog/how-to-implement-dmarc-dkim-spf-to-stop-email-spoofing-phishing-the-definitive-guide)
+to see if DMARC-using mail servers (e.g. GMail) would then drop these
+spoofed emails without notifying me about it.
+
+I started by setting this initial DMARC policy in DNS in order to monitor the change:
+
+    @ TXT v=spf1 -all
+    _dmarc TXT v=DMARC1; p=none; ruf=mailto:dmarc@fmarier.org; sp=none; aspf=s; fo=0:1:d:s;
+
+Then I waited three weeks without receiving anything before updating the
+relevant DNS records to this final DMARC policy:
+
+    @ TXT v=spf1 -all
+    _dmarc TXT v=DMARC1; p=reject; sp=reject; aspf=s;
+
+This policy states that nobody is allowed to send emails for this domain and
+that any incoming email claiming to be from this domain should be silently
+rejected.
+
+I haven't noticed any bounce notifications for messages spoofing this domain
+in a while, so maybe it's working?
+
+[[!tag sysadmin]] [[!tag debian]] [[!tag dns]] [[!tag email]]

Create "email" and "gmail" tags for existing posts
diff --git a/posts/disabling-gmail-spam-filter-and.mdwn b/posts/disabling-gmail-spam-filter-and.mdwn
index 3e61973..e7fb5c0 100644
--- a/posts/disabling-gmail-spam-filter-and.mdwn
+++ b/posts/disabling-gmail-spam-filter-and.mdwn
@@ -35,4 +35,4 @@ This is done using [procmail](http://www.procmail.org/) with the following bit i
     * ^X-Spam-Status: Yes
     /home/francois/mail/spam
 
-[[!tag catalyst]] [[!tag debian]] [[!tag sysadmin]] [[!tag ubuntu]] 
+[[!tag catalyst]] [[!tag debian]] [[!tag sysadmin]] [[!tag ubuntu]] [[!tag email]] [[!tag gmail]]
diff --git a/posts/handling-multiple-identitiesaccounts-in.mdwn b/posts/handling-multiple-identitiesaccounts-in.mdwn
index fe5b521..6a7a1ae 100644
--- a/posts/handling-multiple-identitiesaccounts-in.mdwn
+++ b/posts/handling-multiple-identitiesaccounts-in.mdwn
@@ -44,4 +44,4 @@ Finally, I've got this convenient shortcut which allows me to switch to my inbox
 Next up: [[indexing your emails using mairix|posts/searching-through-contents-of-emails-in/]].
 
 
-[[!tag mutt]] [[!tag catalyst]] [[!tag debian]] [[!tag ubuntu]] 
+[[!tag mutt]] [[!tag catalyst]] [[!tag debian]] [[!tag ubuntu]] [[!tag email]]
diff --git a/posts/keeping-gmail-in-separate-browser.mdwn b/posts/keeping-gmail-in-separate-browser.mdwn
index cfa141b..2d24f4a 100644
--- a/posts/keeping-gmail-in-separate-browser.mdwn
+++ b/posts/keeping-gmail-in-separate-browser.mdwn
@@ -48,4 +48,4 @@ Then log into GMail and tick the "Trust this computer" checkbox at the 2-factor
 With these settings, your browsing history will be cleared and you will be logged out of GMail every time you close your browser but will still be able to skip the 2-factor step on that device.
 
 
-[[!tag firefox]] [[!tag debian]] [[!tag ubuntu]] [[!tag privacy]] [[!tag nzoss]] [[!tag mozilla]] 
+[[!tag firefox]] [[!tag debian]] [[!tag ubuntu]] [[!tag privacy]] [[!tag nzoss]] [[!tag mozilla]] [[!tag gmail]]
diff --git a/posts/mutts-openpgp-support-and-firegpg.mdwn b/posts/mutts-openpgp-support-and-firegpg.mdwn
index b7b2818..7174089 100644
--- a/posts/mutts-openpgp-support-and-firegpg.mdwn
+++ b/posts/mutts-openpgp-support-and-firegpg.mdwn
@@ -32,4 +32,4 @@ However, this didn't actually work with FireGPG and the way that it puts encrypt
 
 
 
-[[!tag mutt]] [[!tag catalyst]] [[!tag debian]] [[!tag sysadmin]] [[!tag ubuntu]] 
+[[!tag mutt]] [[!tag catalyst]] [[!tag debian]] [[!tag sysadmin]] [[!tag ubuntu]] [[!tag email]]
diff --git a/posts/preventing-man-in-middle-attacks-on.mdwn b/posts/preventing-man-in-middle-attacks-on.mdwn
index 6d2c76e..c2b6c55 100644
--- a/posts/preventing-man-in-middle-attacks-on.mdwn
+++ b/posts/preventing-man-in-middle-attacks-on.mdwn
@@ -60,4 +60,4 @@ smtp_tls_fingerprint_cert_match =
    <i>12:34:AB:CD:56:78:EF:90:12:AB:CD:34:56:EF:78:90:AB:CD:12:34:AB:DD:44:66:DA:77:CF:DB:E4:A7:02:E1</i>
 </pre>
 
-[[!tag mutt]] [[!tag catalyst]] [[!tag debian]] [[!tag security]] [[!tag ubuntu]] [[!tag nzoss]] [[!tag fetchmail]] [[!tag postfix]]
+[[!tag mutt]] [[!tag catalyst]] [[!tag debian]] [[!tag security]] [[!tag ubuntu]] [[!tag nzoss]] [[!tag fetchmail]] [[!tag postfix]] [[!tag email]] [[!tag gmail]]
diff --git a/posts/searching-through-contents-of-emails-in.mdwn b/posts/searching-through-contents-of-emails-in.mdwn
index 88317e7..19d2d68 100644
--- a/posts/searching-through-contents-of-emails-in.mdwn
+++ b/posts/searching-through-contents-of-emails-in.mdwn
@@ -40,4 +40,4 @@ If you use GPG, you should also add this to your `~/.muttrc` to make sure that m
     bind pager s decrypt-save
 
 
-[[!tag mutt]] [[!tag catalyst]] [[!tag debian]] [[!tag ubuntu]] 
+[[!tag mutt]] [[!tag catalyst]] [[!tag debian]] [[!tag ubuntu]] [[!tag email]]
diff --git a/posts/test-mail-server-ubuntu-debian.mdwn b/posts/test-mail-server-ubuntu-debian.mdwn
index 3fe9f26..f444c0f 100644
--- a/posts/test-mail-server-ubuntu-debian.mdwn
+++ b/posts/test-mail-server-ubuntu-debian.mdwn
@@ -34,4 +34,4 @@ and then view the mailbox like this:
 
     mutt -f /var/mail/root
 
-[[!tag debian]] [[!tag nzoss]] [[!tag postfix]]
+[[!tag debian]] [[!tag nzoss]] [[!tag postfix]] [[!tag email]]
diff --git a/posts/things-that-work-well-with-tor.mdwn b/posts/things-that-work-well-with-tor.mdwn
index 1885807..110a615 100644
--- a/posts/things-that-work-well-with-tor.mdwn
+++ b/posts/things-that-work-well-with-tor.mdwn
@@ -139,4 +139,4 @@ I can take advantage of GMail's excellent caching and preloading and run the
 whole thing over Tor by setting that entire browser profile to run its
 traffic through the Tor SOCKS proxy on port `9050`.
 
-[[!tag debian]] [[!tag privacy]] [[!tag tor]] [[!tag nzoss]] [[!tag mozilla]] [[!tag xmpp]]
+[[!tag debian]] [[!tag privacy]] [[!tag tor]] [[!tag nzoss]] [[!tag mozilla]] [[!tag xmpp]] [[!tag gmail]]

Comment moderation
diff --git a/posts/making-sip-calls-voipms-without-pstn/comment_1_5b51ef3a4c00b6f1182718fa75c08b49._comment b/posts/making-sip-calls-voipms-without-pstn/comment_1_5b51ef3a4c00b6f1182718fa75c08b49._comment
new file mode 100644
index 0000000..70496e7
--- /dev/null
+++ b/posts/making-sip-calls-voipms-without-pstn/comment_1_5b51ef3a4c00b6f1182718fa75c08b49._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ ip="185.242.5.35"
+ claimedauthor="seth black wider"
+ subject="two flavors"
+ date="2020-04-18T01:35:51Z"
+ content="""
+there are two flavors of sip uri there.
+
+[DID]@sip.voip.ms
+[subaccount]@[POP].voip.ms
+
+and they are not interchangeable.
+"""]]

Remove deprecated option
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index fa4f750..ec41847 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -95,8 +95,6 @@ and end up with the following settings in `/etc/ssh/sshd_config` (jessie):
     Ciphers chacha20-poly1305@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
     MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
  
-    UsePrivilegeSeparation sandbox
-
     AuthenticationMethods publickey
     PasswordAuthentication no
     PermitRootLogin no

Add missing postfix-related package for SASL
https://www.howtoforge.com/community/threads/solved-problem-with-outgoing-mail-from-server.53920/
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index 1387dbf..fa4f750 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -315,7 +315,7 @@ and then run:
 
 # Mail
 
-    apt install postfix
+    apt install postfix libsasl2-modules
     apt purge exim4-base exim4-daemon-light exim4-config
 
 Configuring mail properly is tricky but the following has worked for me.

Add missing perl package for mon
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index a1bb7bc..1387dbf 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -368,7 +368,7 @@ To monitor that mail never stops flowing, add this machine to a free
 
 # Monitoring
 
-    apt install --no-install-recommends mon libfilesys-diskspace-perl
+    apt install --no-install-recommends mon libfilesys-diskspace-perl libfilesys-df-perl
 
 In order to ensure that the root partition never has less than 1G of free
 space, I put the following in `/etc/mon/mon.cf`:

Add another user which sometimes receives mail
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index 5230bd3..a1bb7bc 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -341,7 +341,7 @@ Set the following aliases in `/etc/aliases`:
 
 - set `francois` as the destination of `root` emails
 - set an external email address for `francois`
-- set `root` as the destination for `www-data` emails
+- set `root` as the destination for `mon` and `www-data` emails
 
 before running `newaliases` to update the aliases database.
 

Fix checkmail execute bit and healthchecks.io domain
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index 5f27fc7..5230bd3 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -350,7 +350,10 @@ Create a new cronjob (`/etc/cron.hourly/checkmail`):
     #!/bin/sh
     ls /var/mail
 
-to ensure that email doesn't accumulate unmonitored on this box.
+to ensure that email doesn't accumulate unmonitored on this box. Don't
+forget to make the script executable:
+
+    chmod +x /etc/cron.hourly/checkmail
 
 Finally, set reverse DNS for the server's IPv4 and IPv6 addresses and then
 test the whole setup using `mail root`. You should also use
@@ -361,7 +364,7 @@ To monitor that mail never stops flowing, add this machine to a free
 [healthchecks.io](https://healthchecks.io) account and create a
 `/etc/cron.d/healthchecks-io` cronjob:
 
-    0 1 * * * root echo "ping" | mail xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx@hchk.io
+    0 1 * * * root echo "ping" | mail xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx@hc-ping.com
 
 # Monitoring
 

Add additional ntpdate caller.
diff --git a/posts/installing-debian-buster-on-gnubee2.mdwn b/posts/installing-debian-buster-on-gnubee2.mdwn
index 139a67f..32a97db 100644
--- a/posts/installing-debian-buster-on-gnubee2.mdwn
+++ b/posts/installing-debian-buster-on-gnubee2.mdwn
@@ -225,6 +225,6 @@ Finally, I cleaned up a deprecated and no-longer-needed package:
 
     apt purge ntpdate
 
-and removed its invocation from `/etc/rc.local`.
+and removed its invocation from `/etc/rc.local` and `/etc/cron.d/ntp`.
 
 [[!tag debian]] [[!tag gnubee]]

Add Gogo on Linux post
diff --git a/posts/using-gogo-wifi-linux.mdwn b/posts/using-gogo-wifi-linux.mdwn
new file mode 100644
index 0000000..961d4ba
--- /dev/null
+++ b/posts/using-gogo-wifi-linux.mdwn
@@ -0,0 +1,43 @@
+[[!meta title="Using Gogo WiFi on Linux"]]
+[[!meta date="2020-04-11T16:30:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+[Gogo](https://www.gogoair.com/for-passengers/), the WiFi provider for
+[airlines like Air Canada](https://www.gogoair.com/participating-airlines/),
+is not available to Linux users even though it advertises ["access using any
+Wi-Fi enabled laptop, tablet or
+smartphone"](https://www.gogoair.com/ac-bbyf/one-way-pass/detail/). It is
+however possible to work-around this restriction by faking your browser
+[user agent](https://en.wikipedia.org/wiki/User_agent).
+
+I tried the [User-Agent Switcher for
+Chrome](https://chrome.google.com/webstore/detail/user-agent-switcher-for-c/djflhoibgkdhkhhcedjiklpkjnoahfmg)
+extension on Chrome and [Brave](https://brave.com/clo187) but it didn't work
+for some reason.
+
+What did work was using Firefox and adding the following prefs in
+`about:config` to spoof its user agent to Chrome for Windows:
+
+    general.useragent.override=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36
+    general.useragent.updates.enabled=false
+    privacy.resistFingerprinting=false
+
+The last two prefs are necessary in order for the hidden
+`general.useragent.override` pref to [not be
+ignored](https://searchfox.org/mozilla-central/rev/8ed108064bf1c83e508208e069a90cffb4045977/dom/base/Navigator.cpp#1892-1904).
+
+# Opt out of mandatory arbitration
+
+As an aside, the Gogo [terms of
+service](https://content.gogoair.com/terms/aca/?lang=en_US) automatically
+enroll you into [mandatory
+arbitration](https://www.hotcoffeethemovie.com/default.asp?pg=mandatory_arbitration)
+unless you opt out by sending an email to
+[customercare@gogoair.com](mailto:customercare@gogoair.com) within 30 days
+of using their service.
+
+You may want to create an email template for this so that you can fire off a
+quick email to them as soon as you connect. I will probably write a script
+for it next time I use this service.
+
+[[!tag debian]] [[!tag firefox]]

Remove obsolete comments from GnuBee post
diff --git a/posts/installing-debian-buster-on-gnubee2/comment_1_2a3c537445b6d27e05446e43471ddc81._comment b/posts/installing-debian-buster-on-gnubee2/comment_1_2a3c537445b6d27e05446e43471ddc81._comment
deleted file mode 100644
index 83f1c74..0000000
--- a/posts/installing-debian-buster-on-gnubee2/comment_1_2a3c537445b6d27e05446e43471ddc81._comment
+++ /dev/null
@@ -1,9 +0,0 @@
-[[!comment format=mdwn
- ip="188.192.119.43"
- claimedauthor="Hein Osenberg"
- subject="Works for me"
- date="2019-09-02T19:21:34Z"
- content="""
-With Neil Browns new kernel (5.2.8 - see <http://neil.brown.name/gnubee/>), installed (see README) upgrading to Debian Buster worked perfectly for me. SSH access works
-out of the box without problems.
-"""]]
diff --git a/posts/installing-debian-buster-on-gnubee2/comment_2_bc2dba3b221d2d92ae9c306d1be4fc0d._comment b/posts/installing-debian-buster-on-gnubee2/comment_2_bc2dba3b221d2d92ae9c306d1be4fc0d._comment
deleted file mode 100644
index 1ea2359..0000000
--- a/posts/installing-debian-buster-on-gnubee2/comment_2_bc2dba3b221d2d92ae9c306d1be4fc0d._comment
+++ /dev/null
@@ -1,9 +0,0 @@
-[[!comment format=mdwn
- ip="165.225.114.98"
- claimedauthor="Antoine"
- subject="Same issue with SSH"
- date="2019-09-09T08:49:57Z"
- content="""
-Hi, 
-Just stumbled onto this post. I have the same issue with SSH, on a GnuBee PC1. I believe openssh is running (according to OpenMediaVault GUI), but it rejects all connections attempts. Please keep updating this post if you find a solution.
-"""]]
diff --git a/posts/installing-debian-buster-on-gnubee2/comment_3_5d038744e65cf79c39b9fd03b937c812._comment b/posts/installing-debian-buster-on-gnubee2/comment_3_5d038744e65cf79c39b9fd03b937c812._comment
deleted file mode 100644
index 7d29cdc..0000000
--- a/posts/installing-debian-buster-on-gnubee2/comment_3_5d038744e65cf79c39b9fd03b937c812._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- ip="188.192.119.43"
- claimedauthor="Hein Osenberg"
- subject="Works for me"
- date="2019-09-02T19:21:34Z"
- content="""
-With Neil Browns new kernel (5.2.8 - see http://neil.brown.name/gnubee/), installed (see README) upgrading to Debian Buster worked perfectly for me. SSH access works out of the box without problems. 
-"""]]

Add the missing part to fix the GnuBee 2 (upgrading the firmware)
diff --git a/posts/installing-debian-buster-on-gnubee2.mdwn b/posts/installing-debian-buster-on-gnubee2.mdwn
index 5582f71..139a67f 100644
--- a/posts/installing-debian-buster-on-gnubee2.mdwn
+++ b/posts/installing-debian-buster-on-gnubee2.mdwn
@@ -108,7 +108,7 @@ and reboot:
 
     reboot
 
-# Restore ssh access in Debian jessie
+## Restore ssh access in Debian jessie
 
 Once the GnuBee has finished booting, login using the [serial console](https://github.com/gnubee-git/GnuBee_Docs/blob/master/USB_to_UART/README.md):
 
@@ -171,8 +171,6 @@ and upgrade the packages:
     apt autoremove
     reboot
 
-## Next steps
-
 At this point, my GnuBee is running the latest version of Debian stable,
 however there are two remaining issues to fix:
 
@@ -180,13 +178,53 @@ however there are two remaining issues to fix:
    work](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=932089) and I am
    forced to access the GnuBee via the serial interface.
 
-2. The firmware is running an outdated version of the Linux kernel though
-   this is [being worked
-   on](https://groups.google.com/d/topic/gnubee/YVM08lfWUUc/discussion) by
-   community members.
+2. The firmware is running an outdated version of the Linux kernel.
+
+Both of these issues can be resolved by upgrading the firmware to a recent
+version of Linux.
+
+## Upgrading the firmware
+
+In order to move to the firmware that [Neil Brown has been working on for a
+while](https://groups.google.com/d/topic/gnubee/YVM08lfWUUc/discussion), I
+prepared a USB stick:
+
+    $ sudo fdisk -l /dev/sdc
+    Disk /dev/sdc: 3.77 GiB, 4027580416 bytes, 7866368 sectors
+    Disk model: USB Disk
+    Units: sectors of 1 * 512 = 512 bytes
+    Sector size (logical/physical): 512 bytes / 512 bytes
+    I/O size (minimum/optimal): 512 bytes / 512 bytes
+    Disklabel type: dos
+    Disk identifier: 0x6cb65e6c
+    
+    Device     Boot Start     End Sectors  Size Id Type
+    /dev/sdc1        2048 7866367 7864320  3.8G  c W95 FAT32 (LBA)
+    
+    $ sudo mkfs.vfat /dev/sdc1
+
+using a `dos` partition table and a `W95 FAT32 (LBA)` partition.
+
+Then I grabbed the latest `gnubee-*-gbpc2.bin` file from
+<https://neil.brown.name/gnubee/> and copied it onto the USB stick with the
+appropriate name:
+
+    cp gnubee-5.4.14-gbpc2.bin /media/usbdisk/GNUBEE.BIN
+
+I plugged the stick into the GnuBee and rebooted it to upgrade the firmware,
+watching the process using the serial console.
+
+Once booted, I had to delete `/etc/udev/rules.d/70-persistent-net.rules` in
+order to fix a long timeout while bringing up the network interfaces during
+boot.
+
+If you want to see the boot messages to ensure there are no errors, run
+`journalctl -b`.
+
+Finally, I cleaned up a deprecated and no-longer-needed package:
+
+    apt purge ntpdate
 
-I hope to resolve these issues soon, and will update this blog post once I
-do, but you are more than welcome to leave a comment if you know of a
-solution I may have overlooked.
+and removed its invocation from `/etc/rc.local`.
 
-[[!tag debian]] [[!tag gnubee]] [[!tag nzoss]]
+[[!tag debian]] [[!tag gnubee]]

Move the limit forward since Planet Mozilla treats modification time as creation time
diff --git a/tags/mozilla.mdwn b/tags/mozilla.mdwn
index 7883bf0..ff95877 100644
--- a/tags/mozilla.mdwn
+++ b/tags/mozilla.mdwn
@@ -1,4 +1,4 @@
 [[!meta title="pages tagged mozilla"]]
 
 [[!inline pages="tagged(mozilla)" actions="no" archive="yes"
-feedshow=9 feedpages=created_after(posts/letting-someone-ssh-into-your-laptop-using-pagekite)]]
+feedshow=9 feedpages=created_after(posts/restricting-third-party-iframes-sandbox-referrer-feature-policy)]]

Remove aloodo resource since its HTTPS cert expired
diff --git a/local.css b/local.css
index 3f1933d..69f70db 100644
--- a/local.css
+++ b/local.css
@@ -225,17 +225,6 @@ body {
     background-color: transparent;
 }
 
-/* ALOODO
-     - stops it from putting extra empty space at bottom of page
-*/
-iframe[src='//ad.aloodo.com/track/'] {
-    position: absolute;
-    top: 0;
-    left: 0;
-    background-color: #fff;
-}
-
-
 /* ADAPT TO MOBILE */
 
 @media all and (max-width: 79em) {
diff --git a/sidebar.mdwn b/sidebar.mdwn
index 463ac41..d42b2e6 100644
--- a/sidebar.mdwn
+++ b/sidebar.mdwn
@@ -24,5 +24,3 @@
 
 [[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="https://ad.aloodo.com/ad.js" async></script>

Fix image path
diff --git a/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn b/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn
index 74e169b..6608027 100644
--- a/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn
+++ b/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn
@@ -35,7 +35,7 @@ that might interfere with this:
 - [Brave](https://brave.com/clo187): Disable Shields entirely for that page
   (Simple view) or *allow all cookies* for that page (Advanced view).
 
-![](/posts/how-to-get-direct-webrtc-connections-between-computers/brave-shields-cookies.png)
+![](/posts/how-to-get-direct-webrtc-connection-between-computers/brave-shields-cookies.png)
 
 - Firefox: Ensure that `http.network.referer.spoofSource` is set to `false`
   in `about:config`, which it is by default.
@@ -43,7 +43,7 @@ that might interfere with this:
 - [uMatrix](https://github.com/gorhill/uMatrix): The "Spoof `Referer`
   header" option needs to be turned off for that site.
 
-![](/posts/how-to-get-direct-webrtc-connections-between-computers/umatrix-settings.png)
+![](/posts/how-to-get-direct-webrtc-connection-between-computers/umatrix-settings.png)
 
 # Checking the type of peer connection you have
 
@@ -75,13 +75,13 @@ find the one which says:
 - `nominated: true`
 - `writable: true`
 
-![](/posts/how-to-get-direct-webrtc-connections-between-computers/chromium-webrtc-internals-candidatepair.png)
+![](/posts/how-to-get-direct-webrtc-connection-between-computers/chromium-webrtc-internals-candidatepair.png)
 
 Then from the name of that pair (`N6cxxnrr_OEpeash` in the above example)
 find the two matching `RTCIceCandidate` lines (one `local-candidate` and one
 `remote-candidate`) and expand them.
 
-![](/posts/how-to-get-direct-webrtc-connections-between-computers/chromium-webrtc-internals-candidates.png)
+![](/posts/how-to-get-direct-webrtc-connection-between-computers/chromium-webrtc-internals-candidates.png)
 
 In the case of a **direct connection**, I saw the following on the
 `remote-candidate`:
@@ -127,7 +127,7 @@ the [candidate
 type](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate/type)
 in brackets.
 
-![](/posts/how-to-get-direct-webrtc-connections-between-computers/firefox-about-webrtc.png)
+![](/posts/how-to-get-direct-webrtc-connection-between-computers/firefox-about-webrtc.png)
 
 # Firewall ports to open to avoid using a relay
 

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

Add WebRTC post
diff --git a/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn b/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn
new file mode 100644
index 0000000..74e169b
--- /dev/null
+++ b/posts/how-to-get-direct-webrtc-connection-between-computers.mdwn
@@ -0,0 +1,176 @@
+[[!meta title="How to get a direct WebRTC connections between two computers"]]
+[[!meta date="2020-03-28T16:55:00.000-07:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+[WebRTC](https://webrtc.org/) is a standard real-time communication protocol
+built directly into modern web browsers. It enables the creation of video
+conferencing services which do not require participants to download
+additional software. Many services make use of it and it almost always works
+out of the box.
+
+The reason it just works is that it uses a protocol called
+[ICE](https://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment)
+to establish a connection regardless of the network environment. What that
+means however is that in some cases, your video/audio connection will need
+to be relayed (using end-to-end encryption) to the other person via
+third-party
+[TURN](https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT)
+server. In addition to adding extra network latency to your call that relay
+server might overloaded at some point and drop or delay packets coming
+through.
+
+Here's how to tell whether or not your WebRTC calls are being relayed, and
+how to ensure you get a direct connection to the other host.
+
+# Testing basic WebRTC functionality
+
+Before you place a real call, I suggest using the official [test
+page](https://test.webrtc.org/) which will test your camera, microphone and
+network connectivity.
+
+Note that this test page makes use of a Google TURN server which is locked
+to particular HTTP referrers and so you'll need to disable privacy features
+that might interfere with this:
+
+- [Brave](https://brave.com/clo187): Disable Shields entirely for that page
+  (Simple view) or *allow all cookies* for that page (Advanced view).
+
+![](/posts/how-to-get-direct-webrtc-connections-between-computers/brave-shields-cookies.png)
+
+- Firefox: Ensure that `http.network.referer.spoofSource` is set to `false`
+  in `about:config`, which it is by default.
+
+- [uMatrix](https://github.com/gorhill/uMatrix): The "Spoof `Referer`
+  header" option needs to be turned off for that site.
+
+![](/posts/how-to-get-direct-webrtc-connections-between-computers/umatrix-settings.png)
+
+# Checking the type of peer connection you have
+
+Once you know that WebRTC is working in your browser, it's time to establish
+a connection and look at the network configuration that the two peers agreed
+on.
+
+My favorite service at the moment is [Whereby](https://whereby.com)
+(formerly *Appear.in*), so I'm going to use that to connect from two
+different computers:
+
+- `canada` is a laptop behind a regular home router without any port
+  forwarding.
+- `siberia` is a desktop computer in a remote location that is also behind a
+  home router, but in this case its internal IP address (`192.168.1.2`) is
+  set as the [DMZ
+  host](https://en.wikipedia.org/wiki/DMZ_%28computing%29#DMZ_host).
+
+## Chromium
+
+For all Chromium-based browsers, such as Brave, Chrome, Edge, Opera and
+Vivaldi, the debugging page you'll need to open is called
+`chrome://webrtc-internals`.
+
+Look for `RTCIceCandidatePair` lines and expand them one at a time until you
+find the one which says:
+
+- `state: succeeded` (or `state: in-progress`)
+- `nominated: true`
+- `writable: true`
+
+![](/posts/how-to-get-direct-webrtc-connections-between-computers/chromium-webrtc-internals-candidatepair.png)
+
+Then from the name of that pair (`N6cxxnrr_OEpeash` in the above example)
+find the two matching `RTCIceCandidate` lines (one `local-candidate` and one
+`remote-candidate`) and expand them.
+
+![](/posts/how-to-get-direct-webrtc-connections-between-computers/chromium-webrtc-internals-candidates.png)
+
+In the case of a **direct connection**, I saw the following on the
+`remote-candidate`:
+
+- `ip` shows the external IP address of `siberia`
+- `port` shows a random number between 1024 and 65535
+- `candidateType: srflx`
+
+and the following on `local-candidate`:
+
+- `ip` shows the external IP address of `canada`
+- `port` shows a random number between 1024 and 65535
+- `candidateType: prflx`
+
+These [candidate
+types](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate/type)
+indicate that a [STUN](https://en.wikipedia.org/wiki/STUN) server was used
+to determine the public-facing IP address and port for each computer, but
+the actual connection between the peers is direct.
+
+On the other hand, for a **relayed/proxied connection**, I saw the following
+on the `remote-candidate` side:
+
+- `ip` shows an IP address belonging to the TURN server
+- `candidateType: relay`
+
+and the same information as before on the `local-candidate`.
+
+## Firefox
+
+If you are using Firefox, the debugging page you want to look at is
+`about:webrtc`.
+
+Expand the top entry under "Session Statistics" and look for the line
+(should be the first one) which says the following in green:
+
+- `ICE State: succeeded`
+- `Nominated: true`
+- `Selected: true`
+
+then look in the "Local Candidate" and "Remote Candidate" sections to find
+the [candidate
+type](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate/type)
+in brackets.
+
+![](/posts/how-to-get-direct-webrtc-connections-between-computers/firefox-about-webrtc.png)
+
+# Firewall ports to open to avoid using a relay
+
+In order to get a direct connection to the other WebRTC peer, **one** of the
+two computers (in my case, `siberia`) needs to **open all inbound UDP
+ports** since there doesn't appear to be a way to restrict Chromium or
+Firefox to a smaller port range for incoming WebRTC connections.
+
+This isn't great and so I decided to tighten that up in two ways by:
+
+- restricting incoming UDP traffic to the IP range of `siberia`'s ISP, and
+- explicitly denying incoming to the UDP ports I know are open on `siberia`.
+
+To get the IP range, start with the external IP address of the machine (I'll
+use the IP address of my blog in this example: `66.228.46.55`) and pass it
+to the `whois` command:
+
+    $ whois 66.228.46.55 | grep CIDR
+    CIDR:           66.228.32.0/19
+
+To get the list of open UDP ports on `siberia`, I `ssh`ed into it and ran
+nmap:
+
+    $ sudo nmap -sU localhost
+    
+    Starting Nmap 7.60 ( https://nmap.org ) at 2020-03-28 15:55 PDT
+    Nmap scan report for localhost (127.0.0.1)
+    Host is up (0.000015s latency).
+    Not shown: 994 closed ports
+    PORT      STATE         SERVICE
+    631/udp   open|filtered ipp
+    5060/udp  open|filtered sip
+    5353/udp  open          zeroconf
+    
+    Nmap done: 1 IP address (1 host up) scanned in 190.25 seconds
+
+I ended up with the following in my `/etc/network/iptables.up.rules` (ports
+below 1024 are denied by the default rule and don't need to be included
+here):
+
+    # Deny all known-open high UDP ports before enabling WebRTC for canada
+    -A INPUT -p udp --dport 5060 -j DROP
+    -A INPUT -p udp --dport 5353 -j DROP
+    -A INPUT -s 66.228.32.0/19 -p udp --dport 1024:65535 -j ACCEPT
+
+[[!tag brave]] [[!tag firefox]] [[!tag webrtc]] [[!tag mozilla]] [[!tag debian]] [[!tag videoconf]]
diff --git a/posts/how-to-get-direct-webrtc-connection-between-computers/brave-shields-cookies.png b/posts/how-to-get-direct-webrtc-connection-between-computers/brave-shields-cookies.png
new file mode 100644
index 0000000..ac3de50
Binary files /dev/null and b/posts/how-to-get-direct-webrtc-connection-between-computers/brave-shields-cookies.png differ
diff --git a/posts/how-to-get-direct-webrtc-connection-between-computers/chromium-webrtc-internals-candidatepair.png b/posts/how-to-get-direct-webrtc-connection-between-computers/chromium-webrtc-internals-candidatepair.png
new file mode 100644
index 0000000..d14b1f4
Binary files /dev/null and b/posts/how-to-get-direct-webrtc-connection-between-computers/chromium-webrtc-internals-candidatepair.png differ
diff --git a/posts/how-to-get-direct-webrtc-connection-between-computers/chromium-webrtc-internals-candidates.png b/posts/how-to-get-direct-webrtc-connection-between-computers/chromium-webrtc-internals-candidates.png
new file mode 100644
index 0000000..6f3cdbe
Binary files /dev/null and b/posts/how-to-get-direct-webrtc-connection-between-computers/chromium-webrtc-internals-candidates.png differ
diff --git a/posts/how-to-get-direct-webrtc-connection-between-computers/firefox-about-webrtc.png b/posts/how-to-get-direct-webrtc-connection-between-computers/firefox-about-webrtc.png
new file mode 100644
index 0000000..38d3968
Binary files /dev/null and b/posts/how-to-get-direct-webrtc-connection-between-computers/firefox-about-webrtc.png differ
diff --git a/posts/how-to-get-direct-webrtc-connection-between-computers/umatrix-settings.png b/posts/how-to-get-direct-webrtc-connection-between-computers/umatrix-settings.png
new file mode 100644

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

Create a new videoconf tag
diff --git a/posts/installing-vidyo-on-ubuntu-1804.mdwn b/posts/installing-vidyo-on-ubuntu-1804.mdwn
index 3121a0f..78562bc 100644
--- a/posts/installing-vidyo-on-ubuntu-1804.mdwn
+++ b/posts/installing-vidyo-on-ubuntu-1804.mdwn
@@ -57,4 +57,4 @@ version:
 Finally, launch `VidyoDesktop` and go into the settings to check "Always use
 VidyoProxy".
 
-[[!tag mozilla]] [[!tag vidyo]]
+[[!tag mozilla]] [[!tag vidyo]] [[!tag videoconf]]
diff --git a/posts/peer-to-peer-video-conferencing-using.mdwn b/posts/peer-to-peer-video-conferencing-using.mdwn
index ba0bb85..c14fbfd 100644
--- a/posts/peer-to-peer-video-conferencing-using.mdwn
+++ b/posts/peer-to-peer-video-conferencing-using.mdwn
@@ -63,4 +63,4 @@ Another thing I thought of trying was to switch from [TCP](https://secure.wikime
 Please feel free leave a comment if you can suggest ways of improving my quick 'n dirty solution.
 
 
-[[!tag catalyst]] [[!tag gstreamer]] [[!tag debian]] [[!tag sysadmin]] [[!tag ubuntu]] [[!tag nzoss]] 
+[[!tag catalyst]] [[!tag gstreamer]] [[!tag debian]] [[!tag sysadmin]] [[!tag ubuntu]] [[!tag nzoss]] [[!tag videoconf]]

Comment moderation
diff --git a/posts/fixing-mariadb-innodb-errors-mythtv30/comment_1_bfed4f724f41d877156a4bfd354b6b8a._comment b/posts/fixing-mariadb-innodb-errors-mythtv30/comment_1_bfed4f724f41d877156a4bfd354b6b8a._comment
new file mode 100644
index 0000000..b8e497c
--- /dev/null
+++ b/posts/fixing-mariadb-innodb-errors-mythtv30/comment_1_bfed4f724f41d877156a4bfd354b6b8a._comment
@@ -0,0 +1,19 @@
+[[!comment format=mdwn
+ ip="84.250.233.2"
+ claimedauthor="Marko Mäkelä"
+ url="https://mariadb.com"
+ subject="Some history of the InnoDB ROW_FORMAT"
+ date="2020-03-09T07:49:59Z"
+ content="""
+I implemented the `ROW_FORMAT=DYNAMIC` back in 2004 or 2005 in the InnoDB Plugin for MySQL 5.1, which was available separately from the built-in InnoDB. Later, it became the InnoDB in MySQL 5.5.
+
+The only difference between `ROW_FORMAT=DYNAMIC` and the previous default `ROW_FORMAT=COMPACT` (which I introduced in MySQL 5.0.3) is the storage of long string columns (such as `VARCHAR`, `BLOB`, or `TEXT`). Originally, Heikki Tuuri decided to always store the 768 first bytes of each column inline in the page, so that it would be easier to implement column prefix indexes in secondary indexes. Unsurprisingly, users started to complain, because the unnecessary inline storage would happen unconditionally, whether or not the column is indexed.
+
+For `ROW_FORMAT=DYNAMIC`, I improved InnoDB in such a way that there is no need to store a local prefix. Instead, column prefixes will be stored in undo log records if needed. (An attempt to update many prefix-indexed columns in one statement may fail if the undo log record would not fit in one page.)
+
+In MySQL 5.5, the maximum column prefix index length was increased from 767 (the 768th byte was always 'wasted') to 3072 bytes.
+
+Due to someone's strange idea regarding compatibility, one had to override two configuration parameters to enable the sane behaviour. Originally, the idea was that one could try out the InnoDB Plugin in MySQL 5.1 and be able to return to the built-in InnoDB. I finally changed the parameters `innodb_file_format`, `innodb_large_prefix` to have sane defaults in MySQL 5.7 and removed them in MySQL 8.0. Likewise, In MySQL 5.7 introduced the parameter `innodb_default_row_format=dynamic`, so that it is not necessary to specify a `ROW_FORMAT` when creating tables.
+
+These settings are also present in MariaDB Server starting with version 10.2, which is the first major version released after I joined the company.
+"""]]

Add MythTV InnoDB blog post
diff --git a/posts/fixing-mariadb-innodb-errors-mythtv30.mdwn b/posts/fixing-mariadb-innodb-errors-mythtv30.mdwn
new file mode 100644
index 0000000..303ce46
--- /dev/null
+++ b/posts/fixing-mariadb-innodb-errors-mythtv30.mdwn
@@ -0,0 +1,135 @@
+[[!meta title="Fixing MariaDB InnoDB errors after upgrading to MythTV 30"]]
+[[!meta date="2020-03-07T10:00:00.000-08:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+After upgrading to [MythTV
+30](https://www.mythtv.org/wiki/Release_Notes_-_30) and MariaDB 10.3.18 on
+[Debian buster](https://www.debian.org/releases/buster/), I noticed the
+following errors in my logs:
+
+    Jan 14 02:00:05 hostname mysqld[846]: 2020-01-14  2:00:05 62 [Warning] InnoDB: Cannot add field `rating` in table `mythconverg`.`internetcontentarticles` because after adding it, the row size is 8617 which is greater than maximum allowed size (8126) for a record on index leaf page.
+    Jan 14 02:00:05 hostname mysqld[846]: 2020-01-14  2:00:05 62 [Warning] InnoDB: Cannot add field `playcommand` in table `mythconverg`.`videometadata` because after adding it, the row size is 8243 which is greater than maximum allowed size (8126) for a record on index leaf page.
+
+The root cause is that the database is using an [InnoDB row
+format](https://mariadb.com/kb/en/troubleshooting-row-size-too-large-errors-with-innodb/)
+that cannot handle the new table sizes.
+
+To fix it, I put the following in `alter_tables.sql`:
+
+    ALTER TABLE archiveitems ROW_FORMAT=DYNAMIC;
+    ALTER TABLE bdbookmark ROW_FORMAT=DYNAMIC;
+    ALTER TABLE callsignnetworkmap ROW_FORMAT=DYNAMIC;
+    ALTER TABLE capturecard ROW_FORMAT=DYNAMIC;
+    ALTER TABLE cardinput ROW_FORMAT=DYNAMIC;
+    ALTER TABLE channel ROW_FORMAT=DYNAMIC;
+    ALTER TABLE channelgroup ROW_FORMAT=DYNAMIC;
+    ALTER TABLE channelgroupnames ROW_FORMAT=DYNAMIC;
+    ALTER TABLE channelscan ROW_FORMAT=DYNAMIC;
+    ALTER TABLE channelscan_channel ROW_FORMAT=DYNAMIC;
+    ALTER TABLE channelscan_dtv_multiplex ROW_FORMAT=DYNAMIC;
+    ALTER TABLE codecparams ROW_FORMAT=DYNAMIC;
+    ALTER TABLE credits ROW_FORMAT=DYNAMIC;
+    ALTER TABLE customexample ROW_FORMAT=DYNAMIC;
+    ALTER TABLE diseqc_config ROW_FORMAT=DYNAMIC;
+    ALTER TABLE diseqc_tree ROW_FORMAT=DYNAMIC;
+    ALTER TABLE displayprofilegroups ROW_FORMAT=DYNAMIC;
+    ALTER TABLE displayprofiles ROW_FORMAT=DYNAMIC;
+    ALTER TABLE dtv_multiplex ROW_FORMAT=DYNAMIC;
+    ALTER TABLE dtv_privatetypes ROW_FORMAT=DYNAMIC;
+    ALTER TABLE dvdbookmark ROW_FORMAT=DYNAMIC;
+    ALTER TABLE dvdinput ROW_FORMAT=DYNAMIC;
+    ALTER TABLE dvdtranscode ROW_FORMAT=DYNAMIC;
+    ALTER TABLE eit_cache ROW_FORMAT=DYNAMIC;
+    ALTER TABLE filemarkup ROW_FORMAT=DYNAMIC;
+    ALTER TABLE gallery_directories ROW_FORMAT=DYNAMIC;
+    ALTER TABLE gallery_files ROW_FORMAT=DYNAMIC;
+    ALTER TABLE gallerymetadata ROW_FORMAT=DYNAMIC;
+    ALTER TABLE housekeeping ROW_FORMAT=DYNAMIC;
+    ALTER TABLE inputgroup ROW_FORMAT=DYNAMIC;
+    ALTER TABLE internetcontent ROW_FORMAT=DYNAMIC;
+    ALTER TABLE internetcontentarticles ROW_FORMAT=DYNAMIC;
+    ALTER TABLE inuseprograms ROW_FORMAT=DYNAMIC;
+    ALTER TABLE iptv_channel ROW_FORMAT=DYNAMIC;
+    ALTER TABLE jobqueue ROW_FORMAT=DYNAMIC;
+    ALTER TABLE jumppoints ROW_FORMAT=DYNAMIC;
+    ALTER TABLE keybindings ROW_FORMAT=DYNAMIC;
+    ALTER TABLE keyword ROW_FORMAT=DYNAMIC;
+    ALTER TABLE livestream ROW_FORMAT=DYNAMIC;
+    ALTER TABLE logging ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_albumart ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_albums ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_artists ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_directories ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_genres ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_playlists ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_radios ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_smartplaylist_categories ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_smartplaylist_items ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_smartplaylists ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_songs ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_stats ROW_FORMAT=DYNAMIC;
+    ALTER TABLE music_streams ROW_FORMAT=DYNAMIC;
+    ALTER TABLE mythlog ROW_FORMAT=DYNAMIC;
+    ALTER TABLE mythweb_sessions ROW_FORMAT=DYNAMIC;
+    ALTER TABLE networkiconmap ROW_FORMAT=DYNAMIC;
+    ALTER TABLE oldfind ROW_FORMAT=DYNAMIC;
+    ALTER TABLE oldprogram ROW_FORMAT=DYNAMIC;
+    ALTER TABLE oldrecorded ROW_FORMAT=DYNAMIC;
+    ALTER TABLE people ROW_FORMAT=DYNAMIC;
+    ALTER TABLE phonecallhistory ROW_FORMAT=DYNAMIC;
+    ALTER TABLE phonedirectory ROW_FORMAT=DYNAMIC;
+    ALTER TABLE pidcache ROW_FORMAT=DYNAMIC;
+    ALTER TABLE playgroup ROW_FORMAT=DYNAMIC;
+    ALTER TABLE powerpriority ROW_FORMAT=DYNAMIC;
+    ALTER TABLE profilegroups ROW_FORMAT=DYNAMIC;
+    ALTER TABLE program ROW_FORMAT=DYNAMIC;
+    ALTER TABLE programgenres ROW_FORMAT=DYNAMIC;
+    ALTER TABLE programrating ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recgrouppassword ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recgroups ROW_FORMAT=DYNAMIC;
+    ALTER TABLE record ROW_FORMAT=DYNAMIC;
+    ALTER TABLE record_tmp ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recorded ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recordedartwork ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recordedcredits ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recordedfile ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recordedmarkup ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recordedprogram ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recordedrating ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recordedseek ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recordfilter ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recordingprofiles ROW_FORMAT=DYNAMIC;
+    ALTER TABLE recordmatch ROW_FORMAT=DYNAMIC;
+    ALTER TABLE scannerfile ROW_FORMAT=DYNAMIC;
+    ALTER TABLE scannerpath ROW_FORMAT=DYNAMIC;
+    ALTER TABLE schemalock ROW_FORMAT=DYNAMIC;
+    ALTER TABLE settings ROW_FORMAT=DYNAMIC;
+    ALTER TABLE storagegroup ROW_FORMAT=DYNAMIC;
+    ALTER TABLE tvchain ROW_FORMAT=DYNAMIC;
+    ALTER TABLE tvosdmenu ROW_FORMAT=DYNAMIC;
+    ALTER TABLE upnpmedia ROW_FORMAT=DYNAMIC;
+    ALTER TABLE user_permissions ROW_FORMAT=DYNAMIC;
+    ALTER TABLE user_sessions ROW_FORMAT=DYNAMIC;
+    ALTER TABLE users ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videocast ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videocategory ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videocollection ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videocountry ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videogenre ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videometadata ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videometadatacast ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videometadatacountry ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videometadatagenre ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videopart ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videopathinfo ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videosource ROW_FORMAT=DYNAMIC;
+    ALTER TABLE videotypes ROW_FORMAT=DYNAMIC;
+    ALTER TABLE weatherdatalayout ROW_FORMAT=DYNAMIC;
+    ALTER TABLE weatherscreens ROW_FORMAT=DYNAMIC;
+    ALTER TABLE weathersourcesettings ROW_FORMAT=DYNAMIC;
+
+and then ran it like this:
+
+    mysql -umythtv -pPassword1 mythconverg < alter_tables.sql
+
+[[!tag mythtv]] [[!tag debian]]

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

Add a post about SIP URIs with VoIP.ms
diff --git a/posts/making-sip-calls-voipms-without-pstn.mdwn b/posts/making-sip-calls-voipms-without-pstn.mdwn
new file mode 100644
index 0000000..ee96aee
--- /dev/null
+++ b/posts/making-sip-calls-voipms-without-pstn.mdwn
@@ -0,0 +1,16 @@
+[[!meta title="Making SIP calls to VoIP.ms subscribers without using the PSTN"]]
+[[!meta date="2020-03-05T19:00:00.000-08:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+If you want to reach a [VoIP.ms](https://voip.ms/) subscriber from
+[Asterisk](https://www.asterisk.org/) without using the
+[PSTN](https://en.wikipedia.org/wiki/Public_switched_telephone_network),
+there is a way to do so via [SIP
+URIs](https://wiki.voip.ms/article/SIP_URI).
+
+Here's what I added to my `/etc/asterisk/extensions.conf`:
+
+    exten => 1234,1,Set(CALLERID(all)=Francois Marier <5555551234>)
+    exten => 1234,n,Dial(SIP/sip.voip.ms/5555556789)
+
+[[!tag asterisk]] [[!tag voipms]]
diff --git a/posts/sip-encryption-on-voip-ms.mdwn b/posts/sip-encryption-on-voip-ms.mdwn
index 2cb3209..0d99118 100644
--- a/posts/sip-encryption-on-voip-ms.mdwn
+++ b/posts/sip-encryption-on-voip-ms.mdwn
@@ -70,4 +70,4 @@ Since my Asterisk server is only acting as a TLS *client*, and not a TLS
 it looks pretty easy to [use a Let's Encrypt cert with
 Asterisk](https://community.asterisk.org/t/has-anyone-used-letsencrypt-to-setup-ssl-for-asterisk/67145/6).
 
-[[!tag debian]] [[!tag asterisk]] [[!tag nzoss]] [[!tag letsencrypt]]
+[[!tag debian]] [[!tag asterisk]] [[!tag nzoss]] [[!tag letsencrypt]] [[!tag voipms]]

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

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

Add Pi-Star 4.1 upgrade post
diff --git a/posts/upgrade-dmr-hotspot-pistar-4_1.mdwn b/posts/upgrade-dmr-hotspot-pistar-4_1.mdwn
new file mode 100644
index 0000000..4cd908f
--- /dev/null
+++ b/posts/upgrade-dmr-hotspot-pistar-4_1.mdwn
@@ -0,0 +1,99 @@
+[[!meta title="Upgrading a DMR hotspot to Pi-Star 4.1 RC-7"]]
+[[!meta date="2020-03-01T10:30:00.000-08:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+While the [Pi-Star](http://www.pistar.uk/) DMR gateway has automatic
+updates, the latest release (3.4.17) is still based on an old version of
+Debian ([Debian 8 jessie](https://www.debian.org/releases/jessie/)) which is
+no longer supported. It is however relatively easy to update to the latest
+release candidate of Pi-Star 4.1 (based on [Debian 10
+buster](https://www.debian.org/releases/buster/)), as long as you have a
+spare SD card (4 GB minimum).
+
+# Download the required files and copy to an SD card
+
+First of all, download the [latest RC image](https://www.pistar.uk/beta/)
+and your [local configuration](http://pi-star.local/admin/configure.php)
+(remember the default account name is `pi-star`). I like to also print a
+copy of that settings page since it's much easier to refer to if things go
+wrong.
+
+Then unzip the image and ["burn"
+it](https://askubuntu.com/questions/179437/how-can-i-burn-a-raspberry-pi-image-to-sd-card-from-ubuntu)
+to a new SD card (no need to format it ahead of time):
+
+    sudo dd if=Pi-Star_RPi_V4.1.0-RC7_20-Dec-2019.img of=/dev/sdX status=progress bs=4M
+    sync
+
+where `/dev/sdX` is the device name for the SD card, which you can find in
+the `dmesg` output. **Don't skip the `sync` command** or you may eject the
+card before your computer is done writing to it.
+
+Then unmount the SD card and unplug it from your computer. Plug it back in.
+You should see two drives mounted automatically on your desktop:
+
+- `pistar`
+- `boot`
+
+Copy the configuration zip file you downloaded earlier onto the root of the
+`boot` drive and then eject the drive.
+
+Run `sync` again before actually unplugging the card.
+
+# Boot into the new version
+
+In order to boot into the new version, start by turning off the Pi. Then
+remove the old SD card and insert the new one that you just prepared. That
+new card will become the new OS drive.
+
+Boot the Pi and ideally connect a monitor to the HDMI port so that you can 
+see it boot up and reboot twice before dropping you to a login prompt.
+
+Login using the default credentials:
+
+- Username: `pi-star`
+- Password: `raspberry`
+
+Once logged in use `top` to see if the pi is busy doing anything. Mine was
+in the process of upgrading Debian packages via `unattended-upgrades` which
+made everything (including the web UI) very slow.
+
+You should now be able to access the [web UI](http://pi-star.local/) using
+the above credentials.
+
+# Update to the latest version
+
+From the command line, you can ensure that you are running the latest
+version of Pi-Star by running the following command:
+
+    sudo pistar-upgrade
+
+This updated from `4.1.0-RC7` to `4.1.0-RC8` on my device.
+
+You can also run the following:
+
+    sudo pistar-update
+
+to update the underlying Raspbian OS.
+
+# Check and restore your settings
+
+Once things have settled down, double-check the
+[settings](http://pi-star.local/admin/configure.php) and restore your admin
+password since that was not part of the configuration backup you made earlier.
+
+I had to restore the following settings since they got lost in the process:
+
+- `Auto AP`: `Off`
+- `uPNP`: `Off`
+
+# Roll back to the previous version
+
+If you run into problems, the best option is to roll back to the previous
+version and then try again.
+
+As long as you didn't reuse the original SD card for this upgrade, rolling
+back to version 3.4.17 simply involves shutting down the pi and then
+swapping the new SD card for the old one and then starting it up again.
+
+[[!tag dmr]] [[!tag ham]] [[!tag pistar]]

Comment moderation
diff --git a/posts/encrypting-your-home-directory-using/comment_13_466daae3810506ee699b1b4c421d866a._comment b/posts/encrypting-your-home-directory-using/comment_13_466daae3810506ee699b1b4c421d866a._comment
new file mode 100644
index 0000000..166122b
--- /dev/null
+++ b/posts/encrypting-your-home-directory-using/comment_13_466daae3810506ee699b1b4c421d866a._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ ip="98.169.32.134"
+ claimedauthor="jamesob"
+ url="jameso.be"
+ subject="Unmounting /home"
+ date="2020-02-17T19:58:45Z"
+ content="""
+If you get errors during `umount /home`, you may need to end your graphical shell and login as root before mounting /home. On Debian, e.g., you can do this by pressing CTRL+ALT+F{1,2,3,4} at a graphical login prompt before logging in as a regular user, and then logging in as `root` from there. This way, `lsof /home` should return nothing and you should be able to unmount /home without error.
+"""]]

Add post about Fedora 31 LXC containers
diff --git a/posts/fedora31-lxc-setup-on-ubuntu-bionic.mdwn b/posts/fedora31-lxc-setup-on-ubuntu-bionic.mdwn
new file mode 100644
index 0000000..edda488
--- /dev/null
+++ b/posts/fedora31-lxc-setup-on-ubuntu-bionic.mdwn
@@ -0,0 +1,123 @@
+[[!meta title="Fedora 31 LXC setup on Ubuntu Bionic 18.04"]]
+[[!meta date="2020-02-09T21:30:00.000-08:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+Similarly to what I wrote for [Fedora 29](https://feeding.cloud.geek.nz/posts/fedora29-lxc-setup-on-ubuntu-bionic/),
+here is how I was able to create a [Fedora](https://getfedora.org/) 31 LXC
+container on an Ubuntu 18.04 (bionic) laptop.
+
+# Setting up LXC on Ubuntu
+
+First of all, install lxc:
+
+    apt install lxc
+    echo "veth" >> /etc/modules
+    modprobe veth
+
+turn on bridged networking by putting the following in
+`/etc/sysctl.d/local.conf`:
+
+    net.ipv4.ip_forward=1
+
+and applying it using:
+
+    sysctl -p /etc/sysctl.d/local.conf
+
+Then allow the right traffic in your firewall
+(`/etc/network/iptables.up.rules` in my case):
+
+    # LXC containers
+    -A FORWARD -d 10.0.3.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+    -A FORWARD -s 10.0.3.0/24 -j ACCEPT
+    -A INPUT -d 224.0.0.251 -s 10.0.3.1 -j ACCEPT
+    -A INPUT -d 239.255.255.250 -s 10.0.3.1 -j ACCEPT
+    -A INPUT -d 10.0.3.255 -s 10.0.3.1 -j ACCEPT
+    -A INPUT -d 10.0.3.1 -s 10.0.3.0/24 -j ACCEPT
+
+and apply these changes:
+
+    iptables-apply
+
+before restarting the lxc networking:
+
+    systemctl restart lxc-net.service
+
+# Create the container
+
+Once that's in place, you can finally create the Fedora 29 container:
+
+    lxc-create -n fedora31 -t download -- -d fedora -r 31 -a amd64
+
+To see a list of all distros available with the `download` template:
+
+    lxc-create -n foo --template=download -- --list
+
+Once the container has been created, disable AppArmor for it:
+
+    lxc.apparmor.profile = unconfined
+
+since the AppArmor profile [isn't working at the moment](https://github.com/lxc/lxc/issues/2778).
+
+# Logging in as root
+
+Starting the container in one window:
+
+    lxc-start -n fedora31 -F
+
+and attaching to a console:
+
+    lxc-attach -n fedora31
+
+to set a root password:
+
+    passwd
+
+# Logging in as an unprivileged user via ssh
+
+While logged into the console, I tried to install ssh:
+
+    $ dnf install openssh-server
+    Cannot create temporary file - mkstemp: No such file or directory
+
+but it failed because `TMPDIR` is set to a non-existent directory:
+
+    $ echo $TMPDIR
+    /tmp/user/0
+
+I found [a fix](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=728500)
+and ran the following:
+
+    TMPDIR=/tmp dnf install openssh-server
+
+then started the ssh service:
+
+  systemctl start sshd.service
+
+Then I installed a few other packages as root:
+
+    dnf install vim sudo man
+
+and created an unprivileged user with sudo access:
+
+    adduser francois -G wheel
+    passwd francois
+
+I set this in `/etc/ssh/sshd_config`:
+
+    GSSAPIAuthentication no
+
+to prevent [slow ssh logins](https://serverfault.com/questions/815538/long-delay-when-logging-in-with-centos7).
+
+Now login as that user from the console and add an ssh public key:
+
+    mkdir .ssh
+    chmod 700 .ssh
+    echo "<your public key>" > .ssh/authorized_keys
+    chmod 644 .ssh/authorized_keys
+
+You can now login via ssh. The IP address to use can be seen in the output
+of:
+
+    lxc-ls --fancy
+
+[[!tag debian]] [[!tag lxc]] [[!tag nzoss]] [[!tag ubuntu]]

Add Talkwalker
diff --git a/posts/keeping-track-of-what-others-are-saying.mdwn b/posts/keeping-track-of-what-others-are-saying.mdwn
index 8ebf1e4..95ae80c 100644
--- a/posts/keeping-track-of-what-others-are-saying.mdwn
+++ b/posts/keeping-track-of-what-others-are-saying.mdwn
@@ -17,7 +17,16 @@ I have also signed up for the following [Google Alert](http://www.google.com/ale
 
 which emails me anytime someone links to my project's homepage in one of the resources indexed by Google.  
   
+## Talkwalker
 
+In addition to Google Alerts, I also subscribe to the [Talkwalker Alerts](https://www.talkwalker.com/alerts)
+service with the following alert:
+
+- Search query: `safe-rm`
+- Result type: (leave blank for *Everything*)
+- Language: `All languages`
+- How often: `As it happens`
+- How many: `All results`
 
 Anything else I should subscribe to or follow?
 

Convert table to simple list
diff --git a/posts/keeping-track-of-what-others-are-saying.mdwn b/posts/keeping-track-of-what-others-are-saying.mdwn
index 7e367f0..8ebf1e4 100644
--- a/posts/keeping-track-of-what-others-are-saying.mdwn
+++ b/posts/keeping-track-of-what-others-are-saying.mdwn
@@ -10,15 +10,10 @@ Here are a few ways to find out what people are saying online about your project
 
 I have also signed up for the following [Google Alert](http://www.google.com/alerts):
 
-> <table>
-> <tr><td>Search terms:</td><td>`link:safe-rm.org.nz`</td>
-> </tr>
-> <tr><td>Type:</td><td>`Comprehensive`</td>
-> </tr>
-> <tr><td>Deliver to:</td><td>`Email`</td>
-> </tr>
-> <tr><td>How often:</td><td>`as-it-happens`</td>
-> </tr></table>
+- Search terms: `link:safe-rm.org.nz`
+- Type: `Comprehensive`
+- Deliver to: `Email`
+- How often: `as-it-happens`
 
 which emails me anytime someone links to my project's homepage in one of the resources indexed by Google.  
   

Remove defunct services
diff --git a/posts/keeping-track-of-what-others-are-saying.mdwn b/posts/keeping-track-of-what-others-are-saying.mdwn
index 6c41253..7e367f0 100644
--- a/posts/keeping-track-of-what-others-are-saying.mdwn
+++ b/posts/keeping-track-of-what-others-are-saying.mdwn
@@ -6,20 +6,6 @@ There are a few ways to easily keep track of what others are saying about your F
 Here are a few ways to find out what people are saying online about your project.  
   
 
-## RSS Feeds
-
-First of all, here are the RSS feeds I subscribe to for one of my projects ([safe-rm](https://launchpad.net/safe-rm)):
-
-  * [Technorati](http://feeds.technorati.com/search/safe-rm.org.nz) (blog posts)
-  * [Twitter tweets](http://search.twitter.com/search.atom?q=safe-rm.org.nz) (tweets)
-  * [Identica](http://identi.ca/search/notice/rss?q=safe-rm.org.nz) (notices)
-  * [TweetMeme](http://rss.tweetmeme.com/domain/?host=http://safe-rm.org.nz) (tweets)
-  * [BackTweets](http://backtweets.com/search.rss?q=safe-rm.org.nz) (tweets)
-  * [Freshmeat](http://freshmeat.net/projects/safe-rm/comments.atom) (comments)
-  * [Ohloh](http://www.ohloh.net/p/safe-rm/messages.rss) (journal entries)
-
-  
-
 ## Google Alerts
 
 I have also signed up for the following [Google Alert](http://www.google.com/alerts):
@@ -37,15 +23,7 @@ I have also signed up for the following [Google Alert](http://www.google.com/ale
 which emails me anytime someone links to my project's homepage in one of the resources indexed by Google.  
   
 
-## Backtype Alerts
 
-Finally, these [Backtype Alerts](http://www.backtype.com/alerts) notify me anytime safe-rm features in a blog comment:
-
-  * `safe-rm`
-  * `safe-rm.org.nz`
-
-  
-  
 Anything else I should subscribe to or follow?
 
 

Add note about slow SSH logins
diff --git a/posts/fedora29-lxc-setup-on-ubuntu-bionic.mdwn b/posts/fedora29-lxc-setup-on-ubuntu-bionic.mdwn
index 7b87943..be3c649 100644
--- a/posts/fedora29-lxc-setup-on-ubuntu-bionic.mdwn
+++ b/posts/fedora29-lxc-setup-on-ubuntu-bionic.mdwn
@@ -76,6 +76,12 @@ and then create an unprivileged user with sudo access:
     adduser francois -G wheel
     passwd francois
 
+I set this in `/etc/ssh/sshd_config`:
+
+    GSSAPIAuthentication no
+
+to prevent [slow ssh logins](https://serverfault.com/questions/815538/long-delay-when-logging-in-with-centos7).
+
 Now login as that user from the console and add an ssh public key:
 
     mkdir .ssh

Comment moderation
diff --git a/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox/comment_5_231d5e5a78c9e67489605b40eb2b36f5._comment b/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox/comment_5_231d5e5a78c9e67489605b40eb2b36f5._comment
new file mode 100644
index 0000000..f758f2c
--- /dev/null
+++ b/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox/comment_5_231d5e5a78c9e67489605b40eb2b36f5._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="francois@665656f0ba400877c9b12e8fbb086e45aa01f7c0"
+ nickname="francois"
+ subject="Re: WINE"
+ date="2020-02-05T19:42:16Z"
+ content="""
+> Have you tried running the programming software in WINE?
+
+I have not. If you do end up trying it, I'd be curious to hear about it.
+"""]]

Comment moderation
diff --git a/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox/comment_4_3f0de17a6d3f39419d9572e50e7d8c27._comment b/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox/comment_4_3f0de17a6d3f39419d9572e50e7d8c27._comment
new file mode 100644
index 0000000..f7057cb
--- /dev/null
+++ b/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox/comment_4_3f0de17a6d3f39419d9572e50e7d8c27._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ ip="187.190.248.208"
+ claimedauthor="Mark"
+ subject="WINE"
+ date="2020-02-05T18:55:30Z"
+ content="""
+Have you tried running the programming software in WINE? Just curious since that would eliminate the VBox setup and using Windows. 
+"""]]
diff --git a/posts/recovering-from-unbootable-ubuntu-encrypted-lvm-root-partition/comment_7_6d782ed81d9fbdfbcc70fdf6da15fbed._comment b/posts/recovering-from-unbootable-ubuntu-encrypted-lvm-root-partition/comment_7_6d782ed81d9fbdfbcc70fdf6da15fbed._comment
new file mode 100644
index 0000000..2b8ef36
--- /dev/null
+++ b/posts/recovering-from-unbootable-ubuntu-encrypted-lvm-root-partition/comment_7_6d782ed81d9fbdfbcc70fdf6da15fbed._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ ip="70.125.19.73"
+ claimedauthor="Gus"
+ subject="Boot to earlier kernel worked better"
+ date="2020-02-05T02:19:59Z"
+ content="""
+As William (William — 13:54, 06 May 2018) did, I booted to the preceding kernel version, and as I logged in, I saw LivePatch flash by saying it had just updated something. I used apt to update everything and restarted, my machine is now runnign like a Swiss watch!
+"""]]

Comment moderation
diff --git a/posts/setting-up-raid-on-existing/comment_18_f58080e8a92469474b205e9b40eb4374._comment b/posts/setting-up-raid-on-existing/comment_18_f58080e8a92469474b205e9b40eb4374._comment
new file mode 100644
index 0000000..8351d96
--- /dev/null
+++ b/posts/setting-up-raid-on-existing/comment_18_f58080e8a92469474b205e9b40eb4374._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ ip="198.52.147.213"
+ claimedauthor="Dennis Chang"
+ subject="Ubuntu 18.04.3 LTS update"
+ date="2020-01-19T17:27:30Z"
+ content="""
+Hi,
+
+Thanks for the article! I followed it and it was my primary reference. However, I did encounter two issues while following it that I thought I should leave with you here. I'm using Ubuntu 18.04.3 and fdisk does not have 'fd' to convert a Linux partition to a Linux RAID partition. It is now '29' for a Linux RAID partition. Also, after adding the original disk to the RAID array and rebooting I found myself in grub rescue mode. After researching more I discovered that I was required to install a module 'mdraid1x' in order for grub to be able to read the RAID array and find the kernel in order to boot. Therefore, I had to boot a Live USB Ubuntu system to access the RAID array before chroot and grub-install --modules='mdraid1x' /dev/sda (to both drives). And finally, when I test each drive separately to see if it will boot (it does).
+
+Anyway, thanks for the article.
+"""]]

Update article for buster
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index c04e271..5f27fc7 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -207,12 +207,7 @@ and these to `/etc/rkhunter.conf.local`:
 
     apt install apparmor apparmor-profiles apparmor-profiles-extra libpam-tmpdir
 
-While the harden packages are configuration-free, AppArmor must be [manually enabled](https://wiki.debian.org/AppArmor/HowToUse#Enable_AppArmor):
-
-    perl -pi -e 's,GRUB_CMDLINE_LINUX="(.*)"$,GRUB_CMDLINE_LINUX="$1 apparmor=1 security=apparmor",' /etc/default/grub
-    update-grub
-
-In addition, certain kernel security features can be enabled by putting the
+Certain kernel security features can be enabled by putting the
 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:
@@ -238,9 +233,9 @@ and the following to harden the TCP stack:
 
 before reloading these settings using `sysctl -p`.
 
-Sandboxing in apt can be enabled by putting the following in `/etc/apt/apt.conf.d/30-seccomp`:
+[Sandboxing in apt](https://www.debian.org/releases/buster/amd64/release-notes/ch-whats-new.en.html#apt-sandboxing) can be enabled by putting the following in `/etc/apt/apt.conf.d/30-seccomp`:
 
-    APT::Sandbox::Seccomp "true";
+    APT::Sandbox::Seccomp "1";
 
 I also restrict the use of cron to the `root` user by putting the following in `/etc/cron.allow`:
 

Add hotspot article
diff --git a/posts/sharing-wifi-connection-with-network-manager-hotspot.mdwn b/posts/sharing-wifi-connection-with-network-manager-hotspot.mdwn
new file mode 100644
index 0000000..e307e52
--- /dev/null
+++ b/posts/sharing-wifi-connection-with-network-manager-hotspot.mdwn
@@ -0,0 +1,96 @@
+[[!meta title="Sharing your WiFi connection with a NetworkManager hotspot"]]
+[[!meta date="2020-01-15T18:15:00.000-08:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+In-flight and hotel WiFi can be quite expensive and often insist on charging
+users extra to connect multiple devices. In order to avoid that, it's
+possible to easily create a WiFi hotspot using
+[NetworkManager](https://wiki.gnome.org/Projects/NetworkManager) and a
+[external USB WiFi
+adapter](https://www.thinkpenguin.com/gnu-linux/penguin-wireless-n-usb-adapter-gnu-linux-tpe-n150usb).
+
+# Creating the hotspot
+
+The main trick is to right-click on the NetworkManager icon in the status
+bar and select "Edit Connections..." (**not** "Create New WiFi Network..."
+despite the promising name).
+
+From there click the "+" button in the lower right then "WiFi" as the
+Connection Type. I like to use the computer name as the "Connection name".
+
+In the *WiFi* tab, set the following:
+
+- SSID: machinename_nomap
+- Mode: hotspot
+- Device: (the device name of the USB WiFi adapter)
+
+The `_nomap` suffix is there to opt out of the
+[Google](https://support.google.com/maps/answer/1725632?hl=en) and
+[Mozilla](https://location.services.mozilla.com/optout) location services
+which could allow anybody to lookup sightings of your device around the
+World.
+
+In the *WiFi Security* tab:
+
+- Security: WPA & WPA2 Personal
+- Password: (a 63-character random password generated using `pwgen -s 63`)
+
+While you may think that such a long password is inconvenient, it's now
+possible to add the network automatically by simply [scanning a QR
+code](https://feeding.cloud.geek.nz/posts/encoding-wifi-access-point-passwords-qr-code/)
+on your phone.
+
+In the *IPv4 Settings* tab:
+
+- Method: Shared to other computers
+
+Finally, in the *IPv6 Settings* tab:
+
+- Method: Ignore
+
+I ended up with the following config in
+`/etc/NetworkManager/system-connections/machinename`:
+
+    [connection]
+    id=machinename
+    uuid=<long UUID string>
+    type=wifi
+    interface-name=wl...
+    permissions=
+    timestamp=1578533792
+    
+    [wifi]
+    mac-address=<MAC>
+    mac-address-blacklist=
+    mode=ap
+    seen-bssids=<BSSID>
+    ssid=machinename_nomap
+    
+    [wifi-security]
+    key-mgmt=wpa-psk
+    psk=<63-character password>
+    
+    [ipv4]
+    dns-search=
+    method=shared
+    
+    [ipv6]
+    addr-gen-mode=stable-privacy
+    dns-search=
+    ip6-privacy=0
+    method=ignore
+
+# Firewall rules
+
+In order for the packets to flow correctly, I opened up the following ports
+on my machine's local firewall:
+
+    -A INPUT -s 10.42.0.0/24 -j ACCEPT
+    -A FORWARD -d 10.42.0.0/24 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+    -A FORWARD -s 10.42.0.0/24 -j ACCEPT
+    -A INPUT -d 224.0.0.251 -s 10.42.0.1 -j ACCEPT
+    -A INPUT -d 239.255.255.250 -s 10.42.0.1 -j ACCEPT
+    -A INPUT -d 10.42.0.255 -s 10.42.0.1 -j ACCEPT
+    -A INPUT -d 10.42.0.1 -s 10.42.0.0/24 -j ACCEPT
+
+[[!tag nzoss]] [[!tag gnome]] [[!tag debian]]

Allow builds to be interrupted if ran interactively
diff --git a/posts/seeding-brave-browser-sccache.mdwn b/posts/seeding-brave-browser-sccache.mdwn
index 6ccf30f..5697ea9 100644
--- a/posts/seeding-brave-browser-sccache.mdwn
+++ b/posts/seeding-brave-browser-sccache.mdwn
@@ -52,7 +52,7 @@ and here are the contents of that script:
     echo $(date)
     echo "=> Debug build"
     killall sccache || true
-    ionice nice timeout 4h npm run build || ionice nice timeout 4h npm run build
+    ionice nice timeout --foreground 4h npm run build || ionice nice timeout 4h npm run build
     ionice nice ninja -C src/out/Component brave_unit_tests
     ionice nice ninja -C src/out/Component brave_browser_tests
     echo
@@ -60,7 +60,7 @@ and here are the contents of that script:
     echo $(date)
     echo "=> Release build"
     killall sccache || true
-    ionice nice timeout 5h npm run build Release || ionice nice timeout 5h npm run build Release
+    ionice nice timeout --foreground 5h npm run build Release || ionice nice timeout 5h npm run build Release
     ionice nice ninja -C src/out/Release brave_unit_tests
     ionice nice ninja -C src/out/Release brave_browser_tests
     echo

Debug builds are now in src/out/Component by default
diff --git a/posts/seeding-brave-browser-sccache.mdwn b/posts/seeding-brave-browser-sccache.mdwn
index 423f702..6ccf30f 100644
--- a/posts/seeding-brave-browser-sccache.mdwn
+++ b/posts/seeding-brave-browser-sccache.mdwn
@@ -53,12 +53,12 @@ and here are the contents of that script:
     echo "=> Debug build"
     killall sccache || true
     ionice nice timeout 4h npm run build || ionice nice timeout 4h npm run build
-    ionice nice ninja -C src/out/Debug brave_unit_tests
-    ionice nice ninja -C src/out/Debug brave_browser_tests
+    ionice nice ninja -C src/out/Component brave_unit_tests
+    ionice nice ninja -C src/out/Component brave_browser_tests
     echo
     
     echo $(date)
-    echo "=>Release build"
+    echo "=> Release build"
     killall sccache || true
     ionice nice timeout 5h npm run build Release || ionice nice timeout 5h npm run build Release
     ionice nice ninja -C src/out/Release brave_unit_tests

Upgrade links to HTTPS
diff --git a/posts/getting-involved-in-open-source-project.mdwn b/posts/getting-involved-in-open-source-project.mdwn
index 97c5848..0a32b59 100644
--- a/posts/getting-involved-in-open-source-project.mdwn
+++ b/posts/getting-involved-in-open-source-project.mdwn
@@ -1,13 +1,13 @@
 [[!meta title="Getting involved in an Open Source project"]]
 [[!meta date="2009-02-11T11:30:00.001+13:00"]]
-[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/)"]]
 Contributing to an Open Source project is a fantastic way to learn new skills and gain some real work experience. Unlike most of the work done in the proprietary world, the contributions you make to a Free Software project are generally publicly visible and thus can easily be included in a portfolio you show to prospective employers.
 
 In most cases, getting involved in an existing project is quite easy. Most projects need help and would be very happy to count you on board even if you're not a developer. Good places to start:
 
-  * the operating system you use (e.g. [Ubuntu](http://www.ubuntu.com/community/participate) or [Debian](http://wiki.debian.org/GetInvolved-Beta))
-  * a piece of [Free Software](http://www.fsf.org/about/what-is-free-software) you use every day
+  * the operating system you use (e.g. [Ubuntu](https://discourse.ubuntu.com/t/contribute/26) or [Debian](https://wiki.debian.org/GetInvolved-Beta))
+  * a piece of [Free Software](https://www.fsf.org/about/what-is-free-software) you use every day
 
-Of course, if you can't find a project that solves your own particular problem, you may also want to [start a new one](http://feeding.cloud.geek.nz/2008/09/starting-free-software-project.html). You may be surprised at how many people will find your pet project useful and see a [community grow](http://feeding.cloud.geek.nz/2008/09/growing-community-around-your-new-free.html) around it.
+Of course, if you can't find a project that solves your own particular problem, you may also want to [start a new one](https://feeding.cloud.geek.nz/posts/getting-involved-in-open-source-project/). You may be surprised at how many people will find your pet project useful and see a [community grow](https://feeding.cloud.geek.nz/posts/growing-community-around-your-new-free/) around it.
   
 I gave [a presentation](https://archive.org/details/contributing-to-foss_soc) on this topic for the [New Zealand Summer of Code](https://summeroftech.co.nz/).

Fix dead links
diff --git a/posts/getting-involved-in-open-source-project.mdwn b/posts/getting-involved-in-open-source-project.mdwn
index fd7a8a1..97c5848 100644
--- a/posts/getting-involved-in-open-source-project.mdwn
+++ b/posts/getting-involved-in-open-source-project.mdwn
@@ -10,4 +10,4 @@ In most cases, getting involved in an existing project is quite easy. Most proje
 
 Of course, if you can't find a project that solves your own particular problem, you may also want to [start a new one](http://feeding.cloud.geek.nz/2008/09/starting-free-software-project.html). You may be surprised at how many people will find your pet project useful and see a [community grow](http://feeding.cloud.geek.nz/2008/09/growing-community-around-your-new-free.html) around it.
   
-I gave [a presentation](http://summerofcode.blip.tv/file/1760791/) on this topic for the [New Zealand Summer of Code](http://www.summerofcode.co.nz).
+I gave [a presentation](https://archive.org/details/contributing-to-foss_soc) on this topic for the [New Zealand Summer of Code](https://summeroftech.co.nz/).

Remove unnecessary whitespace
diff --git a/posts/getting-involved-in-open-source-project.mdwn b/posts/getting-involved-in-open-source-project.mdwn
index 70ee512..fd7a8a1 100644
--- a/posts/getting-involved-in-open-source-project.mdwn
+++ b/posts/getting-involved-in-open-source-project.mdwn
@@ -1,15 +1,13 @@
 [[!meta title="Getting involved in an Open Source project"]]
 [[!meta date="2009-02-11T11:30:00.001+13:00"]]
 [[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
-Contributing to an Open Source project is a fantastic way to learn new skills and gain some real work experience. Unlike most of the work done in the proprietary world, the contributions you make to a Free Software project are generally publicly visible and thus can easily be included in a portfolio you show to prospective employers.  
-  
-In most cases, getting involved in an existing project is quite easy. Most projects need help and would be very happy to count you on board even if you're not a developer. Good places to start:  
+Contributing to an Open Source project is a fantastic way to learn new skills and gain some real work experience. Unlike most of the work done in the proprietary world, the contributions you make to a Free Software project are generally publicly visible and thus can easily be included in a portfolio you show to prospective employers.
+
+In most cases, getting involved in an existing project is quite easy. Most projects need help and would be very happy to count you on board even if you're not a developer. Good places to start:
 
   * the operating system you use (e.g. [Ubuntu](http://www.ubuntu.com/community/participate) or [Debian](http://wiki.debian.org/GetInvolved-Beta))
-  * a piece of [Free Software](http://www.fsf.org/about/what-is-free-software) you use every day  
+  * a piece of [Free Software](http://www.fsf.org/about/what-is-free-software) you use every day
 
-Of course, if you can't find a project that solves your own particular problem, you may also want to [start a new one](http://feeding.cloud.geek.nz/2008/09/starting-free-software-project.html). You may be surprised at how many people will find your pet project useful and see a [community grow](http://feeding.cloud.geek.nz/2008/09/growing-community-around-your-new-free.html) around it.  
+Of course, if you can't find a project that solves your own particular problem, you may also want to [start a new one](http://feeding.cloud.geek.nz/2008/09/starting-free-software-project.html). You may be surprised at how many people will find your pet project useful and see a [community grow](http://feeding.cloud.geek.nz/2008/09/growing-community-around-your-new-free.html) around it.
   
 I gave [a presentation](http://summerofcode.blip.tv/file/1760791/) on this topic for the [New Zealand Summer of Code](http://www.summerofcode.co.nz).
-
-

Update qdisc guidance to fq
This is based on https://www.bufferbloat.net/projects/codel/wiki/#Binary-code-and-kernels-for-Linux-based-operating-systems.
diff --git a/posts/usual-server-setup.mdwn b/posts/usual-server-setup.mdwn
index b048270..c04e271 100644
--- a/posts/usual-server-setup.mdwn
+++ b/posts/usual-server-setup.mdwn
@@ -397,7 +397,7 @@ 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.d/local.conf`:
 
-    net.core.default_qdisc=fq_codel
+    net.core.default_qdisc=fq
 
 and the following to improve congestion control and
 [HTTP/2 prioritization](https://blog.cloudflare.com/http-2-prioritization-with-nginx/):

Add third pass assets
diff --git a/posts/receiving-sstv-images-from-iss/iss_sstv3.png b/posts/receiving-sstv-images-from-iss/iss_sstv3.png
new file mode 100644
index 0000000..dc9a5e8
Binary files /dev/null and b/posts/receiving-sstv-images-from-iss/iss_sstv3.png differ
diff --git a/posts/receiving-sstv-images-from-iss/iss_sstv3.wav b/posts/receiving-sstv-images-from-iss/iss_sstv3.wav
new file mode 100644
index 0000000..3f5178f
Binary files /dev/null and b/posts/receiving-sstv-images-from-iss/iss_sstv3.wav differ

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

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

Create tags for each of my radios
diff --git a/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox.mdwn b/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox.mdwn
index 1d0463a..953b794 100644
--- a/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox.mdwn
+++ b/posts/programming-anytone-d878uv-on-linux-using-windows10-and-virtualbox.mdwn
@@ -75,4 +75,4 @@ since it's much better than the official manual.
 You should be able to use the "Write to radio" menu option without any
 problems once you're done creating your codeplug.
 
-[[!tag ham]]
+[[!tag ham]] [[!tag anytone]]
diff --git a/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn b/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
index 4ddba68..d97037a 100644
--- a/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
+++ b/posts/using-kenwood-th-d72a-with-pat-linux-ax25.mdwn
@@ -98,4 +98,4 @@ If you can't connect to `VA7EOC-10` on UHF, you could also try the VHF BCFM
 repeater on Mt Seymour, [VE7LAN](http://www.bcfmca.bc.ca/lanvhf.php) (VECTOR
 channel 65).
 
-[[!tag ham]]
+[[!tag ham]] [[!tag kenwood]]

Add post about SSTV on the ISS
diff --git a/posts/receiving-sstv-images-from-iss.mdwn b/posts/receiving-sstv-images-from-iss.mdwn
new file mode 100644
index 0000000..4375796
--- /dev/null
+++ b/posts/receiving-sstv-images-from-iss.mdwn
@@ -0,0 +1,80 @@
+[[!meta title="Receiving slow-scan television images from the International Space Station"]]
+[[!meta date="2020-01-01T16:00:00.000-08:00"]]
+[[!meta license="[Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)"]]
+
+Thanks to a fellow [VECTOR](https://vectorradio.ca) volunteer [Nick
+Doyle](https://www.qrz.com/db/VE7NCD), I found out that the [International
+Space Station](https://en.wikipedia.org/wiki/International_Space_Station)
+would be broadcasting [slow-scan
+television](https://en.wikipedia.org/wiki/Slow-scan_television) images at
+the end of the year. I decided to try and pick those up with my handheld
+radio.
+
+# Planning
+
+From the [official announcement](https://ariss.pzk.org.pl/sstv/), I got the
+frequency (145.800 MHz) and the broadcast times.
+
+Next I had to figure out when the ISS would be passing over my location.
+Most of the ISS tracking websites and applications are aimed at people
+wanting to _see_ the reflection of the sun on the station and so they only
+list the passes during nighttime before the earth casts a shadow that would
+prevent any visual contacts.
+
+Thankfully, Nick found a site which has a option to show all of the passes,
+visible or not and so I was able to get a [list of upcoming passes over
+Vancouver](https://heavens-above.com/PassSummary.aspx?satid=25544&lat=49.2827&lng=-123.1207&loc=Vancouver&alt=0&tz=PST).
+
+# Hardware
+
+From a hardware point-of-view, I didn't have to get any special equipment. I
+used my [Kenwood D72](https://www.kenwood.com/usa/com/amateur/th-d72a/) and
+an external Comet SBB5 mobile antenna.
+
+The only other pieces of equipment I used was a 2.5mm mono adapter which I
+used to connect a 3.5mm male-male audio cable in the speaker port of the
+radio and the microphone input of my computer.
+
+# Software
+
+The software I used for the recording was
+[Audacity](https://www.audacityteam.org/) set to a **sampling rate of 48
+kHz**.
+
+Then I installed
+[qsstv](http://users.telenet.be/on4qz/qsstv/manual/index.html) and
+configured it to [read input from a file instead of the sound
+card](http://users.telenet.be/on4qz/qsstv/faq.html#Audiofile).
+
+# Results
+
+Here is the [audio I
+recorded](/posts/receiving-sstv-images-from-iss/iss_sstv1.wav) from the
+first pass (65 degrees at the highest point) as well as the rendered image:
+
+![](/posts/receiving-sstv-images-from-iss/iss_sstv1.png)
+
+The second pass (60 degrees) was not as successful since I didn't hold the
+squelch open and you can tell from the [audio
+recording](/posts/receiving-sstv-images-from-iss/iss_sstv2.wav) that the
+signal got drowned in noise a couple of times. This is the rendering of that
+second pass:
+
+![](/posts/receiving-sstv-images-from-iss/iss_sstv2.png)
+
+# Tips
+
+The signal came through the squelch for only about a minute at the highest
+point, so I found it best to open the squelch fully (`F`+`Moni`) as soon as
+the bird is visible.
+
+Another thing I did on a third pass (16 degrees at the highest point -- not
+particularly visible) was to plug the speaker out of my radio into a Y
+splitter so that I could connect it to my computer and an external speaker I
+could take outside with me. Since I was able to listen to the audio, I held
+the antenna and tried to **point it** at the [satellite's general
+direction](https://heavens-above.com/orbit.aspx?satid=25544&lat=49.2827&lng=-123.1207&loc=Vancouver&alt=0&tz=PST)
+as well as **varying the orientation** of the antenna to increase the signal
+strength.
+
+[[!tag kenwood]] [[!tag ham]]
diff --git a/posts/receiving-sstv-images-from-iss/iss_sstv1.png b/posts/receiving-sstv-images-from-iss/iss_sstv1.png
new file mode 100644
index 0000000..5026cd0
Binary files /dev/null and b/posts/receiving-sstv-images-from-iss/iss_sstv1.png differ
diff --git a/posts/receiving-sstv-images-from-iss/iss_sstv1.wav b/posts/receiving-sstv-images-from-iss/iss_sstv1.wav
new file mode 100644
index 0000000..173913c
Binary files /dev/null and b/posts/receiving-sstv-images-from-iss/iss_sstv1.wav differ
diff --git a/posts/receiving-sstv-images-from-iss/iss_sstv2.png b/posts/receiving-sstv-images-from-iss/iss_sstv2.png
new file mode 100644
index 0000000..fe0129f
Binary files /dev/null and b/posts/receiving-sstv-images-from-iss/iss_sstv2.png differ
diff --git a/posts/receiving-sstv-images-from-iss/iss_sstv2.wav b/posts/receiving-sstv-images-from-iss/iss_sstv2.wav
new file mode 100644
index 0000000..b9d05c0
Binary files /dev/null and b/posts/receiving-sstv-images-from-iss/iss_sstv2.wav differ

calendar update
diff --git a/archives/2020.mdwn b/archives/2020.mdwn
new file mode 100644
index 0000000..8843a09
--- /dev/null
+++ b/archives/2020.mdwn
@@ -0,0 +1 @@
+[[!calendar type=year year=2020 pages="page(posts/*) and !*/Discussion"]]
diff --git a/archives/2020/01.mdwn b/archives/2020/01.mdwn
new file mode 100644
index 0000000..0577516
--- /dev/null
+++ b/archives/2020/01.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=01 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(01) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/02.mdwn b/archives/2020/02.mdwn
new file mode 100644
index 0000000..189d77c
--- /dev/null
+++ b/archives/2020/02.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=02 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(02) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/03.mdwn b/archives/2020/03.mdwn
new file mode 100644
index 0000000..63a191c
--- /dev/null
+++ b/archives/2020/03.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=03 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(03) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/04.mdwn b/archives/2020/04.mdwn
new file mode 100644
index 0000000..d8be67f
--- /dev/null
+++ b/archives/2020/04.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=04 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(04) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/05.mdwn b/archives/2020/05.mdwn
new file mode 100644
index 0000000..92e59fa
--- /dev/null
+++ b/archives/2020/05.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=05 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(05) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/06.mdwn b/archives/2020/06.mdwn
new file mode 100644
index 0000000..fff6e79
--- /dev/null
+++ b/archives/2020/06.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=06 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(06) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/07.mdwn b/archives/2020/07.mdwn
new file mode 100644
index 0000000..9674bf2
--- /dev/null
+++ b/archives/2020/07.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=07 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(07) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/08.mdwn b/archives/2020/08.mdwn
new file mode 100644
index 0000000..19eec13
--- /dev/null
+++ b/archives/2020/08.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=08 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(08) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/09.mdwn b/archives/2020/09.mdwn
new file mode 100644
index 0000000..282af8d
--- /dev/null
+++ b/archives/2020/09.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=09 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(09) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/10.mdwn b/archives/2020/10.mdwn
new file mode 100644
index 0000000..e459232
--- /dev/null
+++ b/archives/2020/10.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=10 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(10) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/11.mdwn b/archives/2020/11.mdwn
new file mode 100644
index 0000000..b462704
--- /dev/null
+++ b/archives/2020/11.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=11 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(11) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]
diff --git a/archives/2020/12.mdwn b/archives/2020/12.mdwn
new file mode 100644
index 0000000..2503185
--- /dev/null
+++ b/archives/2020/12.mdwn
@@ -0,0 +1,5 @@
+[[!sidebar content="""
+[[!calendar type=month month=12 year=2020 pages="page(posts/*) and !*/Discussion"]]
+"""]]
+
+[[!inline pages="creation_month(12) and creation_year(2020) and page(posts/*) and !*/Discussion" show=0 feeds=no reverse=yes]]

Comment moderation
diff --git a/posts/encoding-wifi-access-point-passwords-qr-code/comment_3_4f23e4f1119d36cafcd927b51bbd82ea._comment b/posts/encoding-wifi-access-point-passwords-qr-code/comment_3_4f23e4f1119d36cafcd927b51bbd82ea._comment
new file mode 100644
index 0000000..937cf88
--- /dev/null
+++ b/posts/encoding-wifi-access-point-passwords-qr-code/comment_3_4f23e4f1119d36cafcd927b51bbd82ea._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="RobIII"
+ avatar="http://cdn.libravatar.org/avatar/f4862f3fb4e7d4570395c294e2c73345"
+ subject="@Martin"
+ date="2019-12-30T15:22:57Z"
+ content="""
+If you're using a phone without a camera then there's no point in using a QR code anyway, is it?
+"""]]

Add escaping for semicolons in passwords.
diff --git a/posts/encoding-wifi-access-point-passwords-qr-code.mdwn b/posts/encoding-wifi-access-point-passwords-qr-code.mdwn
index 1339937..bffca9d 100644
--- a/posts/encoding-wifi-access-point-passwords-qr-code.mdwn
+++ b/posts/encoding-wifi-access-point-passwords-qr-code.mdwn
@@ -19,9 +19,17 @@ package, run the following:
 substituting `<SSID>` for the name of your WiFi network and `<PASSWORD>` for
 the 63-character password you hopefully generated with `pwgen -s 63`.
 
-The only pitfall I ran into is that if you include a trailing newline character (for example piping
-`echo "..."` into `qrencode` as opposed to `echo -n "..."`) then it will
-fail on both iOS and Android.
+If your password includes a semicolon, then escape it like this:
+
+    "WIFI:T:WPA;S:<SSID>;P:pass\:word;;"
+
+since iOS won't support the following (which works fine on Android):
+
+    'WIFI:T:WPA;S:<SSID>;P:"pass:word";;'
+
+The only other pitfall I ran into is that if you include a trailing newline
+character (for example piping `echo "..."` into `qrencode` as opposed to
+`echo -n "..."`) then it will fail on both iOS and Android.
 
 ## Scanning the QR code
 
diff --git a/posts/encoding-wifi-access-point-passwords-qr-code/comment_2_c0110bb414c3c1298fb6b3abb6d897eb._comment b/posts/encoding-wifi-access-point-passwords-qr-code/comment_2_c0110bb414c3c1298fb6b3abb6d897eb._comment
deleted file mode 100644
index 62552ac..0000000
--- a/posts/encoding-wifi-access-point-passwords-qr-code/comment_2_c0110bb414c3c1298fb6b3abb6d897eb._comment
+++ /dev/null
@@ -1,8 +0,0 @@
-[[!comment format=mdwn
- ip="2001:44b8:3191:3b00:7dba:a0e1:1b6a:313e"
- claimedauthor="Jeremy"
- subject="Semicolon in SSID or password"
- date="2019-12-30T02:33:57Z"
- content="""
-How does this handle semicolons in the SSID or password?
-"""]]

Comment moderation
diff --git a/posts/encoding-wifi-access-point-passwords-qr-code/comment_3_e3c73a6fa17265f79283284c80a6d9ac._comment b/posts/encoding-wifi-access-point-passwords-qr-code/comment_3_e3c73a6fa17265f79283284c80a6d9ac._comment
new file mode 100644
index 0000000..08c9356
--- /dev/null
+++ b/posts/encoding-wifi-access-point-passwords-qr-code/comment_3_e3c73a6fa17265f79283284c80a6d9ac._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ ip="85.220.211.78"
+ claimedauthor="Martin"
+ subject="63 characters?"
+ date="2019-12-30T12:58:46Z"
+ content="""
+Neither my current mobile device (GPD Pocket running Debian bullseye), nor my future one, the Pyra (there is still some hope), feature a camera. With a password of 63 characters, I hope to type everything correctly! :-)
+"""]]