# ============================================================================= # Vikunja — Docker Compose with PostgreSQL + SMTP e-mail support # ============================================================================= # Before starting the stack run: # # mkdir -p ./files ./db # chown 1000:1000 ./files # Vikunja runs as UID 1000 # chown 999:999 ./db # PostgreSQL runs as UID 999 # # (On some systems you may need: sudo chown -R 999:999 ./db) # # Then copy .env.example → .env and fill in every value. # Start with: docker compose up -d # Test mailer: docker compose exec vikunja /app/vikunja/vikunja testmail
# ============================================================================= services: # --------------------------------------------------------------------------- # PostgreSQL database # --------------------------------------------------------------------------- db: image: postgres:18 restart: unless-stopped security_opt: - no-new-privileges:true user: "999:999" # PostgreSQL official image default UID/GID environment: POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: ${DB_NAME} volumes: # PostgreSQL 18+ requires mounting at /var/lib/postgresql (not /data subfolder) # Data will be stored in ./db/18/data automatically - ./db:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -h localhost -U $$POSTGRES_USER -d $$POSTGRES_DB"] interval: 5s timeout: 3s retries: 5 start_period: 10s # --------------------------------------------------------------------------- # Vikunja (API + frontend in one container) # --------------------------------------------------------------------------- vikunja: image: vikunja/vikunja:latest restart: unless-stopped security_opt: - no-new-privileges:true # The container defaults to UID 1000 / no group. # Adjust if your host folders need a different owner. # user: "1000:1000" ports: - "${HOST_PORT:-3456}:3456" volumes: - ./files:/app/vikunja/files # uploaded / generated files depends_on: db: condition: service_healthy # wait for postgres to be ready # ----------------------------------------------------------------------- # Environment — all sensitive values come from .env # ----------------------------------------------------------------------- environment: # --- Core service ------------------------------------------------------- VIKUNJA_SERVICE_PUBLICURL: ${PUBLIC_URL} VIKUNJA_SERVICE_JWTSECRET: ${JWT_SECRET} VIKUNJA_SERVICE_TIMEZONE: ${TIMEZONE:-UTC} VIKUNJA_SERVICE_ENABLEREGISTRATION: ${ENABLE_REGISTRATION:-true} VIKUNJA_SERVICE_ENABLETASKATTACHMENTS: "true" VIKUNJA_SERVICE_ENABLEEMAILREMINDERS: "true" # --- Database ------------------------------------------------------------ VIKUNJA_DATABASE_TYPE: postgres VIKUNJA_DATABASE_HOST: db VIKUNJA_DATABASE_USER: ${DB_USER} VIKUNJA_DATABASE_PASSWORD: ${DB_PASSWORD} VIKUNJA_DATABASE_DATABASE: ${DB_NAME} VIKUNJA_DATABASE_SSLMODE: disable # set to 'require' if TLS is enabled on PG # --- SMTP / Mailer ------------------------------------------------------- # When VIKUNJA_MAILER_ENABLED is true Vikunja sends: # • registration confirmation mails # • password-reset mails # • task-reminder mails (when ENABLEEMAILREMINDERS is also true) VIKUNJA_MAILER_ENABLED: "true" VIKUNJA_MAILER_HOST: ${SMTP_HOST} VIKUNJA_MAILER_PORT: ${SMTP_PORT:-587} VIKUNJA_MAILER_USERNAME: ${SMTP_USER} VIKUNJA_MAILER_PASSWORD: ${SMTP_PASSWORD} VIKUNJA_MAILER_FROMEMAIL: ${SMTP_FROM} VIKUNJA_MAILER_FORCESSL: ${SMTP_FORCE_SSL:-true} # wraps the connection in TLS from the start (use with port 465) VIKUNJA_MAILER_SKIPTLSVERIFY: ${SMTP_SKIP_TLS_VERIFY:-false} # set true only for self-signed certs VIKUNJA_MAILER_AUTHTYPE: ${SMTP_AUTH_TYPE:-plain} # plain | login | none # --- CORS (required when frontend & API share the same origin) ---------- VIKUNJA_CORS_ENABLE: "true" VIKUNJA_CORS_ORIGINS: ${PUBLIC_URL}