This walkthrough takes you from zero to a fully deployed Simple Agent Manager
on your own Cloudflare account. We'll generate your config and secrets right here
in your browser — nothing is ever sent anywhere.
Cloudflare account
Workers Paid plan ($5/mo) for Durable Objects, plus Analytics Engine enabled (free).
GitHub account
Free tier. Used for authentication and the GitHub Actions deploy pipeline.
A domain on Cloudflare
Any registrar. Use a top-level domain (e.g. example.com), not a subdomain.
You don't need a cloud provider account to start. SAM is bring-your-own-cloud —
you (and your users) add Hetzner, Scaleway, or GCP credentials later through the Settings UI.
Step 1
Your domain
Enter the domain you'll use for SAM. This becomes your BASE_DOMAIN and powers
every URL and secret we generate from here on.
Enter a valid top-level domain, e.g. example.com.
Prefixes your Cloudflare resource names. Defaults to sam if left blank.
Use a top-level domain. Cloudflare's free Universal SSL covers *.example.com
but not nested wildcards like *.sam.example.com. The root domain itself isn't used —
only api., app., and *. subdomains are created.
We'll use these URLs
App
API
Workspaces
Why a top-level domain?
SAM hands every part of your deployment its own hostname — app. for the
dashboard, api. for the control plane, and a throwaway ws-…
subdomain for each running agent. Cloudflare's free wildcard certificate covers
*.example.com, so a top-level domain gets all of them secured automatically.
Point SAM at a nested subdomain like sam.example.com instead and that
wildcard no longer applies — every workspace you spin up would come up without HTTPS.
Step 2
Fork the repository
SAM deploys from your own fork. Pushing to main triggers the GitHub Actions
pipeline that provisions everything via Pulumi.
Keep the fork under the account or organization where you want the deploy to run. You'll
configure its production environment in Step 7.
Why fork instead of using a hosted service?
There's no hosted SAM to sign up for — your fork is your deployment.
Pushing to main is what triggers the GitHub Actions pipeline that
provisions and ships everything onto your own Cloudflare account. You own the code,
the infrastructure, and the data end to end.
Forking (rather than cloning) keeps the link to upstream, so you can pull in new SAM
releases on your own schedule instead of being upgraded out from under you.
Step 3
Create a Cloudflare API token
In the Cloudflare dashboard, go to My Profile → API Tokens → Create Custom Token
and grant exactly these permissions:
Set Zone Resources to your domain and Account Resources to your account.
Also enable Analytics Engine (free): Workers & Pages → Analytics Engine → Enable.
Paste the generated values so we can assemble your final secrets in Step 7:
Token and secret fields are never persisted to your browser storage — they live only in this tab until you close it.
What does each permission actually do?
This one token lets your deploy pipeline build the whole stack on Cloudflare. Each permission maps to a concrete piece of your instance:
D1 · KV · R2 · Workers Scripts Your control plane — the database, login sessions, file & attachment storage, and the API + app Workers themselves.
Cloudflare Pages Hosts the web dashboard your team logs into.
DNS · Workers Routes Auto-creates the api., app., and per-workspace ws-… hostnames and points each at the right Worker.
SSL and Certificates Issues the Origin CA certificate so Cloudflare trusts the agent VMs you provision.
AI Gateway Only used if you turn on SAM-managed AI — it meters and routes your agents' LLM traffic. Skip it entirely if everyone brings their own API keys.
Containers Optional — an experimental Cloudflare-native runtime for lightweight agent workloads. Most agents run in your own BYOC clouds, so you can skip this unless you want to try the experimental runtime.
Workers Observability (read-only) Powers the in-app logs and error views so you can debug your own instance.
Zone (read-only) Lets Pulumi look up your domain. It never changes zone settings.
Analytics Engine (enabled separately, free) feeds SAM's own usage and
cost dashboards — useful when you're running a team and want to see what your agents
spend. For a solo instance it's entirely optional.
Step 4
Create your GitHub App
We'll pre-fill every setting using your domain. Click through to GitHub, paste the one
webhook secret we generate, and create the app.
Why your own GitHub App — and how agent permissions work
This GitHub App is yours — it's how SAM logs you in and how your
agents reach your code. Whenever an agent runs, SAM mints a short-lived token from
this App, so the App's permissions are the hard ceiling on what any agent can
ever do.
You can dial an individual agent down later in the SAM UI, but never
up past what the App grants. So enable everything you might want an
agent to do here, then restrict per-agent as needed. If there's a scope you never want
an agent to touch, leave it off the App entirely.
On the GitHub form, leave "Request user authorization (OAuth) during installation"unchecked. Checking it disables the Setup URL and breaks post-install redirects.
Exactly as it appears in the URL.
Pre-filled settings
Webhook secret
GitHub can't pre-fill this. Copy it into the Webhook secret field on the form:
We base64-encode this locally for GH_APP_PRIVATE_KEY.
The Client Secret and Private Key are never persisted to your browser storage — they live only in this tab until you close it.
Step 5
Create an R2 API token
Separate from your main token, this one stores Pulumi state. In the Cloudflare dashboard:
R2 → Manage R2 API Tokens → Create with Object Read & Write permissions.
These feed Pulumi's remote state backend. Like all secrets here, they stay in this tab only.
Why a second, separate token?
Pulumi records the state of your infrastructure — what exists, resource IDs, and
encrypted secrets — in an R2 bucket so every deploy is repeatable and survives a fresh
machine or CI runner.
This token is deliberately narrower than your main Cloudflare one: object read &
write on that single state bucket is all it ever needs, so it's safe to scope tightly.
Step 6
Generate a Pulumi passphrase
Pulumi encrypts your stack secrets with this passphrase. Save it — you'll need
the exact same value for every future deployment.
PULUMI_CONFIG_PASSPHRASE
Prefer to generate it yourself?
Run this in your terminal and use that value instead:
openssl rand -base64 32
Why a passphrase, and why save it?
Your Pulumi state holds secrets, so Pulumi encrypts them with this passphrase before
writing to R2 — anyone who reads the bucket still can't decrypt them.
There's no reset. Lose it and you can't update or tear down your stack, so save it in
your password manager now. Every future deploy must reuse the exact same value.
Step 7
Configure the production environment
In your fork: Settings → Environments → New environment → production.
Add the variables and secrets below. We've filled in everything you entered.
Environment variables
Environment secrets
Faster: set everything with the GitHub CLI
Already have GitHub CLI
installed and authenticated? Drop in your fork's repo and run one command to set every variable
and secret on the production environment at once.
Add your repo above and the command will target it directly. Without it, run the command from
inside a clone of your fork.
The command includes your secret values in plain text — run it in a trusted terminal and clear
your shell history afterward if you're cautious.
Security keys (ENCRYPTION_KEY, JWT_*), Origin CA credentials, and
TRIAL_CLAIM_TOKEN_SECRET are generated automatically by Pulumi — no manual setup.
GH_* secrets are mapped to GITHUB_* Worker secrets at deploy time.
Optional: Google OAuth (for GCP provider support)
Only needed if your users will deploy VMs on GCP. Add GOOGLE_CLIENT_ID and
GOOGLE_CLIENT_SECRET as environment secrets.
Why a GitHub Environment?
Your deploy pipeline reads its config from a named GitHub Environment rather than plain
repo secrets. That keeps your deploy credentials in one place you can lock down later
with required reviewers or branch protections — handy once more than one person can
push.
Variables are non-sensitive config (your domain, account IDs).
Secrets are credentials GitHub encrypts and never shows you again
after saving — so keep your own copy of anything you generated here.
Step 8
Deploy & verify
No commit needed — just run the Deploy Production workflow in your fork.
Open it, click Run workflow, and choose the main branch. Pulumi
provisions D1, KV, R2, and DNS, deploys the Worker and web UI, runs migrations, and builds
the VM agent.
Add your fork in Step 7 and this button links straight to its Run-workflow screen.
Verify the API is healthy
Then open — you should see the login page.
What happens when you deploy?
One push runs the whole pipeline: Pulumi provisions D1, KV, R2, and DNS, deploys the
Worker and dashboard, runs database migrations, and builds the VM agent your
workspaces boot from.
Re-running it later is safe — Pulumi compares your config to what's already live and
only applies what changed, so routine deploys are fast and won't touch untouched
resources.
That's it — you're self-hosting SAM.
Once your deploy finishes, log in to your own dashboard and create your first workspace.