Skip to main content

Configuration

TryPost is configured through environment variables in the .env file.

Basic Configuration

Self-Hosted Mode

SELF_HOSTED=true is the default. It bypasses everything billing-related so you never have to touch Stripe or Cashier, and it locks down public sign-ups:
  • Public registration is disabled — /register is closed so random users can’t create accounts on your instance. Bootstrap the first admin via the UserSeeder (see Seed default data and create the admin user); after that, every account comes from a workspace invite (Settings → Members).
  • No Stripe, Cashier, or CASHIER_TRIAL_DAYS configuration required
  • The LoadWorkspaceFromToken middleware skips the 402 Payment Required gate
  • Subscription gating is not enforced, so workspaces, social accounts, and members are unlimited per account
  • AI calls go straight to your configured provider; you pay the provider directly (no Cloud metering)
There’s no reason to flip this to false on a self-hosted install. The Cloud SaaS deployment is the only place that runs with billing enabled.

Multiple accounts per network

A workspace can connect as many accounts as you want on the same network — two LinkedIns, two Instagrams, and so on. There is no env flag for this. Two flavours of the same platform still collapse to one identity:
  • LinkedIn profile + LinkedIn Page
  • Instagram Standalone + Instagram (Facebook Business)
The same identity cannot sit twice. Reconnecting an account that already has a card updates that card instead of adding another. ALLOW_MULTIPLE_SOCIAL_ACCOUNTS was removed. If it is still in your .env, you can delete it — it is ignored.

Database

TryPost runs on PostgreSQL or MySQL. Every change runs the full test suite against both, so the application treats them as equals — pick the one you already know how to back up and restore. What differs is the packaging around them: MariaDB is close enough to MySQL that it may well work, but it is not tested and not something support can help with. Pick one before you have data. Moving an existing install from one engine to the other is not a dump-and-load: the two disagree on types, quoting and JSON layout, so it needs a conversion tool and a careful check afterwards. That path is neither documented nor supported.

PostgreSQL

MySQL

Create the database as utf8mb4 (see Installation) so emoji in posts survive. MySQL 8 already defaults to it; this matters on older servers and on MariaDB.
On MySQL you cannot schedule a post past 19 January 2038.TryPost’s schema stores dates in MySQL’s TIMESTAMP columns, and that type ends on 19 January 2038 — a post scheduled beyond it is rejected outright. PostgreSQL’s equivalent has no such ceiling, which is why the same schedule saves there.This only bites if you schedule more than a decade ahead. If that is part of how you work, choose PostgreSQL.

Redis

Redis is required for queues and caching.

Runtime drivers

For a working production-like stack, point the Laravel drivers at Redis / Reverb / the database:
Without Redis queues, Horizon has nothing useful to process. Without Redis cache on multi-instance deploys, scheduled jobs can double-fire.

Passport (API & MCP tokens)

Passport signs and verifies both REST API keys (Personal Access Tokens) and MCP OAuth grants. You need:
Alternatively, set PASSPORT_PRIVATE_KEY and PASSPORT_PUBLIC_KEY in .env (PEM contents) instead of key files — required for Docker production (compose.prod.yaml) and useful for secret managers / multi-node deploys. Do not regenerate keys after users have issued tokens. MCP clients authenticate with OAuth (mcp:use), not with an API key Bearer header. API keys are for the REST API only. The API reference describes your instance too — same routes, same payloads, same MCP tools. Only two things differ: the base URL is your APP_URL followed by /api, and responses reflect the settings on this page rather than the Cloud plan. GET /social-accounts can return several accounts sharing one platform value, so read it by id. See multiple accounts per network. Full install order: Installation.

Media size limits

Signed uploads are rate-limited per workspace and per IP (MEDIA_SIGNED_UPLOAD_PER_WORKSPACE_PER_MINUTE, MEDIA_SIGNED_UPLOAD_PER_IP_PER_MINUTE). If you raise the video limit, also bump PHP’s upload_max_filesize / post_max_size and any reverse-proxy body-size cap to match.

File Storage

TryPost supports local public storage and S3-compatible cloud storage. The application default is public (FILESYSTEM_DISK=public). Use object storage (S3 / R2 / Spaces) when you outgrow local disk or run multiple app instances.

Public Disk

Stores files in storage/app/public and serves them directly from ${APP_URL}/storage.
Create the symlink from public/storage to storage/app/public (once per install):
Only needed for the public disk. Object storage (s3, r2, spaces) does not use this symlink. See Laravel’s public disk documentation for more details.

AWS S3

Cloudflare R2

DigitalOcean Spaces

Other S3-Compatible Storage

Any other S3-compatible storage (MinIO, Backblaze B2, etc.) can be used with the s3 disk configuration.

Mail

TryPost sends transactional emails for post notifications, team invites, account alerts, and authentication (email verification, password reset). A working mail configuration is required. SendKit is TryPost’s official mailer — built by the same team and wired in as the default. Every new SendKit account is free and includes 3,000 transactional emails per month, which is plenty for a self-hosted TryPost instance handling post notifications, team invites, and account alerts.
  1. Create a free account at sendkit.dev
  2. Copy your API key from the SendKit dashboard
  3. Drop it into your .env:
That’s it — no DNS warm-up, no domain verification dance to get the first emails out, and the free tier doesn’t expire.

SMTP

If you’d rather use your own SMTP server:

Emails sent by TryPost

WebSockets (Reverb)

TryPost uses Laravel Reverb for real-time updates (live post status, notifications).
In production, set REVERB_SCHEME=https, set REVERB_HOST to your real public domain (e.g. app.example.com), and use a reverse proxy to handle SSL termination for WebSocket connections. REVERB_SERVER_HOST stays 0.0.0.0 so the daemon listens on all interfaces inside the box.

Social Platforms

Each social platform requires API credentials from its developer portal. See each platform guide for step-by-step setup.
Bluesky and Mastodon don’t require API credentials — they work out of the box. Telegram uses a single shared bot you create with @BotFather, and Discord uses a single shared bot application from the Discord Developer Portal — neither is a per-user OAuth app. See their credentials below.

All platform credentials

Telegram delivers /connect commands and reactions over a webhook. After setting the variables above, register it with php artisan telegram:set-webhook. The webhook URL is {APP_URL}/telegram/webhook, so APP_URL must be a public HTTPS URL Telegram can reach — re-run the command whenever it changes. The bot must be added as an administrator of each channel or group it publishes to.
Discord uses a single shared bot application (create one in the Discord Developer Portal). Use the OAuth2 Client Secret — not the application’s Public Key — for DISCORD_CLIENT_SECRET, and add the redirect URL above under OAuth2 → Redirects. The bot invite permissions and scopes are configurable via DISCORD_PERMISSIONS (default 248832) and DISCORD_SCOPES (default bot,identify,guilds). See the Discord platform guide for the full setup.

Enabling/disabling platforms

You can selectively enable or disable platforms without removing their credentials. This is useful when API credentials are pending approval or temporarily revoked.
Set any platform to false to hide it from the UI. All platforms are enabled by default. X charges much more to deliver a post that carries a link than a plain one, and its algorithm shows link posts to fewer people. With defusing on, every URL in the X version of a post is rewritten into a non-clickable form before it is published, so the address still reads normally but X no longer treats the post as a link post.
So https://www.example.com/pricing publishes as example(.)com/pricing, and https://blog.example.com.br as blog(.)example(.)com(.)br. Every dot has to break — leaving one intact still leaves a domain X can resolve and bill for. Only X is affected. The same post published to LinkedIn, Bluesky, Telegram or anywhere else keeps its links exactly as they were typed. What counts as a link:
  • Anything carrying https://, http:// or www. is rewritten on sight, whatever it ends in.
  • A bare host is rewritten only when its last label is a delegated top-level domain, which is what tells acme.com apart from Node.js. The list mirrors the full IANA root zone, so README.md and backup.zip are rewritten too — .md and .zip are real top-level domains and X links them.
  • Email addresses are left alone.
  • Dots in the path or query string are left alone.
Publishing and the post previews in the app, the API and MCP all show the same rewritten text, and the editor counts characters against it — what is counted is what X receives.
The default is off. A self-hosted install publishes through its own X app and pays its own X bill, so the saving this buys may not be worth links a reader cannot click. TryPost Cloud runs with it on.

Repurpose

Active repurposes poll Instagram and Facebook for videos published outside TryPost. The scheduler runs repurpose:poll every five minutes; each source is checked when it is due.
Raise the interval if you are close to Meta’s app-wide quota. Horizon and the scheduler must both be running or nothing is replicated.

Social login

TryPost supports sign in with Google and GitHub. Both providers are off by default — set the corresponding *_AUTH_ENABLED flag and provide credentials to surface the buttons on the login/register pages.

Google

Google login reuses the OAuth credentials from the YouTube integration, with a separate callback URL.
In the Google Cloud Console, add both callback URLs to your OAuth 2.0 client:
  • https://your-domain.com/accounts/youtube/callback (YouTube connection)
  • https://your-domain.com/auth/google/callback (Google login)

GitHub

Register a new OAuth App at github.com/settings/developers and set the Authorization callback URL to ${APP_URL}/auth/github/callback.

AI features (optional)

The Generate / Review / Create AI flows in the post editor need a configured text-generation provider. Without one, the AI buttons stay disabled. See AI Providers for the full list of supported providers, per-provider model overrides, and OpenRouter-specific gotchas.

Asset library (Unsplash & Giphy)

The Assets page exposes optional Unsplash and Giphy tabs. Configure these to enable them:
Without these keys, the Library tab still works — only the stock-photo and GIF tabs are hidden.

Analytics (optional)

PostHog

POSTHOG_ENABLED gates the entire integration — without it set to true, the keys are ignored.

Google Tag Manager

Both are optional and only needed if you want to track usage analytics.

Horizon (Queue Dashboard)

Laravel Horizon provides a dashboard to monitor your queues. Access it at /horizon.
If not set, Horizon dashboard will be inaccessible in non-local environments.

Advanced

Next Steps