Self-Hosted Kanban Boards with WeKan

Published: 2022-09-23

If you are into productivity, then you have probably heard of Kanban boards. Kanban boards allow you to track your tasks in multiple rows. Compared to more traditional tasks lists, Kanban boards solve one major problem. To see the problem, say that you are gathering your tasks all in one place just like David Allen would advice in Getting Things Done. Now if you have all tasks in one big list and if you want to take a task out of your list, then you will need to read all tasks and pick one. That's not very productive. Instead, with a Kanban board, you can group your tasks in different lists. For example, one for the supermarket and one for priority work. Based on Cal Newports advice, I've been using the following Trello setup:

AfterburnerThis WeekBackburnerFigure OutWaiting
Do groceriesWrite WeKan blog postBirthday gift for dad
Cook dinner
Receive packet from store

The task lists such as Backburner and Figure Out allow me to organize thoughts in different lists. For example, the "Receive packet from store" item was something that I remembered in the evening and quickly wrote down to not forget it. The birthday gift item was also remembered on a random moment, but has less priority since the birthday is in a few months.

This Kanban board has worked great for me via Trello, but to back it up I needed to pay $6 per month for it. That's too much, so I moved to an open-source and self-hosted alternative: WeKan. I've been used WeKan for a few weeks now and it works as well as Trello. One reason could be that the core maintainer, Lauri Ojansivu, has been steadily working on WeKan for a few years. It doesn't have a native app for my iPhone, but that is not problem since the website works great on mobile.

To set it up, we'll use Docker Compose. Let's get started. Intall Docker Compose on your server and make a new directory called wekan. Inside this directory, add the following docker-compose.yml:

version: '3.7'

    image: 'mongo:5.0'
    container_name: 'wekan_db'
    user: '3020:3020'
    command: 'mongod --logpath /dev/null --oplogSize 128 --quiet'
      - '/data/wekan_db:/data/db:rw'
    restart: 'unless-stopped'

    image: ''
    container_name: 'wekan'
    user: '3020:3020'
      - '2000:8080'
      driver: "json-file"
        max-size: "10m"
        max-file: "10"
      MONGO_URL: 'mongodb://wekan_db:27017/wekan'
      MAIL_URL: 'smtp://'
      ROOT_URL: 'https://wekan.<yourdomain>.com'
      WITH_API: 'true'
      WRITABLE_PATH: '/data'
      - 'wekan_db'
      - '/data/wekan:/data:rw'
    restart: 'unless-stopped'

Before starting it, add the following inside the wekan directory too:

set -e

mkdir -p /data/wekan
mkdir -p /data/wekan_db

chown -R 3020:3020 /data/wekan*
chmod 775 /data/wekan*
chmod g+s /data/wekan*

and run it with

$ bash

This setup script creates the /data/wekan and /data/wekan_db folders and sets the right permissions. Specifically, it ensures that user 3020 has access to the data. Together with user: '3020:3020' inside docker-compose.yml, this improves security since it makes it harder for attackers to gain admin rights.

Next, start the service with:

$ docker-compose up

and verify that it doesn't print errors; see the Docker Compose cheatsheet if you need more information.

Next, setup a reverse proxy. To do so, setup your DNS settings so that it forwards wekan.<yourdomain>.com to your server IP. Next, add the following to your Caddyfile:

wekan.<yourdomain>.com {

and ensured that Caddy handles incoming requests on port 80 and 443. Now, if someone opens https://wekan.<yourdomain>.com in a browser, then they will talk to Caddy via a secure connection (SSL) and be forwared to WeKan at internal port 2000. In turn, this should make WeKan available via SSH 🥳. You can now create an admin user via the web interface. Also, don't forget to disable registration of new users via the web interface and consider setting up automated backups.

The text is licensed under CC BY-NC-SA 4.0 and the code under Unlicense.