What Vikunja Does That Todoist and Notion Don’t
Vikunja is a free, open-source task manager built for self-hosting – meaning your tasks, projects, and deadlines live on your own server, not a company’s cloud. If you have ever grown frustrated with per-seat pricing on project tools or worried about what happens to your data when a startup shuts down, Vikunja is the answer worth installing.

What You Need Before You Start
Vikunja runs comfortably on a small Linux server or even a home machine with 1 GB of RAM and a modern 64-bit CPU. You will need Docker and Docker Compose installed, since the Docker route is by far the cleanest way to get it running without dependency headaches. If you plan to expose Vikunja to the internet rather than just your local network, a reverse proxy is worth setting up first – Traefik works well alongside Docker containers and handles SSL termination automatically. A registered domain or a local DNS entry pointing to your server will round out your requirements.
Vikunja supports three database backends: SQLite, MySQL (or MariaDB), and PostgreSQL. For personal use or a small team, SQLite is perfectly fine and requires no extra setup. For anything more demanding – multiple users, shared projects with heavy task volumes – PostgreSQL is the better choice. This guide will use MariaDB, which sits in a practical middle ground between simplicity and production readiness.
Before writing any configuration files, create a directory to hold everything. Running mkdir -p ~/vikunja && cd ~/vikunja gives you a clean workspace. You will also want to decide on a secret string for the JWT token used to sign user sessions. Generate one now with openssl rand -hex 32 and keep it handy – it goes directly into the config.
One thing to settle before proceeding: port allocation. Vikunja’s API server listens on port 3456 by default, and the frontend on port 80 inside the container. If you are running other services on the same host, check for conflicts with ss -tlnp before you start writing compose files. Skipping this step causes silent failures that take longer to debug than the setup itself.

Installing and Configuring Vikunja with Docker Compose
Create a file called docker-compose.yml in your Vikunja directory. The setup involves three containers: the database, the Vikunja API backend, and the Vikunja frontend. They talk to each other over a shared Docker network, which keeps everything isolated from other services on the host.
Paste the following into your compose file:
- db service: use mariadb:10 as the image. Set environment variables for MYSQL_ROOT_PASSWORD, MYSQL_USER (set to vikunja), MYSQL_PASSWORD, and MYSQL_DATABASE (set to vikunja). Mount a named volume at /var/lib/mysql so your data survives container restarts.
- api service: use vikunja/api:latest. Set VIKUNJA_DATABASE_TYPE to mysql, VIKUNJA_DATABASE_HOST to db, and fill in the matching VIKUNJA_DATABASE_USER, VIKUNJA_DATABASE_PASSWORD, and VIKUNJA_DATABASE_DATABASE values. Set VIKUNJA_SERVICE_JWTSECRET to the hex string you generated earlier. Mount a volume at /app/vikunja/files for attachments and uploads. Add depends_on: [db] so it waits for the database to be ready.
- frontend service: use vikunja/frontend:latest. Set VIKUNJA_API_URL to the address where your API will be reachable – for local testing this is http://your-server-ip:3456/api/v1. Map port 8080:80 on the host so the web interface is accessible without touching privileged ports.
Add a top-level networks block defining a network named vikunja and assign all three services to it. Add a top-level volumes block declaring your named volumes for the database and file storage. Once the file looks right, run docker compose up -d from your Vikunja directory. The first run pulls all three images, which takes a few minutes depending on your connection speed.
When the containers are up, check their status with docker compose ps. All three should show as running. If the API container exits immediately, check its logs with docker compose logs api – the most common culprits are a mismatched database password or a missing JWT secret. The database container sometimes takes 10 to 15 seconds to finish initializing before the API can connect, so a quick restart with docker compose restart api resolves most timing-related failures.
Open a browser and navigate to http://your-server-ip:8080. Vikunja’s login screen should appear. The first account you register automatically receives admin rights, so create your account immediately after the service comes up. From there you can invite additional users, create projects, assign tasks, and configure labels directly in the interface – no config file edits required for day-to-day management.
Keeping Vikunja Running and Up to Date

Backups for a Docker-based Vikunja setup come down to two things: the database and the files volume. Automate a nightly MariaDB dump with a cron job running docker compose exec db mysqldump -u vikunja -p vikunja > ~/backups/vikunja-$(date +%F).sql. For the uploaded files, a simple rsync of the named volume’s mount path covers everything that the database dump misses. Store both somewhere off the host – a network share, an S3-compatible bucket, or even an encrypted external drive.
Updating Vikunja means pulling new images and recreating the containers. Run docker compose pull followed by docker compose up -d and Docker will replace any containers whose images have changed while leaving the volumes – and all your data – completely intact. Vikunja’s API handles database migrations automatically on startup, so there is no manual schema work between versions. The project moves quickly, with new releases addressing bugs and adding features like recurring tasks and project templates, so checking for updates every few weeks is a habit worth building.





