C Concierge Documentation
Docs / Start here / Deployment
Self‑host · ~20 min

Deployment guide.

From the Deploy to Cloudflare button on the README to a deployed Worker absorbing inbound messages on every channel. Cloudflare Builds handles the build and deploy from your fork; you’ll set bindings and secrets in the dashboard, register Meta and Discord apps, and wire webhooks. Plan on twenty minutes if your accounts are ready.

Audience Operators / agencies Prereqs Cloudflare · Meta · Discord Optional Razorpay Time ~20 min

Prerequisites

CF Cloudflare account

Workers, D1, KV, Queues, and Email Routing enabled. Free tier is fine to start; D1 + AI usage will be the first thing to outgrow it.

META Meta Developer app

A Facebook App with WhatsApp Business and Instagram Graph products. See Facebook app setup.

GCP Google Cloud project

For Google OAuth sign‑in. Just an OAuth 2.0 client ID: no service account needed.

DSC Discord application

For the relay bot and slash commands. Discord integration covers the bot setup.

RZP Razorpay account optional

Only if you want to sell paid credit packs. The hosted service uses this; self‑hosters often skip it.

NIX Nix optional

Cloudflare Builds installs rustup, cargo, and Node automatically — no Nix required for CI. For local dev, the flake provides a pinned shell: nix develop.

Step-by-step

  1. Fork & connect Cloudflare Builds

    The fastest path is the Deploy to Cloudflare button on the repo README. It forks ananthb/concierge into your account, creates a Worker, auto-provisions the bindings declared in wrangler.toml (D1, KV, AI, Email send-binding, Durable Objects, Queues), and connects the fork to Cloudflare Builds so future pushes deploy automatically.

    To wire it up by hand: fork the repo, then in the dashboard create a Worker named concierge and connect the fork under Workers › concierge › Settings › Builds:

    • Build command: leave default (CF Builds detects package.json and runs npm install).
    • Deploy command: npm run deploy — runs cargo install -q worker-build && wrangler deploy.

    Local dev still works the usual way: nix develop (or install cargo, wrangler, the WASM target by hand), then cargo test / wrangler dev.

  2. Bind resources in the dashboard

    Under Workers › concierge › Settings › Bindings. The Deploy button auto-provisions matching resources for most of these; you only need to attend to anything missing. Names must match the binding values in wrangler.toml.

    BindingWhat it backs
    DB → D1 conciergeSQLite for messages, rules, billing, audit log.
    KVAccount configs, sessions, persona drafts, billing state.
    AIWorkers AI (LLaMA reply generation + safety classifier).
    EMAIL (send_email)Outbound forwarding via Email Routing.
    REPLY_BUFFERReplyBufferDODurable Object: buffers inbound messages so we can reply to a batch.
    APPROVALS_DOApprovalsDODurable Object: per-tenant SSE fan-out for the approvals page.
    SAFETY_QUEUEconcierge-safety + DLQ concierge-safety-dlqPersona safety classifier pipeline. If absent, persona safety checks stay Pending and AI replies are blocked tenant-wide; static replies still work.
  3. D1 migrations run on every deploy

    The Worker carries its schema in migrations/*.sql. The npm run deploy script runs wrangler d1 migrations apply concierge --remote as part of the deploy; it’s idempotent, safe to re-run, and you don’t need to do anything for it manually.

    If you ever want to run it yourself (e.g. to apply pending migrations without redeploying), nix develop --command wrangler d1 migrations apply concierge --remote works from a local checkout.

  4. Set secrets in the dashboard

    All runtime secrets live under Workers › concierge › Settings › Variables and Secrets › Secrets. The full reference is on the configuration page; the minimum to deploy is below.

    SecretNotes
    ENCRYPTION_KEY32-byte hex (token encryption). Generate with openssl rand -hex 32.
    GOOGLE_OAUTH_CLIENT_ID / GOOGLE_OAUTH_CLIENT_SECRETSign-in.
    META_APP_ID / META_APP_SECRETShared across Facebook Login, Instagram, and WhatsApp.
    WHATSAPP_ACCESS_TOKEN / WHATSAPP_VERIFY_TOKENPlatform WABA token + webhook verifier.
    INSTAGRAM_VERIFY_TOKENInstagram DM webhook verifier.
    DISCORD_PUBLIC_KEY / DISCORD_APPLICATION_ID / DISCORD_BOT_TOKENDiscord interactions + bot.
    RAZORPAY_KEY_ID / RAZORPAY_KEY_SECRET / RAZORPAY_WEBHOOK_SECRETOnly if billing is enabled.
  5. Set runtime variables in the dashboard

    Plain-text vars live alongside the secrets, under Variables and Secrets › Variables. Set each one per-deployment:

    VariableWhat it’s for
    CF_ACCESS_TEAMYour Cloudflare Access team name (the subdomain in myteam.cloudflareaccess.com).
    CF_ACCESS_AUDApplication Audience (AUD) tag from your Access app for /manage/*.
    WHATSAPP_WABA_IDYour WhatsApp Business Account ID.
    WHATSAPP_SIGNUP_CONFIG_IDMeta Embedded Signup configuration ID.
    EMAIL_DOMAINEmail domain you control. Set MX records on its apex and add it to Cloudflare Email Routing.
    AI_MODEL / AI_FAST_MODELOptional overrides for the reply and injection-scanning models.
  6. Deploy

    Push to main. Cloudflare Builds runs npm run deploy — installs worker-build, compiles the Rust crate to WASM, applies any pending D1 migrations, runs wrangler deploy. Watch the build log under Settings › Builds; it prints the deployed Worker URL when it’s done.

    bash terminal
    git push origin main

    For an out-of-band deploy from a local checkout, nix develop --command wrangler deploy still works.

  7. Configure Meta webhooks

    In the Meta Developer Console, point both products at your Worker. Subscribe to the messages field on each.

    Webhook URLs
    WhatsApp
    https://your-domain/webhook/whatsapp
    Instagram
    https://your-domain/webhook/instagram

    The verify tokens you set in step 4 are echoed back during webhook setup. See Facebook app setup for screenshots.

  8. Set up the Discord bot

    1. Create a Discord application at discord.com/developers.
    2. Set the Interactions Endpoint URL to https://your-domain/discord/interactions.
    3. Create a bot user and copy the token into DISCORD_BOT_TOKEN.
    4. Register the slash commands /status, /domains, /rules via the Discord API.
    5. Invite the bot to your server with the appropriate permissions.

    Detailed walkthrough on the Discord integration page.

  9. Set up email routing

    Cloudflare Email Routing handles inbound mail for the domain in EMAIL_DOMAIN. To finish:

    1. In the Cloudflare dashboard, open Email Routing for your email domain.
    2. Add a catch‑all routing rule: ActionSend to a Worker → select concierge.

    See Email routing for the per-tenant address model.

  10. Set up Cloudflare Access for management

    1. In the Cloudflare dashboard, go to Zero Trust → Access → Applications.
    2. Create an application for your-domain/manage/*.
    3. Copy the Application Audience (AUD) Tag and set it as the CF_ACCESS_AUD variable under Workers › concierge › Settings › Variables and Secrets.
    4. Add a policy allowing the emails that should have management access.

    See the Management panel page.

  11. Set up Razorpay optional

    1. Create a Razorpay account and grab your API keys.
    2. Set up a webhook at https://your-domain/webhook/razorpay subscribing to payment.captured, payment.failed, subscription.activated, subscription.charged, subscription.halted, subscription.cancelled.
    3. Set the webhook secret and API keys as Worker secrets.

    See Billing for the credit‑pack model.

You’re done.

Sign in at https://your-domain/ to walk through the in‑app onboarding wizard, then send a test message to your WhatsApp number to confirm the round‑trip.