I ve had a kludgy mess of electronic address books for most of two decades,
and have got rather fed up with it. My stack consisted of:
~/.mutt/aliases, a flat text file consisting of
- lbdb configuration to query
~/.mutt/aliases, Debian s LDAP database, and Canonical s LDAP database,
so that I can search by name with Ctrl-t in
mutt when composing a new message
- Google Contacts, which I used from Android and was completely separate
from all of the above
The biggest practical problem with this was that I had the address book that
was most convenient for me to add things to (Google Contacts) and the one I
used when sending email, and no sensible way to merge them or move things
between them. I also wasn t especially comfortable with having all my
contact information in a proprietary web service.
My goals for a replacement address book system were:
- free software throughout
- storage under my control
- single common database
- minimal manual transcription when consolidating existing databases
- integration with Android such that I can continue using the same
contacts, messaging, etc. apps
- integration with
mutt such that I can continue using the same query interface
- not having to write my own software, because honestly
I think I have all this now!
The obvious basic technology to use is
: it s fairly complex,
admittedly, but lots of software supports it and one of my goals was not
having to write my own thing. This meant I needed a CardDAV server, some
way to sync the database to and from both Android and the system where I run
, and whatever query glue was necessary to get
to understand vCards.
There are lots of different alternatives here, and if anything the problem
was an embarrassment of choice. In the end I just decided to go for things
that looked roughly the right shape for me and tried not to spend too much
time in analysis paralysis.
I went with Xandikos
server, largely because I know Jelmer and have generally had pretty good
experiences with their software, but also because using Git for history of
the backend storage seems like something my future self will thank me for.
It isn t packaged in stretch, but it s in Debian unstable, so I installed it
Rather than the standalone mode suggested on the web page, I decided to set
it up in what felt like a more robust way using WSGI
. I installed
, and created the
following file in
which I then
socket = 127.0.0.1:8801
uid = xandikos
gid = xandikos
umask = 022
master = true
cheaper = 2
processes = 4
plugin = python3
module = xandikos.wsgi:app
env = XANDIKOSPATH=/srv/xandikos/collections
The port number was arbitrary, as was the path. You need to create the
user and group first (
adduser --system --group --no-create-home
). I created
and mode 0700, and I recommend setting a
as shown above since uwsgi s default
umask is 000 (!). You should also run
sudo -u xandikos xandikos -d
and then Ctrl-c it after a short
time (I think it would be nicer if there were a way to ask the WSGI wrapper
to do this
For Apache setup, I kept it reasonably simple: I ran
with a username and
password for myself, added a virtual host in
, and enabled it with
service apache2 reload
, set the new virtual host up with Let s
, reloaded again, and off we go.
I installed DAVdroid
from the Play Store: it
cost a few pounds, but I was OK
with that since it s GPLv3 and I m happy to
help fund free software. I created two accounts, one for my existing Google
Contacts database (and in fact calendaring as well, although I don t intend
to switch over to self-hosting that just yet), and one for the new Xandikos
instance. The Google
was a bit fiddly
because I have two-step verification turned on so I had to create an
app-specific password. The Xandikos setup was straightforward: base URL
username, password, and done.
Since I didn t completely trust the new setup yet, I followed what seemed
like the most robust option from the DAVdroid contacts syncing
and used the stock contacts app to export my Google Contacts account to a
file and then import that into the appropriate DAVdroid account
(which showed up automatically). This seemed straightforward and everything
got pushed to Xandikos. There are some weird delays in syncing contacts
that I don t entirely understand, but it all seems to get there in the end.
First off I needed to sync the contacts. (In fact I happen to run
the same system where I run Xandikos at the moment, but I don t want to rely
on that, and going through the CardDAV server means that I don t have to
poke holes for myself using filesystem permissions.) I used
for this. In
status_path = "~/.vdirsyncer/status/"
a = "contacts_local"
b = "contacts_remote"
collections = ["from a", "from b"]
type = "filesystem"
path = "~/.contacts/"
fileext = ".vcf"
type = "carddav"
url = "<Xandikos base URL>"
username = "<my username>"
password = "<my password>"
then synced everything
. I added an hourly
entry to run
-v WARNING sync
Next, I needed a command-line address book tool based on this.
looked about right and is in
stretch, so I installed that. In
mostly just the example configuration, but I preferred to sort by first name
since not all my contacts have neat first/last names):
path = ~/.contacts/<UUID of my contacts collection>/
debug = no
default_action = list
editor = vim
merge_editor = vimdiff
# display names by first or last name: first_name / last_name
display = first_name
# group by address book: yes / no
group_by_addressbook = no
# reverse table ordering: yes / no
reverse = no
# append nicknames to name column: yes / no
show_nicknames = no
# show uid table column: yes / no
show_uids = yes
# sort by first or last name: first_name / last_name
sort = first_name
# extend contacts with your own private objects
# these objects are stored with a leading "X-" before the object name in the vcard files
# every object label may only contain letters, digits and the - character
# private_objects = Jabber, Skype, Twitter
private_objects = Jabber, Skype, Twitter
# preferred vcard version: 3.0 / 4.0
preferred_version = 3.0
# Look into source vcf files to speed up search queries: yes / no
search_in_source_files = no
# skip unparsable vcard files: yes / no
skip_unparsable = no
shows all my contacts. So far so good. Apparently there
are some awkward vCard compatibility
with creating or modifying
contacts from the
end. I ve tried adding one address from
and it seems to at least minimally work for
me, but I haven t explored this very much yet.
I had to install python3-vobject 0.9.4.1-1 from experimental to fix
saving certain vCard files.
integration. I already had
set query_command="lbdbq '%s'"
, and I wanted to keep that in place since I still wanted to
querying as well. I had to write a very small amount of code for
this (perhaps I should contribute this to
khard email --parsable --remove-first-line --search-in-source-files "$1"
now reads as follows (you probably won t want the LDAP
stuff, but I ve included it here for completeness):
METHODS='m_muttalias m_khard m_ldap'
I ve deleted one account from Google Contacts just to make sure that
everything still works (e.g. I can still search for it when composing a new
message), but I haven t yet deleted everything. I won t be adding anything
new there though.
I need to push everything from
into the new system. This
is only about 30 contacts so shouldn t take too long.
Overall this feels like a big improvement! It wasn t a trivial amount of
setup for just me, but it means I have both better usability for myself and
more independence from proprietary services, and I think I can add extra
users with much less effort if I need to.
A day later and I ve consolidated all my accounts from Google Contacts and
into the new system, with the exception of one group that
I had defined as a
alias and need to work out what to do with. This
all went smoothly.
I ve filed the new
, and the