How to Install Vikunja with Docker
Table of contents
- Key takeaways
- What is Vikunja?
- What views does it offer: list, kanban, Gantt and calendar?
- The Vikunja docker-compose.yml with a database
- Key configuration variables
- How do you publish it with a reverse proxy and HTTPS?
- Frequently asked questions
- Do I really need PostgreSQL or is SQLite enough?
- Why should I not use the image's latest tag?
- How do I back up Vikunja?
- Conclusion
- Sources
Vikunja is an open-source task manager that you self-host with Docker in a single image. With one docker-compose.yml file you bring up the application alongside a PostgreSQL database and organize your projects in list, kanban board, Gantt and table views, with all your data stored on your own server.
Vikunja is a task and project manager that you can self-host with Docker in a matter of minutes, and it now fits into a single image. In this guide you bring up the application alongside a PostgreSQL database with a single docker-compose.yml file, learn how to set the essential variables, how to organize your tasks in list, kanban, Gantt and table views, and how to publish it over HTTPS behind a reverse proxy. The same explanation is available in Spanish.
Key takeaways
- Vikunja is an open-source task manager licensed under AGPLv3, written in Go, that replaces services like Todoist or Trello and keeps your data on your own server.
- Since the unified release, everything lives in a single image
vikunja/vikunja; you no longer have to combinevikunja/apiandvikunja/frontendseparately. - The container listens on port 3456 and runs as user
1000, so the attachments folder must belong to that UID before you start it. - It supports three databases (SQLite by default, MySQL/MariaDB and PostgreSQL); for serious use a PostgreSQL in its own container is best.
- The
VIKUNJA_SERVICE_PUBLICURLvariable is mandatory: without the correct public URL, the frontend cannot find the API when you put it behind a proxy.
What is Vikunja?
Vikunja is an open-source application for managing tasks and projects that you host on your own infrastructure, a self-hosted replacement for tools like Todoist, Trello or Asana. Its motto sums up the idea well: it is the task manager you actually own, because the data stays on your server and not in a third party’s cloud.
It is written in Go, which means a single lightweight binary, with a Vue frontend that also works as an installable web app (PWA) on mobile. It is released under the AGPLv3 license and exposes a full REST API, so you can connect your own clients or integrate it with other tools. It ships built-in migration from Todoist, Trello and Microsoft To-Do, so moving from one of those platforms is just a matter of importing a file.
What views does it offer: list, kanban, Gantt and calendar?
The big advantage of Vikunja over a simple to-do list is that each project can be seen in several ways at once. Since the multiple-views system introduced in version 0.24, you define whichever views you want per project and switch between them with one click:
- List: the classic view, ideal for day-to-day work and for ticking tasks off.
- Kanban board: draggable columns (to do, in progress, done) to track the state of a workflow.
- Gantt: a timeline perfect for planning deadlines and due dates at a glance.
- Table: a grid with columns for priority, labels, assignees and dates.
For the calendar, Vikunja does not include a monthly calendar view as such, but it does offer CalDAV integration: you subscribe your usual calendar app (your phone’s, Thunderbird or another) to the Vikunja server and your dated tasks appear there automatically. On top of that, the new query-language filter system lets you build precise views such as "my tasks due this week".
The Vikunja docker-compose.yml with a database
Create a folder for the project, prepare the attachments folder with the right user and save this docker-compose.yml inside it. Replace each change_this_key... value with your own password and the secret with a long random string before starting:
services:
db:
image: postgres:17-alpine
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_USER: vikunja
POSTGRES_PASSWORD: change_this_db_key
POSTGRES_DB: vikunja
healthcheck:
test: ["CMD-SHELL", "pg_isready -U vikunja"]
interval: 30s
timeout: 5s
retries: 5
vikunja:
image: vikunja/vikunja:2.3.0
restart: unless-stopped
ports:
- "3456:3456"
depends_on:
db:
condition: service_healthy
volumes:
- ./files:/app/vikunja/files
environment:
VIKUNJA_SERVICE_PUBLICURL: "http://localhost:3456"
VIKUNJA_SERVICE_SECRET: change_this_long_random_secret_key
VIKUNJA_SERVICE_ENABLEREGISTRATION: "true"
VIKUNJA_DATABASE_TYPE: postgres
VIKUNJA_DATABASE_HOST: db
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_DATABASE_PASSWORD: change_this_db_key
VIKUNJA_DATABASE_DATABASE: vikunja
volumes:
db_data:
Notice a few details in the file. The application does not start until PostgreSQL passes its healthcheck, thanks to depends_on with the service_healthy condition. The container listens on port 3456 and we publish it on the same port of the host. The attachments you upload to tasks are stored in a ./files bind mount, and because Vikunja runs as UID 1000, that folder must belong to that user. Prepare it before the first boot:
mkdir -p files
sudo chown 1000:1000 files
docker compose up -d
docker compose ps
When the log stops moving, open http://localhost:3456 in the browser. You will see Vikunja’s welcome screen ready to create the first account.
Key configuration variables
Vikunja is configured entirely with environment variables prefixed VIKUNJA_. Three of them are worth understanding well:
VIKUNJA_SERVICE_PUBLICURLis the most important: it must match the exact URL through which users reach the application (with itshttps://scheme and no extra trailing slash). If you set it wrong, the frontend will load but cannot talk to the API and you will see network errors when signing in.VIKUNJA_SERVICE_SECRETis the secret used to sign the JWT session tokens. Generate a long, random string; if you change this value, all open sessions are invalidated. The oldVIKUNJA_SERVICE_JWTSECRETstill works but is deprecated.VIKUNJA_SERVICE_ENABLEREGISTRATIONdefaults totrue. Leave it that way just long enough to create your user, then set it tofalseand recreate the container; otherwise anyone who reaches your instance could register.
A good practice is to move these values into a .env file rather than writing them directly in the Compose file; it is the same pattern other tools in this series use, such as Firefly III for your personal finances. To start from scratch, you first need Docker installed; follow the guide to install Docker on Ubuntu 24.04 if that is your case.
How do you publish it with a reverse proxy and HTTPS?
Serving Vikunja over plain HTTP is only fine for tests on your local network. To take it to the Internet with a valid certificate, place it behind a reverse proxy that handles TLS. With Nginx Proxy Manager you just create a "proxy host" pointing to the container on port 3456 and request a Let’s Encrypt certificate from its interface.
If you prefer Traefik, remove the ports section from the vikunja service, connect it to the proxy network and add these labels:
labels:
- "traefik.enable=true"
- "traefik.http.routers.vikunja.rule=Host(`tasks.mydomain.com`)"
- "traefik.http.routers.vikunja.entrypoints=websecure"
- "traefik.http.routers.vikunja.tls.certresolver=le"
- "traefik.http.services.vikunja.loadbalancer.server.port=3456"
The step you must not forget: update VIKUNJA_SERVICE_PUBLICURL to your real domain with HTTPS (for example https://tasks.mydomain.com) and recreate the container. It is the most common mistake when publishing Vikunja: the proxy works, but the frontend still points to localhost and login fails.
Frequently asked questions
Do I really need PostgreSQL or is SQLite enough?
For a personal, low-use instance, SQLite (the default backend) works with no configuration: it is stored in a file inside the volume. But if you are going to be several users, or you want more robust backups and better performance with many tasks, a PostgreSQL database in its own container is the recommended option, and it is the one we used in the docker-compose.yml above.
Why should I not use the image’s latest tag?
Because :latest changes without warning, and a major update could introduce database migrations or configuration changes during a simple restart. By pinning vikunja/vikunja:2.3.0 you decide when you update: you read the release notes first, take a backup and only then bump the tag. Version 2.3.0 was released in April 2026 with 277 commits and several security fixes.
How do I back up Vikunja?
You need two pieces: the database dump and the attachments folder. Export PostgreSQL with pg_dump and copy the ./files bind mount, where the files you attach to tasks live:
docker compose exec db pg_dump -U vikunja vikunja > vikunja-db.sql
tar czf vikunja-files.tar.gz files
With those two elements you can restore the whole instance on another server.
Conclusion
With a single docker-compose.yml you have a complete, private task manager: application and database, with list, kanban, Gantt and table views, and all the data on your server. The logical next step is to publish it securely behind Nginx Proxy Manager or Traefik, set VIKUNJA_SERVICE_PUBLICURL to your domain and schedule backups of the database and attachments. From there, import your tasks from Todoist or Trello and organize your projects your way.