> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trypost.it/llms.txt
> Use this file to discover all available pages before exploring further.

# Installation

> Install TryPost on your server

# Installation

Step-by-step install on a bare-metal server or VM. Prefer containers? Use [Docker production](/self-hosting/docker#production-recommended-for-self-hosting) instead.

## Requirements

* PHP 8.2+ (with the extensions listed in [Requirements](/self-hosting/requirements))
* Node.js 20+
* PostgreSQL 14+ or MySQL 8+ (either works — see [choosing a database](/self-hosting/configuration#database))
* Redis 6+
* Composer 2.x

## Install

### 1. Clone the repository

```bash theme={null}
git clone https://github.com/trypostit/trypost.git
cd trypost
```

### 2. Install PHP and Node dependencies

```bash theme={null}
composer install
cp .env.example .env
php artisan key:generate
npm install
```

`php artisan key:generate` writes `APP_KEY` into `.env`. Without it the app will not boot.

### 3. Configure the environment

Edit `.env` **before** migrating. Minimum for a working self-hosted instance:

```env theme={null}
APP_URL=https://your-domain.com
APP_ENV=production
APP_DEBUG=false

SELF_HOSTED=true

DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=trypost
DB_USERNAME=postgres
DB_PASSWORD=your_password

REDIS_HOST=127.0.0.1
REDIS_PORT=6379

QUEUE_CONNECTION=redis
CACHE_STORE=redis
SESSION_DRIVER=database
BROADCAST_CONNECTION=reverb

FILESYSTEM_DISK=public
```

| Block | Why |
| - | - |
| `APP_KEY` | Already set by `key:generate` — encrypts sessions, cookies, encrypted data |
| Database | Where posts, users, and Passport clients live. The block above is PostgreSQL; for MySQL use `DB_CONNECTION=mysql` on port `3306` — see [Database](/self-hosting/configuration#database) |
| Redis + queue/cache drivers | Horizon publishes posts and processes background jobs from Redis queues |
| `BROADCAST_CONNECTION=reverb` | Live dashboard updates |
| `FILESYSTEM_DISK=public` | Local media on disk (use `s3` / `r2` / `spaces` for object storage) |
| `SELF_HOSTED=true` | Disables Stripe billing and public `/register` |

Also configure **mail** (invites / password reset) and optional social OAuth / AI keys — see [Configuration](/self-hosting/configuration).

<Tip>
  Prefer a one-liner for deps? `composer setup` runs install + `key:generate` + migrate + npm build, but it migrates **before** you edit `.env`. Safer path for a real server: follow the steps above (configure `.env`, then migrate yourself).
</Tip>

### 4. Create the database and run migrations

Migrations build the schema but not the database itself — create it first, with the name you put in `DB_DATABASE`:

```bash theme={null}
# PostgreSQL
createdb -U postgres trypost

# MySQL — utf8mb4 so emoji in posts survive
mysql -u root -p -e "CREATE DATABASE trypost CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
```

```bash theme={null}
php artisan migrate --force
```

<Note>
  On a fresh install this just builds the schema. When you run it later to **upgrade** an existing instance, back the database up first and check [Upgrading](/self-hosting/upgrading) — some releases rewrite data as well as schema.
</Note>

### 5. Passport keys (and local storage symlink)

Passport needs an RSA key pair on disk to **sign and verify** API / MCP tokens:

```bash theme={null}
php artisan passport:keys
```

Run once. Do **not** regenerate later unless you intend to invalidate every existing API token.

If you keep `FILESYSTEM_DISK=public`, also create the public media symlink:

```bash theme={null}
php artisan storage:link
```

Skip `storage:link` when using object storage (`s3`, `r2`, `spaces`) — those disks serve from the bucket URL.

### 6. Seed Passport client and admin user

Self-hosted installs close `/register`. Bootstrap the database once:

```bash theme={null}
php artisan db:seed
php artisan db:seed --class=UserSeeder
```

| Seeder | What it creates |
| - | - |
| `DatabaseSeeder` (`db:seed`) | **Passport Personal Access Client** (required to issue API tokens) + plan rows |
| `UserSeeder` | Admin account |

<Tip>
  Passport is two independent pieces:

  1. **Keys** (`passport:keys`) — files on disk
  2. **Personal Access Client** (`db:seed`) — row in `oauth_clients`

  API keys in Settings need **both**. MCP OAuth uses the same Passport keys (not API-key Bearer headers).
</Tip>

Admin credentials — **change the password immediately on first login**:

| Field | Value |
| - | - |
| Email | `admin@trypost.it` |
| Password | `password` |

Further accounts come from workspace invites (Settings → Members).

<Warning>
  Only on a brand-new empty database you may use `php artisan migrate:fresh --seed && php artisan db:seed --class=UserSeeder`. `migrate:fresh` **drops every table**.
</Warning>

### 7. Build the frontend

```bash theme={null}
npm run build
```

### 8. Run the app

**Local / smoke test** (one terminal):

```bash theme={null}
composer dev
```

This starts `php artisan serve`, a queue listener, log tail, and Vite. Open `http://localhost:8000` and sign in with the admin user.

**Production** — do **not** use `composer dev`. You need long-running processes:

| Process | Command | Purpose |
| - | - | - |
| Web (PHP-FPM + Nginx) | see [Production](/self-hosting/production#nginx-configuration) | Serve HTTP |
| **Horizon** | `php artisan horizon` | Queues — publish posts, notifications, webhooks |
| **Reverb** | `php artisan reverb:start` | WebSockets |
| **Scheduler** | cron → `php artisan schedule:run` | Due posts, token refresh, stuck-post recovery |

Full Supervisor configs, Nginx (including Reverb `/app/` + `/apps/`), SSL, and caches: [Production setup](/self-hosting/production).

## End-to-end checklist

| Step | Done when |
| - | - |
| `APP_KEY` set | `key:generate` ran |
| Database reachable | `.env` `DB_*` correct |
| Queues on Redis | `QUEUE_CONNECTION=redis` + Redis up |
| Migrations applied | `php artisan migrate` |
| Passport keys | `storage/oauth-private.key` exists |
| Passport client | `php artisan db:seed` ran |
| Admin user | `UserSeeder` ran; you can log in |
| Media (local) | `storage:link` if `FILESYSTEM_DISK=public` |
| Frontend built | `npm run build` |
| Horizon running | posts actually publish |
| Reverb + scheduler | live UI + cron jobs |
| Mail configured | invites / password reset work |

## Verify

1. Sign in at `APP_URL` with the admin credentials
2. Create an API key under workspace Settings → API Keys (fails with 500 if Passport keys or client are missing)
3. Connect an MCP client via OAuth (Settings → MCP), or call the REST API with the key above
4. Upload a media file (404s if you use `public` disk without `storage:link`)
5. Schedule a test post and confirm Horizon processes it

## Next steps

* [Configuration](/self-hosting/configuration) — mail, storage, social OAuth, AI
* [Production setup](/self-hosting/production) — Nginx, SSL, Horizon, Reverb, cron
* [Docker](/self-hosting/docker) — same stack via Compose


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.