Skip to main content

Production Setup

This guide is for bare metal / a VM after you have completed Installation (app key, .env, migrations, Passport keys, seed, frontend build). Prefer containers? Use compose.prod.yaml — it already runs Horizon, Reverb, and the scheduler for you.

Before you continue

Confirm the install checklist is done:
  • APP_KEY set
  • Database migrated
  • QUEUE_CONNECTION=redis and Redis reachable
  • Passport keys present (PASSPORT_* env for Docker prod, or php artisan passport:keys on bare metal)
  • php artisan db:seed + UserSeeder ran
  • storage:link ran if FILESYSTEM_DISK=public
  • npm run build completed

Environment (production values)

See Configuration for mail, object storage, and social OAuth.

Optimizations

Run these commands after deployment:

Queue Worker

TryPost uses queues for critical background processing:
  • Publishing posts to social platforms at scheduled times
  • Sending notifications (email and in-app)
  • Verifying social account connections
  • Processing analytics events
  • Delivering webhooks and their retries
Without a running queue worker, scheduled posts will not be published. Use Supervisor to keep Horizon running.

Install Supervisor

Configure Supervisor

Create /etc/supervisor/conf.d/trypost-worker.conf:
Then start it:

Nginx Configuration

Example Nginx configuration:
Both /app/ (browser WebSocket) and /apps/ (Pusher HTTP API) must be proxied to Reverb. Omitting /apps/ causes flaky real-time updates.

SSL Certificate

Use Let’s Encrypt for free SSL:

Scheduled Tasks (Cron)

TryPost uses Laravel’s task scheduler for several recurring jobs. The scheduler must run every minute or scheduled posts won’t publish, expiring tokens won’t refresh, and stuck posts won’t recover. Add the Laravel scheduler to cron:
Add this line:
This is required. Without the cron job, scheduled posts will not be published automatically and social tokens will expire silently.

WebSocket Server (Reverb)

TryPost uses Laravel Reverb for real-time updates in the dashboard (live post status changes, notifications). Add a Supervisor config to keep it running: Create /etc/supervisor/conf.d/trypost-reverb.conf:
Then reload Supervisor:
Proxy /app/ and /apps/ through Nginx as shown above.

File Permissions

Set correct permissions:
Keep storage/oauth-private.key readable only by the app user (typically mode 600).

Checklist

Make sure all of these are in place in production:
If Horizon, Reverb, or the scheduler are not running, TryPost will not function correctly. Scheduled posts won’t publish, notifications won’t send, and the dashboard won’t update in real time.

Monitoring

Consider setting up monitoring for:
  • Server health (CPU, memory, disk)
  • Application errors (Laravel logs in storage/logs/)
  • Queue status (Horizon dashboard at /horizon)
  • WebSocket connections (Reverb logs in storage/logs/reverb.log)

Backups

Regularly backup:
  • Database
  • .env file
  • Passport keys (storage/oauth-*.key or PASSPORT_* env) — losing them invalidates API keys and MCP OAuth grants
  • Uploaded media (if using local storage)
Upgrading asks for a database dump before every migrate --force, so it is worth having the command to hand: Both read the credentials from the app’s own environment, so they work as written wherever .env is loaded — no need to remember whether this install calls the user postgres, root or trypost. PostgreSQL
MySQL
On the bundled Compose stack the app container carries both clients and already has those variables, so docker compose -f compose.prod.yaml exec app runs either one as written — as does php artisan db for an interactive session.
mysql-client was added to the image alongside pdo_mysql; images up to and including v1.0.8 carry only the PostgreSQL client. On those, run the MySQL commands from the database host instead.