# Quickstart (/self-hosting/quickstart)





This guide gets a signed-in deployment running first. Then it adds the services
that let agents work on repositories.

## Prerequisites [#prerequisites]

* Node.js `22.22.x` (see `.nvmrc`) and pnpm `10` through Corepack
  (`corepack enable`).
* **Docker path:** Docker with Compose, on amd64 or arm64. Compose pulls the
  published image and runs Postgres for you.
* **Vercel path:** a Postgres 17 database with the `vector` and `pg_trgm`
  extensions available. [Neon](https://neon.tech) has both.
* A public HTTPS domain for the deployment. OAuth callbacks and webhooks must
  reach it.

## 1. Get the code [#1-get-the-code]

```bash
git clone https://github.com/Mogplex/mogplex.git
cd mogplex
pnpm install
cp .env.example .env.local    # use .env for Docker
```

Fork the repository first if you plan to change code or deploy from Git. The
Docker path runs a prebuilt image; you still need the checkout to deploy the
Trigger.dev tasks and to run the setup doctor.

## 2. Configure the minimum environment [#2-configure-the-minimum-environment]

Generate each secret with `openssl rand -base64 32`, except
`CONNECTIONS_ENCRYPTION_KEY`, which must be 32 bytes of hex
(`openssl rand -hex 32`).

```bash
# Backend switches. Both must be "neon".
MOGPLEX_DATA_BACKEND=neon
NEXT_PUBLIC_MOGPLEX_DATA_BACKEND=neon

# Public URL. APP_URL is read at runtime, so one build serves any domain.
APP_URL=https://mogplex.example.com

# Database. DATABASE_URL is the owner connection that migrations use.
# Docker Compose fills these in for its own Postgres when you leave them unset.
DATABASE_URL=postgres://...
DATABASE_URL_UNPOOLED=postgres://...

# Auth
BETTER_AUTH_SECRET=...
AUTH_GITHUB_CLIENT_ID=...        # or AUTH_GOOGLE_* / AUTH_MICROSOFT_*
AUTH_GITHUB_CLIENT_SECRET=...

# Secrets the app requires
CRON_SECRET=...
INTERNAL_API_SECRET=...
CONNECTIONS_ENCRYPTION_KEY=...   # 64 hex characters
EMAIL_UNSUBSCRIBE_SECRET=...     # required in production

# Give every signed-in user platform AI and sandbox access (no Stripe needed)
MOGPLEX_SELF_HOSTED=1
```

[Database and auth](/self-hosting/database-and-auth) explains the database URLs,
the least-privilege runtime role, and each sign-in provider.

## 3. Deploy [#3-deploy]

<Tabs items="['Docker', 'Vercel']">
  <Tab value="Docker">
    ```bash
    docker compose up -d
    ```

    This pulls `ghcr.io/mogplex/mogplex:latest`. To pin a release, set
    `MOGPLEX_VERSION` in `.env`, for example `MOGPLEX_VERSION=v0.2.0`. Set
    `MOGPLEX_PORT` to serve on a host port other than 3000.

    Compose starts four services from that one image:

    | Service    | What it does                                                                                                                                                                                                                                                                                |
    | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `postgres` | Postgres 17 with pgvector, started by `COMPOSE_PROFILES=postgres` from `.env.example`. Set `POSTGRES_PASSWORD` to change the default password. To use an external database instead, set `DATABASE_URL` and `DATABASE_URL_UNPOOLED` and remove `COMPOSE_PROFILES`; no local Postgres starts. |
    | `migrate`  | Applies `neon/baseline.sql` and `neon/migrations/`, then exits. The app starts only after it succeeds.                                                                                                                                                                                      |
    | `app`      | The web app on port 3000. Its health check calls `GET /api/health`.                                                                                                                                                                                                                         |
    | `cron`     | Calls each cron route on its schedule with `Authorization: Bearer $CRON_SECRET`.                                                                                                                                                                                                            |

    Put a TLS-terminating proxy in front of port 3000.

    Some `NEXT_PUBLIC_*` values are compiled in at build time, so the published
    image leaves them unset: the Sentry DSN, the consent backend, the Vercel sign-in
    client ID, and the legacy Supabase keys. To set them, or to run unreleased code,
    build the image from your checkout instead:

    ```bash
    docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build
    ```

    Without Compose, the same image runs each role:

    ```bash
    docker run --rm --env-file .env ghcr.io/mogplex/mogplex node scripts/migrate.cjs
    docker run -d --env-file .env -p 3000:3000 ghcr.io/mogplex/mogplex
    docker run -d -e CRON_SECRET -e CRON_TARGET_URL=https://mogplex.example.com \
      ghcr.io/mogplex/mogplex node scripts/self-host-cron.mjs
    ```
  </Tab>

  <Tab value="Vercel">
    Apply migrations first, as the database owner:

    ```bash
    pnpm exec tsx --env-file=.env.local scripts/apply-neon-migrations.ts
    ```

    On an empty database, the script applies `neon/baseline.sql` first. Then it
    applies every pending file in `neon/migrations/`. Add `--dry-run` to preview.

    `vercel.json` turns off automatic Git deployments, so deploy with the Vercel CLI
    or from your own CI:

    ```bash
    vercel link                 # link to a project in your own Vercel team
    vercel env add ...          # or paste .env.local into Project → Settings → Environment Variables
    vercel deploy --prod
    ```

    To deploy on every push instead, remove `"git": { "deploymentEnabled": false }`
    from `vercel.json` in your fork. Vercel runs the cron routes for you.
  </Tab>
</Tabs>

Open the deployment and sign in. If sign-in works, the app shell is done.

## 4. Add services for agent work [#4-add-services-for-agent-work]

Add these in order. Each one is independent.

1. [GitHub App](/self-hosting/github-app): repository access, webhooks, PR
   reviews, and GitHub triggers. Create it in one step at
   `/admin/setup/github`.
2. [Background jobs](/self-hosting/background-jobs): a Trigger.dev project, on
   Trigger.dev Cloud or your own instance.
3. [Sandboxes and models](/self-hosting/sandboxes-and-models): Vercel Sandbox
   and model access, including your own OpenAI-compatible endpoint.
4. [Slack app](/self-hosting/slack-app) (optional), from the manifest in the
   repo.

## 5. Verify [#5-verify]

```bash
pnpm setup:doctor          # add --live to test credentials against the services

# Docker: run it inside the image, no checkout needed
docker compose exec app node scripts/doctor.cjs
```

The doctor reports each service as pass, warn, or fail, and links the page that
fixes each problem. It never prints secret values.

<Callout>
  Then sign in, connect GitHub, import a repository, and start a run. Confirm in
  [Observability](/web/observability) that a sandbox starts and the job
  completes.
</Callout>
