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_KEYset - Database migrated
-
QUEUE_CONNECTION=redisand Redis reachable - Passport keys present (
PASSPORT_*env for Docker prod, orphp artisan passport:keyson bare metal) -
php artisan db:seed+UserSeederran -
storage:linkran ifFILESYSTEM_DISK=public -
npm run buildcompleted
Environment (production values)
VITE_REVERB_* are compiled into the frontend — run npm run build again after changing any REVERB_* value.
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 (one
social-<platform>queue per enabled network) - Sending email notifications
- Verifying channel connections and refreshing tokens
- Collecting analytics for Insights (
analyticsqueue) - Importing posts made outside TryPost and media from Google Drive, Google Photos, Canva or Unsplash (
media-importsqueue) - Polling RSS feeds (
rss-feedsqueue); repurpose sources are polled on their network’ssocial-<platform>queue - Delivering webhooks and their retries (
webhooksqueue) - Live updates to the browser (
broadcastsqueue)
config/horizon.php.
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:
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.
Two jobs also run on the scheduler to close each day’s analytics (23:30 and 00:30 UTC).
Add the Laravel scheduler to the cron of the user that runs PHP (usually
www-data), so the files it creates stay writable by php-fpm and Horizon:
WebSocket Server (Reverb)
TryPost uses Laravel Reverb for real-time updates in the app (posts created, deleted or changing status, post notes, Telegram connections and webhook delivery logs). Add a Supervisor config to keep it running: Create/etc/supervisor/conf.d/trypost-reverb.conf:
/app/ and /apps/ through Nginx as shown above.
File Permissions
Set correct permissions:storage/oauth-private.key readable only by the app user (typically mode 600).
Checklist
Make sure all of these are in place in production: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
.envfile- Passport keys (
storage/oauth-*.keyorPASSPORT_*env) — losing them invalidates API keys and MCP OAuth grants - Uploaded media (if using local storage)
migrate --force. The commands below read the database credentials from environment variables. On bare metal, load them from .env first, from the app directory: set -a; . ./.env; set +a. Inside the bundled Compose stack the app container already has them.
PostgreSQL
docker compose -f compose.prod.yaml exec app runs either one as written — as does php artisan db for an interactive session.
The image carries
mysql-client alongside pdo_mysql, so the MySQL commands run inside the container.
