Get started in minutes

Deploy Yotara on your own server. No vendor lock-in, no data leaving your infrastructure.

Upgrading an existing instance? The Archive tab is now called Completed — your tasks and their history are unchanged.

Docker 512MB RAM 2GB disk Linux x86_64 / arm64

Before you start

Self-hosting is a small, one-time setup — but it does ask a few things of you. Make sure you're comfortable with these before you begin.

Set two keys

You must generate a BETTER_AUTH_SECRET to sign sessions, and a free Resend API key for verification and password-reset emails. Without either, the stack refuses to boot in production.

Plan for persistence

Your data lives in a SQLite file. Keep it on a named volume or mounted path so it survives container restarts.

Back it up

You own the data, which means you own the backups. Yotara runs SQLite in WAL mode — use sqlite3 yotara.db ".backup yotara-backup.db", or copy the database while the app is stopped, and keep backups off-server.

Expose it safely

For real use, put it behind a domain with TLS. The included nginx config serves plain HTTP on port 80. Add a TLS-terminating reverse proxy (e.g. Caddy, nginx with certbot, or Cloudflare Tunnel) in front of it.

Method 1 Recommended

Quick start with Docker Compose

This downloads Yotara's maintained Compose file, pinned to the current release, and starts the stack.

$ curl -o docker-compose.yml \
  https://raw.githubusercontent.com/apauldev/yotara/main/docker-compose.selfhost.yml
$ export BETTER_AUTH_SECRET=$(openssl rand -base64 32)
$ export RESEND_API_KEY=re_your_key_here
$ docker compose up -d

→ Open http://localhost:8080

The API refuses to boot without a Resend API key — it powers signup verification and password resets, and the free tier is plenty for personal use. Once you've verified a sender domain with Resend, set EMAIL_FROM to match it.

Method 2

Manual Docker Compose

Create a docker-compose.yml in your project directory:

services:
  api:
    image: apauldev2/yotara-api:v0.85.3
    environment:
      DATABASE_URL: /app/apps/api/data/yotara.db
      APP_BASE_URL: ${APP_BASE_URL:-http://localhost:8080}
      FRONTEND_BASE_URL: ${FRONTEND_BASE_URL:-http://localhost:8080}
      TRUSTED_ORIGINS: ${TRUSTED_ORIGINS:-http://localhost:8080}
      TRUST_PROXY: ${TRUST_PROXY:-172.16.0.0/12}
      BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET?set a strong BETTER_AUTH_SECRET (openssl rand -base64 32)}
      HOST: 0.0.0.0
      PORT: ${PORT:-3000}
      NODE_ENV: ${NODE_ENV:-production}
      RESEND_API_KEY: ${RESEND_API_KEY:-}
      EMAIL_FROM: ${EMAIL_FROM:-noreply@email.yotara.website}
      CONTENT_SECURITY_POLICY: ${CONTENT_SECURITY_POLICY:-default-src 'self'; script-src 'self' https://static.cloudflareinsights.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self' https://cloudflareinsights.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'}
    volumes:
      - yotara_api_data:/app/apps/api/data
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    read_only: true
    tmpfs:
      - /tmp

  frontend:
    image: apauldev2/yotara-frontend:v0.85.3
    depends_on:
      - api
    environment:
      CONTENT_SECURITY_POLICY: ${CONTENT_SECURITY_POLICY:-default-src 'self'; script-src 'self' https://static.cloudflareinsights.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self' https://cloudflareinsights.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'}
    ports:
      - "8080:80"

volumes:
  yotara_api_data:

Then run:

$ export BETTER_AUTH_SECRET=$(openssl rand -base64 32)
$ export RESEND_API_KEY=re_your_key_here
$ docker compose up -d

→ Open http://localhost:8080

System requirements

Docker installed
Docker Compose installed
512MB RAM
2GB disk space
Linux x86_64 or arm64
OpenSSL to generate a BETTER_AUTH_SECRET
A free Resend API key for verification and reset emails

That's it — no external database, no Redis, and no mail server to run (email delivery uses Resend's free tier). Generate your BETTER_AUTH_SECRET with openssl rand -base64 32 and export it, along with your RESEND_API_KEY, before docker compose up.

Production checklist

Happy with the quick start? Before you rely on it day to day, run through this list.

  • Use a strong, unique BETTER_AUTH_SECRET and keep it out of version control and shell history.
  • Serve over HTTPS with a real domain and a valid certificate — the stack ships security headers, but TLS is on you.
  • Persist the database on a named volume (the Compose file does this) or a backed-up mount.
  • Automate backups with sqlite3 yotara.db ".backup yotara-backup.db" (WAL-safe) or a copy taken while the app is stopped, and test a restore occasionally.
  • Pin your image tag for reproducible upgrades, then review the changelog before bumping.
  • Restrict network access with a firewall; only expose what you intend.