Self-host & operators
Install Habla (self-host)
This runbook is for platform operators standing up a self-hosted Habla deployment — from a fresh server to one admin account, one published agent, and the widget answering on a test page. Expect 20–40 minutes if your server is already provisioned with PHP, Node, a database, and Redis.
Use this page as the checklist. Detailed references live in the Environment variables, Deployment, Artisan commands, Observability, Architecture, and Platform admin guides.
Installation checklist
- Server requirements — see below.
- Get the deployment package / private repo — unpack or clone into your document root.
- Configure database +
.env— see step 3–4; full key reference in Environment variables. - Run migrations —
php artisan migrate --forceandPlanSeeder. - Build frontend —
npm ci,npm run build,npm run build:widget. - Start Octane / Horizon / Reverb — supervised processes; see step 6 and Deployment.
- Configure scheduler — host cron for
schedule:run; see step 7. - Choose queue architecture — Horizon (normal) or Cloudflare Cron fallback; see step 7.
- Create first admin — register, then
php artisan pitchbar:make-admin; see Platform admin. - System keys + smoke test — paste keys in Settings → System, then verify agent + queue health.
1. Server requirements
| Component | Minimum |
|---|---|
| PHP | 8.3+ (8.4 recommended) with standard Laravel extensions |
| Composer | 2.6+ |
| Node.js | 20+ |
| Database | PostgreSQL 14+ or MySQL 8.0+ |
| Redis | 7+ — cache, sessions, queue |
| TLS + SMTP | HTTPS origin; outbound mail for auth and notifications |
You'll also need at least one LLM provider (Cloudflare Workers AI recommended) and a vector store (Cloudflare Vectorize or self-hosted Qdrant). Stack layout: Architecture.
2. Get the deployment package
Unpack the deployment package provided by your platform operator, or clone your private repository. From the project root:
cd /var/www/pitchbar # or your deploy path
composer install --no-dev --optimize-autoloader
cp .env.example .env
php artisan key:generate
Back up APP_KEY immediately — encrypted
app_settings values depend on it. See
APP_KEY rotation before
rotating in production.
3. Database + environment
Create the database, then set the connection block in
.env:
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=pitchbar
DB_USERNAME=pitchbar
DB_PASSWORD=…strong-password…
Set boot-required keys (APP_URL, Redis,
QUEUE_CONNECTION=redis, WIDGET_JWT_SECRET,
Reverb, mail) before opening the admin. Every variable, LLM provider
key, and INTERNAL_QUEUE_TOKEN rule is documented in
Environment variables.
4. Migrations and plans
php artisan migrate --force
php artisan db:seed --class=PlanSeeder --force
Skip UserSeeder in production — it
creates public demo accounts. Edit plan pricing at
/admin/plans after seeding.
5. Build frontend bundles
npm ci
npm run build
npm run build:widget
php artisan storage:link
php artisan optimize
Release packages may ship pre-built assets; rebuilding on the server guarantees bundles match the deployed PHP. Build troubleshooting: Deployment.
6. Octane, Horizon, and Reverb
Habla runs on Laravel Octane + FrankenPHP, Horizon for queues, and Reverb for realtime inbox / handoff. On a single host, supervise three systemd units (names are fixed identifiers):
pitchbar-app.service— Octane / FrankenPHPpitchbar-horizon.service— queue workerpitchbar-reverb.service— WebSocket server
sudo systemctl enable --now pitchbar-app pitchbar-horizon pitchbar-reverb
Unit file examples, TLS reverse proxy, sizing, and CI/CD:
Deployment.
Queue dashboard: /admin/queue-health —
Site health & failed jobs.
7. Scheduler and queue architecture
Self-hosted Habla needs both a Laravel scheduler and a queue worker. They are not interchangeable.
Laravel scheduler (required)
* * * * * cd /var/www/pitchbar && php artisan schedule:run >> /dev/null 2>&1
Queue worker — normal production vs fallback
Normal production (Option A): Redis +
Horizon as a supervised daemon (step 6). Leave
INTERNAL_QUEUE_TOKEN empty when Horizon is running.
Fallback only (Option B): when no persistent queue
daemon exists, deploy the Cloudflare Cron Worker via
Settings → System → Cron worker. It POSTs to
/api/v1/internal/queue-tick with
INTERNAL_QUEUE_TOKEN. Use only when Horizon is
not running.
Tick semantics, monitoring, and Sentry / OTEL wiring: Deployment and Observability. CLI reference: Artisan commands.
8. First admin and system keys
Register at {APP_URL}/register, then promote your account:
php artisan pitchbar:make-admin you@example.com
As super_admin, open Settings → System
and paste Cloudflare, mail, Stripe, and other platform keys. Use each
Test button before saving. Console layout:
Platform admin.
9. Smoke test
- Visit
{APP_URL}/admin— no error banners. - Settings → System — mail, LLM, and Stripe tests pass.
- Run the Quickstart in your workspace: index one page, publish, embed on a test site.
/admin/queue-health— queues draining, no failed jobs.
Widget or crawl issues: Widget doesn't show, Slow replies.
What's next?
.env reference — required, optional, and admin-overridable keys.