{
  "slug": "install/docker",
  "title": "Install with Docker",
  "description": "Deploy Cuitty on a single VM using Docker Compose. Recommended for solo developers and small teams.",
  "url": "https://cuitty.com/docs/install/docker",
  "markdown_url": "https://cuitty.com/docs/install/docker.md",
  "json_url": "https://cuitty.com/docs/install/docker.json",
  "frontmatter": {
    "title": "Install with Docker",
    "description": "Deploy Cuitty on a single VM using Docker Compose. Recommended for solo developers and small teams.",
    "order": 1,
    "section": "Install",
    "updatedAt": "2026-04-27"
  },
  "headings": [
    {
      "depth": 1,
      "slug": "install-with-docker-compose",
      "text": "Install with Docker Compose"
    },
    {
      "depth": 2,
      "slug": "reference-compose-file",
      "text": "Reference compose file"
    },
    {
      "depth": 2,
      "slug": "backups",
      "text": "Backups"
    },
    {
      "depth": 2,
      "slug": "upgrades",
      "text": "Upgrades"
    },
    {
      "depth": 2,
      "slug": "see-also",
      "text": "See also"
    }
  ],
  "body_markdown": "# Install with Docker Compose\n\nDocker Compose is the fastest way to run Cuitty in production-like conditions on a single VM. The reference compose file lives at the root of the `cuitty` repo.\n\n## Reference compose file\n\n```yaml\nversion: \"3.9\"\n\nservices:\n  postgres:\n    image: postgres:16\n    environment:\n      POSTGRES_USER: cuitty\n      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}\n      POSTGRES_DB: cuitty\n    volumes:\n      - pgdata:/var/lib/postgresql/data\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U cuitty\"]\n      interval: 5s\n      timeout: 3s\n      retries: 12\n\n  spicedb:\n    image: authzed/spicedb:latest\n    command: serve --grpc-preshared-key ${SPICEDB_PRESHARED_KEY}\n    ports:\n      - \"50051:50051\"\n\n  portal:\n    image: ghcr.io/cuitty/portal:latest\n    depends_on:\n      postgres: { condition: service_healthy }\n      spicedb: { condition: service_started }\n    ports:\n      - \"7700:7700\"\n    environment:\n      DATABASE_URL: postgres://cuitty:${POSTGRES_PASSWORD}@postgres:5432/cuitty\n      SPICEDB_URL: spicedb:50051\n      SPICEDB_TOKEN: ${SPICEDB_PRESHARED_KEY}\n      BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET}\n\nvolumes:\n  pgdata:\n```\n\nCreate a `.env` file with `POSTGRES_PASSWORD`, `SPICEDB_PRESHARED_KEY`, and a 32-byte random `BETTER_AUTH_SECRET`. Then:\n\n```bash\ndocker compose up -d\n```\n\n## Backups\n\nThe portal stores nothing important on its own filesystem — every byte that matters lives in the `postgres` and `libsql` volumes. Snapshot the named volumes nightly with `pg_dump` and a `tar` of the libSQL data directory.\n\n## Upgrades\n\n```bash\ndocker compose pull portal\ndocker compose up -d portal\n```\n\nThe portal runs migrations on startup. Always snapshot first.\n\n## See also\n\n- [Install on Kubernetes](/docs/install/kubernetes)\n- [Install on bare metal](/docs/install/bare-metal)\n- [Install on cloud providers](/docs/install/cloud)",
  "links_out": [
    "/docs/install/kubernetes",
    "/docs/install/bare-metal",
    "/docs/install/cloud"
  ]
}