Project Management beginner ⏱ 30 minutes

Vikunja: To-Do App and Task Manager

Simple, effective task management. Lists, labels, and filters with mobile apps.

By Homelab Team • 2025-01-15
#vikunja#tasks#todo#lists#docker

Introduction

Vikunja is a beautiful, fast, and feature-rich open-source to-do list and task manager. Designed as a self-hosted alternative to Todoist, Wunderlist, and Microsoft To-Do, Vikunja offers an intuitive interface with powerful features including multiple views (list, kanban, table, gantt), subtasks, labels, filters, and team collaboration. With over 4,000 GitHub stars and active development, Vikunja has become the leading self-hosted task management solution.

Why Choose Vikunja?

Beautiful and Fast Interface

Vikunja provides a modern, responsive interface that works seamlessly on desktop, tablet, and mobile. The application is blazingly fast, with instant updates and smooth animations.

Multiple View Types

Switch between different views depending on your workflow: list view for traditional to-do lists, kanban boards for visual task management, table view for spreadsheet-like organization, gantt charts for timeline planning, and calendar view for date-based tasks.

Privacy-Focused

Your tasks, projects, and personal productivity data remain on your infrastructure. No third-party service tracks your activities, reads your tasks, or monetizes your data.

Cost Savings

Todoist costs $4-6/user/month. Microsoft To-Do is free but requires Microsoft account and collects data. Vikunja is completely free, open-source, and respects your privacy.

Rich Feature Set

Despite being self-hosted, Vikunja rivals commercial services with features like subtasks, reminders, recurring tasks, attachments, comments, team sharing, and comprehensive API.

Key Features:

  • Multiple projects (called “namespaces” and “lists”)
  • List, kanban, table, gantt, and calendar views
  • Tasks with subtasks and checklists
  • Labels, priorities, and assignees
  • Due dates and reminders
  • Recurring tasks
  • File attachments
  • Comments and activity feed
  • Team collaboration and sharing
  • Comprehensive filters and saved views
  • Bulk editing
  • Import from Todoist, Wunderlist, Microsoft To-Do
  • CalDAV support for calendar integration
  • Mobile apps (iOS and Android)
  • RESTful API
  • Webhooks
  • Multi-language support (25+ languages)

Understanding the Architecture

Vikunja has a simple, efficient architecture:

Internet/Local Network
        │
        ▼
┌───────────────┐
│ Reverse Proxy │ (Optional - Nginx, Caddy)
│  HTTPS/SSL    │
└───────┬───────┘
        │
        ▼
┌───────────────┐
│   Vikunja     │ (Combined Frontend + Backend)
│   Port 3456   │
└───────┬───────┘
        │
    ┌───┴────┐
    │        │
    ▼        ▼
┌────────┐ ┌──────┐
│Database│ │Files │
│(SQLite,│ │Upload│
│ MySQL, │ │      │
│Postgres)│ │      │
└────────┘ └──────┘

Vikunja can use SQLite (no separate database needed), MySQL, or PostgreSQL.

Prerequisites

Hardware Requirements

Minimum Configuration:

  • RAM: 512MB (perfect for personal use)
  • CPU: 1 core
  • Storage: 5GB
  • Network: Standard homelab network

Recommended Configuration:

  • RAM: 1GB (better for teams)
  • CPU: 2 cores
  • Storage: 20GB+ SSD
  • Network: Gigabit ethernet

For Teams (25+ users):

  • RAM: 2GB+
  • CPU: 2+ cores
  • Storage: 50GB+ SSD
  • Dedicated database server (PostgreSQL)

Software Requirements

  • Docker Engine v24+ with docker-compose
  • Linux (Ubuntu 22.04/24.04 LTS recommended)
  • Domain name (optional, for HTTPS and CalDAV)
  • SMTP server (optional, for email reminders)

Pre-Deployment Checklist

# Verify Docker installation
docker --version
docker compose version

# Check resources
free -h
df -h

# Test network
ping -c 3 google.com

Installation and Deployment

Step 1: Create Project Structure

# Create directory
mkdir -p ~/vikunja/{files,db}
cd ~/vikunja

# Set permissions
chmod 755 ~/vikunja

Step 2: Choose Database Backend

Option A: SQLite (Simplest - Recommended for Personal Use)

No separate database container needed. Vikunja will create SQLite file automatically.

Option B: PostgreSQL (Recommended for Teams)

Better for multi-user environments and larger datasets.

We’ll show both configurations below.

Step 3: Create Configuration File

Create config.yml:

service:
  # Service configuration
  publicurl: http://YOUR-SERVER-IP:3456
  maxitemsperpage: 50
  enableregistration: true
  enablelinksharing: true
  enabletaskattachments: true
  enabletaskcomments: true
  enabletotp: true
  enableemailreminders: true
  timezone: America/New_York

database:
  # For SQLite (simple, personal use)
  type: sqlite
  path: /db/vikunja.db

  # For PostgreSQL (teams, production)
  # type: postgres
  # host: vikunja-db
  # database: vikunja
  # user: vikunja
  # password: YOUR-SECURE-PASSWORD

auth:
  # Authentication settings
  local:
    enabled: true
  openid:
    enabled: false

mailer:
  # Email configuration (optional)
  enabled: false
  # host: smtp.gmail.com
  # port: 587
  # username: [email protected]
  # password: your-app-password
  # fromemail: [email protected]
  # skiptlsverify: false

cors:
  # CORS settings
  enable: true
  origins:
    - http://YOUR-SERVER-IP:3456

log:
  # Logging
  enabled: true
  standard: stdout
  level: INFO
  database: off
  databaselevel: WARNING

files:
  # File uploads
  basepath: /app/vikunja/files
  maxsize: 20MB

avatar:
  # Avatar settings
  gravatarexpiration: 3600

backgrounds:
  # Enable background images for lists
  enabled: true

legal:
  # Legal URLs (optional)
  imprinturl: ""
  privacyurl: ""

migration:
  # Import from other services
  todoist:
    enable: true
  wunderlist:
    enable: true
  microsofttodo:
    enable: true

Update YOUR-SERVER-IP:

SERVER_IP=$(hostname -I | awk '{print $1}')
sed -i "s/YOUR-SERVER-IP/${SERVER_IP}/g" config.yml

Step 4: Create Docker Compose Configuration

For SQLite (Simple Setup):

Create docker-compose.yml:

version: "3.8"

services:
  vikunja:
    image: vikunja/vikunja:latest
    container_name: vikunja
    restart: unless-stopped
    environment:
      VIKUNJA_SERVICE_PUBLICURL: http://YOUR-SERVER-IP:3456
      VIKUNJA_DATABASE_TYPE: sqlite
      VIKUNJA_DATABASE_PATH: /db/vikunja.db
      VIKUNJA_SERVICE_TIMEZONE: America/New_York
    volumes:
      - ./files:/app/vikunja/files
      - ./db:/db
      - ./config.yml:/etc/vikunja/config.yml:ro
    ports:
      - "3456:3456"
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3456/api/v1/info"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

For PostgreSQL (Production Setup):

Create docker-compose.yml:

version: "3.8"

services:
  vikunja-db:
    image: postgres:15-alpine
    container_name: vikunja-db
    restart: unless-stopped
    environment:
      POSTGRES_USER: vikunja
      POSTGRES_PASSWORD: CHANGE-THIS-PASSWORD
      POSTGRES_DB: vikunja
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U vikunja"]
      interval: 10s
      timeout: 5s
      retries: 5

  vikunja:
    image: vikunja/vikunja:latest
    container_name: vikunja
    restart: unless-stopped
    depends_on:
      vikunja-db:
        condition: service_healthy
    environment:
      VIKUNJA_SERVICE_PUBLICURL: http://YOUR-SERVER-IP:3456
      VIKUNJA_DATABASE_TYPE: postgres
      VIKUNJA_DATABASE_HOST: vikunja-db
      VIKUNJA_DATABASE_USER: vikunja
      VIKUNJA_DATABASE_PASSWORD: CHANGE-THIS-PASSWORD
      VIKUNJA_DATABASE_DATABASE: vikunja
      VIKUNJA_SERVICE_TIMEZONE: America/New_York
    volumes:
      - ./files:/app/vikunja/files
      - ./config.yml:/etc/vikunja/config.yml:ro
    ports:
      - "3456:3456"
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3456/api/v1/info"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

volumes:
  postgres-data:

Update configuration:

# Set your server IP
SERVER_IP=$(hostname -I | awk '{print $1}')
sed -i "s/YOUR-SERVER-IP/${SERVER_IP}/g" docker-compose.yml

# Generate secure password for PostgreSQL
PG_PASSWORD=$(openssl rand -base64 24)
sed -i "s/CHANGE-THIS-PASSWORD/${PG_PASSWORD}/g" docker-compose.yml

echo "PostgreSQL Password: ${PG_PASSWORD}"
echo "Save this password securely!"

Step 5: Deploy Vikunja

# Pull images
docker compose pull

# Start services
docker compose up -d

# Monitor startup logs
docker compose logs -f

# Wait for "Vikunja is ready" message
# Press Ctrl+C to exit

# Verify container is running
docker compose ps

Step 6: Access Vikunja

Navigate to http://YOUR-SERVER-IP:3456 in your browser.

Create your account:

  1. Click “Create an account”
  2. Enter username: your-username
  3. Enter email: [email protected]
  4. Enter password: (secure password)
  5. Confirm password
  6. Click “Sign up”
  7. You’re logged in and ready to go!

Initial Setup and Configuration

Create Your First Project

Vikunja organizes tasks into “Namespaces” and “Lists”:

  • Namespace: Top-level container (like a workspace)
  • List: Contains tasks (like a project)

Create a namespace:

1. Click "+" next to "Namespaces" in sidebar
2. Enter name: "Personal Projects"
3. Click "Create"

Create a list:

1. Click the new namespace
2. Click "+ New List"
3. Enter title: "Home Renovation"
4. Description: "Tasks for home renovation project"
5. Click "Create"

Configure List Settings

Click on list → Settings (gear icon):

General:
├─ Title and description
├─ Color: Choose identifying color
├─ Favorite: Pin to sidebar
└─ Archive: Hide completed list

Background:
├─ Upload custom background image
└─ Or choose from Unsplash integration

Sharing:
├─ Share with team members
├─ Share via link (read-only or editable)
└─ Make list public

Views:
├─ Default view: List, Kanban, Table, Gantt, Calendar
└─ This sets what view opens by default

Create Tasks

Simple task:

1. In any list, type in the "Add a new task" box
2. Press Enter
3. Task created!

Detailed task:

1. Click on a task to open details
2. Set properties:
   - Description: Add detailed notes (Markdown supported)
   - Due Date: When task is due
   - Priority: Low, Medium, High, Urgent
   - Labels: Add tags (create new or use existing)
   - Assignees: Assign to team members
   - Repeat: Set recurring pattern
   - Color: Visual identification
   - Percent Done: Track progress
3. Add subtasks:
   - Click "Add a subtask"
   - Create checklist of sub-items
4. Attachments:
   - Drag files or click to upload
   - Images, PDFs, documents
5. Relations:
   - Link related tasks
   - Block dependencies
6. Comments:
   - Add notes and updates
   - Team discussion

Use Different Views

List View (Traditional To-Do List):

- Simple vertical list of tasks
- Check boxes to complete
- Quick add at top
- Filter and sort options

Kanban View:

1. Click "Kanban" tab
2. Columns represent task status:
   - To Do
   - In Progress
   - Done
3. Drag tasks between columns
4. Add new columns for custom workflow
5. Set WIP limits per column

Table View:

- Spreadsheet-like interface
- Sort by any column
- Bulk edit multiple tasks
- Filter complex criteria
- Export to CSV

Gantt View:

- Timeline visualization
- See task dependencies
- Drag to adjust dates
- Visual project planning
- Resource allocation

Calendar View:

- Monthly/weekly calendar
- Tasks shown on due dates
- Drag to reschedule
- Integrate with CalDAV
- See all projects in one view

Set Up Labels

1. Settings → Labels (in sidebar)
2. Click "+ Create Label"
3. Configure:
   - Title: "urgent"
   - Description: "Needs immediate attention"
   - Color: Red (#ff0000)
4. Create more labels:
   - home, work, personal
   - bug, feature, enhancement
   - waiting, blocked, in-review
5. Use labels across all lists

Configure Filters

Save custom filters:

1. In any list, click "Filter"
2. Build filter:
   - Priority: High or Urgent
   - Due date: Next 7 days
   - Assignee: Me
   - Labels: work AND urgent
3. Click "Save this filter"
4. Name: "My Urgent Work Tasks"
5. Access from sidebar anytime

Team Collaboration

Share Lists with Team Members

Add team member:

1. Open list
2. Click "Share" button
3. Enter email or username
4. Select permission:
   - Read: View only
   - Write: Create and edit tasks
   - Admin: Full control including sharing
5. Click "Share"
6. User receives notification
1. List → Share → Link Sharing
2. Click "Create share link"
3. Configure:
   - Right: Read or Write
   - Name: "Client Review Link"
   - Password: Optional protection
4. Copy link
5. Share with anyone (no account needed)
6. Revoke link anytime

Team Namespaces

1. Create namespace: "Company Projects"
2. Add all team members to namespace
3. All lists in namespace are accessible
4. Separate permissions per list
5. Great for departments or teams

Comments and Activity

On any task:
1. Scroll to comments section
2. Write update or question
3. Mention team members: @username
4. They receive notification
5. View activity feed for all changes
6. Track who did what when

Mobile Apps and Integrations

Mobile Apps

iOS:

Download from App Store
Login with your Vikunja URL: http://YOUR-SERVER-IP:3456
Full feature parity with web version
Offline support for viewing tasks
Push notifications (requires configuration)

Android:

Download from Google Play or F-Droid
Login with server URL
Full offline support
Material Design interface
Widget support

CalDAV Integration

Sync tasks with calendar apps:

CalDAV URL: http://YOUR-SERVER-IP:3456/dav/
Username: your-username
Password: your-password

Compatible with:
- Apple Calendar (macOS, iOS)
- Thunderbird
- Evolution
- Any CalDAV-compatible client

Tasks appear as calendar events
Due dates sync bidirectionally

API Usage

Generate API token:

1. Settings → API Tokens
2. Click "Create a new token"
3. Label: "Automation Script"
4. Click "Create"
5. Copy token (shown once)

Example API request:

# Get all tasks
curl -H "Authorization: Bearer YOUR-TOKEN"   http://YOUR-SERVER-IP:3456/api/v1/tasks/all

# Create task
curl -X POST   -H "Authorization: Bearer YOUR-TOKEN"   -H "Content-Type: application/json"   -d '{"title":"New task","list_id":1}'   http://YOUR-SERVER-IP:3456/api/v1/lists/1/tasks

Backup Procedures

What to Backup

ComponentPriorityContains
DatabaseCriticalAll tasks, lists, users
Files directoryImportantAttachments, avatars
config.ymlImportantConfiguration

Automated Backup Script

Create ~/vikunja/backup.sh:

#!/bin/bash

# Configuration
BACKUP_DIR="/mnt/backups/vikunja"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30

mkdir -p "$BACKUP_DIR"

echo "Starting Vikunja backup at $(date)"

# For SQLite
if [ -f ~/vikunja/db/vikunja.db ]; then
    cp ~/vikunja/db/vikunja.db "$BACKUP_DIR/vikunja-${DATE}.db"
    gzip "$BACKUP_DIR/vikunja-${DATE}.db"
    echo "SQLite database backed up"
fi

# For PostgreSQL
if docker ps | grep -q vikunja-db; then
    docker exec vikunja-db pg_dump -U vikunja vikunja |       gzip > "$BACKUP_DIR/vikunja-db-${DATE}.sql.gz"
    echo "PostgreSQL database backed up"
fi

# Backup files
tar czf "$BACKUP_DIR/vikunja-files-${DATE}.tar.gz"   -C ~/vikunja files/

# Backup config
cp ~/vikunja/config.yml "$BACKUP_DIR/config-${DATE}.yml"

# Clean old backups
find "$BACKUP_DIR" -name "*.gz" -mtime +$RETENTION_DAYS -delete
find "$BACKUP_DIR" -name "*.db" -mtime +$RETENTION_DAYS -delete
find "$BACKUP_DIR" -name "*.yml" -mtime +$RETENTION_DAYS -delete

echo "Backup completed at $(date)"

Schedule backups:

chmod +x ~/vikunja/backup.sh

crontab -e
# Add: 0 3 * * * /home/user/vikunja/backup.sh >> /var/log/vikunja-backup.log 2>&1

Restore from Backup

SQLite:

cd ~/vikunja
docker compose down
gunzip < /mnt/backups/vikunja/vikunja-YYYYMMDD.db.gz > db/vikunja.db
tar xzf /mnt/backups/vikunja/vikunja-files-YYYYMMDD.tar.gz -C .
cp /mnt/backups/vikunja/config-YYYYMMDD.yml config.yml
docker compose up -d

PostgreSQL:

cd ~/vikunja
docker compose down
docker compose up -d vikunja-db
sleep 10
gunzip < /mnt/backups/vikunja/vikunja-db-YYYYMMDD.sql.gz |   docker exec -i vikunja-db psql -U vikunja vikunja
tar xzf /mnt/backups/vikunja/vikunja-files-YYYYMMDD.tar.gz -C .
docker compose up -d

Troubleshooting

Issue: Can’t Access Web Interface

# Check container status
docker compose ps

# View logs
docker compose logs vikunja

# Check port availability
sudo netstat -tlnp | grep :3456

# Restart Vikunja
docker compose restart vikunja

Issue: Database Connection Failed

# For SQLite - check permissions
ls -la ~/vikunja/db/
chmod 644 ~/vikunja/db/vikunja.db

# For PostgreSQL - verify database is ready
docker compose logs vikunja-db

# Test database connection
docker exec vikunja-db psql -U vikunja -c "SELECT 1"

# Restart in correct order
docker compose restart vikunja-db
sleep 10
docker compose restart vikunja

Issue: File Upload Failing

# Check files directory permissions
ls -la ~/vikunja/files/
chmod 755 ~/vikunja/files/

# Check max file size in config.yml
# Should be: maxsize: 20MB or higher

# Check disk space
df -h

# Restart Vikunja
docker compose restart vikunja

Issue: Mobile App Can’t Connect

# Verify Vikunja is accessible from mobile device
# From mobile browser, visit: http://YOUR-SERVER-IP:3456

# Check firewall rules
sudo ufw status
sudo ufw allow 3456/tcp

# Verify correct URL in mobile app
# Use IP address, not localhost

# For HTTPS, ensure valid certificate

Issue: CalDAV Sync Not Working

# Verify CalDAV is enabled in config.yml

# Test CalDAV endpoint
curl http://YOUR-SERVER-IP:3456/dav/

# Check credentials
# Username: your-vikunja-username (not email)
# Password: your-vikunja-password

# For iOS Calendar:
# Server: YOUR-SERVER-IP:3456
# Path: /dav/
# Username: username (without @)

Import from Other Services

Import from Todoist

1. Todoist → Settings → Integrations → Export
2. Download backup file
3. Vikunja → Settings → Migration
4. Select "Todoist"
5. Upload backup file
6. Click "Import"
7. All tasks, projects, labels imported

Import from Microsoft To-Do

1. Settings → Migration → Microsoft To-Do
2. Click "Authenticate with Microsoft"
3. Login to Microsoft account
4. Grant permissions
5. Select lists to import
6. Click "Import"

Import from Wunderlist

1. Download Wunderlist export file (if available)
2. Settings → Migration → Wunderlist
3. Upload export file
4. Map Wunderlist folders to Vikunja lists
5. Import

Advanced Configuration

Enable Email Reminders

Update config.yml:

mailer:
  enabled: true
  host: smtp.gmail.com
  port: 587
  username: your-[email protected]
  password: your-app-password
  fromemail: [email protected]
  skiptlsverify: false

Restart Vikunja:

docker compose restart vikunja

Configure HTTPS

Using Caddy reverse proxy:

Create Caddyfile:

vikunja.yourdomain.com {
    reverse_proxy vikunja:3456
    encode gzip
}

Update config.yml:

service:
  publicurl: https://vikunja.yourdomain.com

Disable Public Registration

After creating accounts:

service:
  enableregistration: false

Only admin can create users via CLI:

docker exec -it vikunja ./vikunja user create   --username newuser   --email [email protected]   --password securepass

Conclusion

Vikunja provides a powerful, beautiful task management experience with complete privacy and control. Whether for personal productivity or team collaboration, Vikunja delivers enterprise features without the enterprise cost.

What You’ve Accomplished:

  • Deployed Vikunja with your choice of database
  • Created projects and organized tasks
  • Explored multiple view types (list, kanban, gantt, calendar)
  • Set up team collaboration and sharing
  • Configured mobile apps and CalDAV sync
  • Implemented automated backups
  • Learned import from commercial services

Next Steps:

  1. Import existing tasks from Todoist or Microsoft To-Do
  2. Set up CalDAV for calendar integration
  3. Install mobile apps for on-the-go access
  4. Configure email reminders
  5. Set up HTTPS for secure access
  6. Create automation with API
  7. Train team on advanced features

Start managing your tasks with the freedom and simplicity of self-hosting!