Ok so after writing up about todo list management with iCal, I realized that it was still bugging me that I gave up on Taskwarrior prematurely. Not that I’m super unhappy about my current setup, but some things were lacking with iCal tasks, mainly being able to group by topics or projects. Also Taskwarrior has heaps of other features that maybe I don’t need, but it made me want to give it a go anyway.

Turns out that it is as powerful as they say, and I’ll probably be sticking with it for a while! But my thoughts on that are for another post. So without further ado, here’s a tutorial, both to help anyone else setting up taskwarrior with syncing and so I have something to follow if I need to set it up again in the future.

Goal

This is aiming to set up Taskwarrior on an Archlinux desktop and an Android device, and Taskserver on a headless Archlinux server. The network looks like:

[desktop] <--> [server] <--> [android]

Where the server is publically facing and is accessible by domain name(s).

Taskserver

The server is the most complex to set up, because it uses it’s own sync protocol over top of TLS, and clients authenticate using public certificates.

Because this setup process involves several commands, in different directories, and as various users, commands displayed below will be displayed as in a bash shell, with an example username, machine name, and working directory.

Firstly, you will need to log in to your Archlinux server as a user with sudo privileges.

Now let’s install taskd. This step is more streamlined on Arch than what you will find on other tutorials; there is an aur package! Simply install using your preferred aur helper (or manually with makepkg, I don’t care). :P

[admin@server ~]$ pacaur -y taskd

This will install the taskserver, add a taskd user, install a systemd service, and init a data directory under /var/lib/taskd.

Change to the taskd user.

[admin@server ~]$ sudo -u taskd /bin/bash

Now this is the part that can get complicated… time to generate the server and client certificates.

[taskd@server /]$ cp -r /usr/share/doc/taskd/pki /var/lib/taskd
[taskd@server /]$ cd /var/lib/taskd/pki

Edit the vars file for information about the certificates that will be generated.

[taskd@server pki]$ vi vars

The important one is the CN value, which will default to something like localhost. This must be changed to the domain through which you will be accessing the taskserver. Other information is up to you. You may want to increase the EXPIRATION_DAYS to more than the default (1 year) for convenience though. The end result should look something like:

BITS=4096
EXPIRATION_DAYS=365
ORGANIZATION="WHATEVER"
CN=your.domain.tld
COUNTRY=AU
STATE="WHATEVER"
LOCALITY="WHATEVER"

Next, generate the certificates. This is automated by:

[taskd@server pki]$ ./generate

This will have generated the CA, server certificates, an a client key pair.

Now configure taskd to use the generated certs:

[taskd@server /]$ export TASKDDATA=/var/lib/taskd
[taskd@server /]$ taskd config --force client.cert $TASKDDATA/pki/client.cert.pem
[taskd@server /]$ taskd config --force client.key $TASKDDATA/pki/client.key.pem
[taskd@server /]$ taskd config --force server.cert $TASKDDATA/pki/server.cert.pem
[taskd@server /]$ taskd config --force server.key $TASKDDATA/pki/server.key.pem
[taskd@server /]$ taskd config --force server.crl $TASKDDATA/pki/server.crl.pem
[taskd@server /]$ taskd config --force ca.cert $TASKDDATA/pki/ca.cert.pem

Some final configuration. If you want persistant logging (the default for me was under /tmp):

[taskd@server /]$ taskd config --force log $TASKDDATA/taskd.log

Make sure it’s going to listen on the interfaces and ports required. In my case this was the usual taskserver port and all interfaces. The official docs has some notes about interface binding.

[taskd@server /]$ taskd config --force server '*:53589'

Log out from the taskd user so we can do some admin tasks. First, allow incoming connections to this port:

[admin@server ~]$ sudo ufw allow 53589

Don’t forget to forward the port if your server is behind a router with nat!

Finally we can start the server! Also don’t forget to enable the systemd service so it autostarts on boot.

[admin@server ~]$ sudo systemctl start taskd
[admin@server ~]$ sudo systemctl enable taskd

Log back in as the taskd user so we can add users to the system. Taskserver can group users by organizations, and a user must be part of an organization. Name them as you please. My setup was something like:

[taskd@server /]$ export TASKDDATA=/var/lib/taskd
[taskd@server /]$ taskd add org Public
[taskd@server /]$ taskd add user 'Public' 'Samuel Walladge'
New user key: 00000000-0000-dead-beef-000000000000
Created user 'Samuel Walladge' for organization 'Public'

Take special note of the new user key displayed when adding the user! You will need this, along with the org and user names, when setting up a client.

For each client, you will also need the CA certfication (ca.cert.pem), and a client key pair. One was generated back when you generated the other certs (client.cert.pem and client.key.pem), so you can use that for the first client. Then you can either reuse this keypair for all your clients, or generate a new pair for each client with:

[taskd@server pki]$ ./generate.client certname

(Generates certname.key.pem and certname.cert.pem in the directory.)

For now, we’ll just work with the original generated ones and move on to setting up taskwarrior to sync with the server. Up to this point, you should have a working taskserver, but nothing to test it with.

Note on security: clients can only access the server with certificates generated this way. They can also only access your tasks if they know your org, username, and user key (uuid).

Taskwarrior on Linux

First install it:

[user@desktop ~]$ sudo pacman -S task

Done! Taskwarrior doesn’t require anything fancy to get started. You can go ahead and start using it now if you like, but let’s set up syncing next.

If you previously have been using task, it’s probably a good idea to backup the task data directory before continuing (this is stored at ~/.task/ by default). If not, go ahead and add an example task to help with testing sync later:

[user@desktop ~]$ task add finish setting up taskwarrior

Now on to syncing! You will need the following things from setting up the taskserver:

  • org name: Public
  • username: Samuel Walladge
  • user key: 00000000-0000-dead-beef-000000000000
  • ca.cert.pem
  • client.key.pem
  • client.cert.pem

Yes, this means you’ll have to copy the cert files from the server to your client. Use whatever secure method suits. I think I managed to get the files on the server to a place where I could then pull them via rsync, but YMMV^[https://xkcd.com/949/]. ¯\_(ツ)_/¯

Once you have everything together, configure task to use the correct credentials and info:

[user@desktop ~]$ task config taskd.certificate -- ~/.task/client.cert.pem
[user@desktop ~]$ task config taskd.key -- ~/.task/client.key.pem
[user@desktop ~]$ task config taskd.ca -- ~/.task/ca.cert.pem
[user@desktop ~]$ task config taskd.server -- your.domain.tld:53589
[user@desktop ~]$ task config taskd.credentials -- Public/Samuel Walladge/00000000-0000-dead-beef-000000000000

Now we’re ready to init syncing! Run the following command once for the first sync:

[user@desktop ~]$ task sync init

THIS STEP IS IMPORTANT: accidentally running task sync instead of the initial task sync init will do bad things. (I may have discovered this the hard way…) The init part seems to set up some important initial data server-side, and if this isn’t set up, you may get errors like ERROR: Could not find common ancestor for ....

If you do forget to do this first, according to Taskwarrior’s author, you should find the tx.data file for your user among the taskserver data files and delete it. Then run run task sync init from the client side again (once). 1

Note that this will reset the data saved on the server and force the client to mirror all tasks up to the server. You may lose data.

As a side note, it seems odd that it’s possible for the client to make the server state unstable… something to look into.

Anyway, if sync init ran without errors, everything is now working! You can use the task command to interact with Taskwarrior, and run task sync any time you wish to sync with the server. It syncs quickly, and I have a crontab entry to auto sync every few minutes.

Taskwarrior on Android

Now let’s set up on Android!

There’s an open source Android app (not affiliated with the main Taskwarrior project) available from the Play store or F-Droid.

It’s a bit rough around the edges, but quite functional. It wraps the task binary, and configuration must be done via a text editor (the app comes with an editor with one click access to the config file).

Once the app is installed, run it and create an account name (this is local - doesn’t matter what details you use) and let it create a new data directory.

Now you need the client key pair and CA cert as in setting up the desktop for syncing. Copy these to your device. Best place is /sdcard/Android/data/kvj.taskw/files/00000-data-dir-name000 so the configuration file can then refer to them easily via relative paths, and they’re easy to find again.

[user@desktop ~]$ adb push client.key.pem /sdcard/Android/data/kvj.taskw/files/00000-data-dir-name000/
[user@desktop ~]$ adb push client.cert.pem /sdcard/Android/data/kvj.taskw/files/00000-data-dir-name000/
[user@desktop ~]$ adb push ca.cert.pem /sdcard/Android/data/kvj.taskw/files/00000-data-dir-name000/

(This method may or may not need root access… can’t remember. Either way, the files need to be on your device either in the Taskwarrior app data directory or on the main storage where apps can access or request access to.)

Now we can configure the app to sync similarly to desktop. Edit /sdcard/Android/data/kvj.taskw/files/00000-data-dir-name000/.taskrc.android to add the credentials and cert paths. (Either with a cli editor over adb, in the app by tapping Settings, or via another text editor.)

Minimal config for syncing should look something like:

taskd.certificate=client.cert.pem
taskd.key=client.key.pem
taskd.ca=ca.cert.pem
taskd.server=your.domain.tld:53589
taskd.credentials=Public\/Samuel Walladge\/00000000-0000-dead-beef-000000000000

See the wiki on the app’s Bitbucket for more configuration options specific to the app. Some tweaking may be necessary to get it to connect successfully to the taskserver sync server. On my LineageOS Nougat phone I needed to tweak the ciphers config to get it to connect:

ciphers=SECURE256

That should be it!

Resources and parting notes

Here are some useful links I found that helped me in setting all this up.

Shout out to the helpful people on #taskwarrior on freenode for answering all my newbie questions!

It’s probably a good idea to securely backup the server data directory - everything is in plain text files so I’m using restic to make periodic backups.

Have fun using one of the most powerful todo list managers I’ve ever seen!

  1. https://botbot.me/freenode/taskwarrior/2018-03-12/