Free on Cloudflare · AGPL-3.0

Pitch your
own camp.

Everything runs on Cloudflare's free tier. Fork the repo, set a few variables, run one workflow — then connect your channels.

1 D1 database 2 KV namespaces 1 GitHub workflow 4 admin secrets
  1. Cloudflare

    Create the resources

    One D1 database and two KV namespaces. Use the dashboard (Storage & Databases → D1 and KV) or the CLI, and note the three ids.

    terminal
    npx wrangler d1 create kervly-db
    npx wrangler kv namespace create kervly-oauth
    npx wrangler kv namespace create kervly-sessions
  2. GitHub

    Set secrets and variables

    Fork the repository, then open Settings → Secrets and variables → Actions. Keeping ids out of the code means your fork carries nothing personal.

    CLOUDFLARE_API_TOKENSecret · Workers Scripts, D1 and KV edit
    CLOUDFLARE_ACCOUNT_IDSecret · from the dashboard home
    D1_DATABASE_IDVariable · required
    KV_OAUTH_IDVariable · required
    KV_SESSIONS_IDVariable · required
    CUSTOM_DOMAINVariable · optional, zone on Cloudflare
  3. Deploy

    Run the workflow

    Actions → Deploy → Run workflow. Every later push to main redeploys automatically and applies database migrations.

    github actions● deploy
    ✓ Typecheck and tests
    ✓ Render deployment config
    ✓ Database migrations
    ✓ Deploy
  4. Admin

    Password + 2FA

    Open your Kervly URL — you're sent to /setup. Choose a password of at least 12 characters and generate the values in your browser. Add them as Cloudflare secrets, then add the TOTP secret to your authenticator app.

    ADMIN_PASSWORD_HASH
    ADMIN_TOTP_SECRET
    ENCRYPTION_KEY
    CONSENT_SECRET
    If ENCRYPTION_KEY changes, stored platform connections can't be decrypted and must be reconnected.
  5. Brands

    Draw the allowlist

    In the dashboard: Brands → New brand. Set an id, a name, the folders your videos are served from, a daily limit and a time zone. Kervly will only ever publish .mp4 files under these prefixes.

    video allowlist
    https://raw.githubusercontent.com/you/videos/main/clips/
  6. Platforms

    Create one app per platform

    Each brand then connects its own accounts with Connect in the dashboard.

    1. Google Cloud Console: create a project and enable YouTube Data API v3.
    2. Google Auth Platform: audience External, scope youtube.upload, add yourself as a test user, then publish the app to production.
    3. Create a Web application client with redirect URI <URL>/connect/youtube/callback.
    4. Add Cloudflare secrets GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.
    5. Dashboard → select brand → YouTube → Connect.
    In Testing mode refresh tokens expire after 7 days. Unverified projects may keep uploads private until you submit the free audit form.
  7. MCP

    Hand the reins to your agent

    In Claude: Settings → Connectors → Add custom connector. Click Connect, sign in with password and 2FA, and click Allow.

    connector url
    https://<your-worker>.<subdomain>.workers.dev/mcp

    “List my Kervly brands, then schedule https://…/clip.mp4 for YouTube and TikTok tomorrow at 10:00 Istanbul time.”

Full details, including every variable: SELF_HOSTING.md · Türkçe

Troubleshooting

When the road gets rough.

The platform’s client id or secret is missing. Add both as Cloudflare secrets.

Rather skip the setup?

Kervly Cloud does all of this for you.

No Cloudflare account, no GitHub workflow, no developer apps. Same open-source Kervly.

See Cloud plans →