Get started in minutes

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

Docker 512MB RAM 1GB 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 a strong secret

You must generate a BETTER_AUTH_SECRET to sign sessions. Without it the stack refuses to boot.

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. Schedule a copy of the database file 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

Quick start with Docker Compose

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

→ Open http://localhost:8080

Method 2

Recommended — manual Docker Compose

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

services:
  api:
    image: apauldev2/yotara-api:latest
    environment:
      DATABASE_URL: /app/apps/api/data/yotara.db
      APP_BASE_URL: ${APP_BASE_URL:-http://localhost:8080/api}
      TRUSTED_ORIGINS: ${TRUSTED_ORIGINS:-http://localhost:8080}
      BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET?set a strong secret}
      HOST: 0.0.0.0
      PORT: ${PORT:-3000}
      NODE_ENV: ${NODE_ENV:-production}
      CONTENT_SECURITY_POLICY: ${CONTENT_SECURITY_POLICY:-default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; 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:latest
    depends_on:
      - api
    environment:
      CONTENT_SECURITY_POLICY: ${CONTENT_SECURITY_POLICY:-default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; 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)
$ docker compose up -d

→ Open http://localhost:8080

System requirements

Docker installed (20.10+)
512MB RAM
1GB disk space
Linux x86_64 or arm64
OpenSSL to generate a BETTER_AUTH_SECRET

That's it. No external database, no Redis, no email server required. Generate your BETTER_AUTH_SECRET with openssl rand -base64 32 and export it 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 of the SQLite file 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.