Self-Hosted Deployment Guide
Deploy the full Wraps control plane to your own AWS account. API, dashboard, database, and email infrastructure — everything in your infrastructure.
Deploy the full Wraps control plane to your own AWS account. Your API, your dashboard, your database — everything in your infrastructure with no Wraps servers in the critical path.
Self-hosting deploys the Wraps control plane API as an AWS Lambda function in your account, backed by your own Postgres database. Your team's dashboard runs on Vercel and connects to the Lambda directly — no Wraps SaaS in the loop.
Deployed into your AWS account via Pulumi — you own the function, logs, and billing
Bring any Postgres-compatible DB (Neon, Supabase, Railway, self-hosted), or let Wraps provision a Neon project automatically
Deploy apps/web from the Wraps repo to your own Vercel project
Dashboard authenticates to AWS via Vercel OIDC federation — no static keys
npm install -g @wraps.dev/cli)Run the deploy command. The CLI will walk you through selecting a region, connecting a database, and entering your license key. The control plane API is deployed as an AWS Lambda with a public function URL.
# Pass flags directly (non-interactive):wraps selfhost deploy --database-url "postgres://user:pass@your-db.example.com/wraps"wraps selfhost deploy --neon-api-key "your-key" --neon-org-id "org-..."# Or run without flags — the CLI will prompt you to choose:wraps selfhost deployThe CLI will:
https://abc123.lambda-url.us-east-1.on.aws)App URL
The --app-url flag (or prompt) should be the URL where you will deploy the dashboard — for example https://dashboard.yourdomain.com. This is used for CORS and auth redirect configuration. You can update it later if the URL is not finalised yet.
Initialise email sending with AWS SES. This creates IAM roles, configures SES, and sets up event processing for open and click tracking.
wraps email initIf you only need SMS, skip this step and run wraps sms init instead.
Generate the .env block for your Vercel dashboard deployment. This reads your local Wraps metadata and prints all required variables in KEY=value format.
wraps selfhost envThe output looks like this — copy it and keep it ready for Step 4:
DATABASE_URL=postgres://user:pass@your-db.neon.tech/wrapsNEXT_PUBLIC_APP_URL=https://dashboard.yourdomain.comNEXT_PUBLIC_API_URL=https://abc123.lambda-url.us-east-1.on.awsCORS_ORIGIN=https://dashboard.yourdomain.comBETTER_AUTH_SECRET=<generated-secret>UNSUBSCRIBE_SECRET=<generated-secret>WRAPS_LICENSE_KEY=v1.scale.2027-01-01.<fingerprint>AWS_BACKEND_ACCOUNT_ID=123456789012The Wraps dashboard lives in apps/web in the Wraps monorepo. Fork or clone the repo and deploy that directory to Vercel.
apps/web.wraps selfhost env output into Vercel → Project Settings → Environment Variables. Scope them to Production (and Preview if needed).The dashboard reads AWS resources (SES stats, CloudWatch, DynamoDB) without any stored credentials. It uses Vercel OIDC federation to obtain short-lived AWS tokens automatically.
In Vercel: go to your team's Settings → Cloud → Configure AWS. Copy the OIDC provider URL — it looks like https://oidc.vercel.com/your-team-id.
In the AWS Console, go to IAM → Identity providers → Add provider:
sts.amazonaws.comCreate a new IAM role named wraps-vercel-backend-role (or similar) with two distinct policies:
Trust policy (who can assume this role):
Replace YOUR_ACCOUNT_ID and YOUR_TEAM_ID with your AWS account ID and Vercel team ID from Step 5a:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/oidc.vercel.com/YOUR_TEAM_ID" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "oidc.vercel.com/YOUR_TEAM_ID:aud": "sts.amazonaws.com" } } } ]}Permissions policy (what this role can do):
This allows the Vercel backend role to chain-assume wraps-console-access-role, which is created automatically in Step 6 when you run wraps selfhost connect:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::YOUR_ACCOUNT_ID:role/wraps-console-access-role" } ]}Copy the ARN of the role you just created — it looks like arn:aws:iam::YOUR_ACCOUNT_ID:role/wraps-vercel-backend-role.
Add one more environment variable to your Vercel project using the role ARN from 5c:
# Add after setting up Vercel OIDC (Step 5):AWS_ROLE_ARN=arn:aws:iam::123456789012:role/<your-vercel-backend-role>Redeploy the Vercel project after adding this variable.
With the dashboard running, create your account, then authenticate the CLI against your instance and register the AWS connection.
wraps selfhost loginWhy not wraps auth login?
The standard login command authenticates against the Wraps SaaS platform. wraps selfhost login reads your deployment metadata and authenticates against your own dashboard URL instead.
Once signed in, register this AWS account with your self-hosted control plane. This creates the wraps-console-access-role IAM role (which your dashboard uses to read SES stats, CloudWatch metrics, and DynamoDB event history) and enables event streaming from your email infrastructure to the dashboard.
wraps selfhost connectSingle-account deployments
Because you are self-hosting, the CLI automatically configures the trust policy to trust your own AWS account — not the Wraps SaaS platform account. You do not need a second account.
Check the health of your self-hosted control plane from the CLI:
wraps selfhost statusA healthy deployment reports the API URL, Lambda ARN, deployed version, and database connectivity. Then open your dashboard URL and confirm your connected AWS account, SES sending stats, and any email or SMS infrastructure you deployed in Steps 1–2 are visible.
You are fully self-hosted
All API calls from the dashboard go directly to your Lambda. No Wraps SaaS servers are involved at runtime. Your license is verified offline — no phone-home required.
When a new Wraps CLI version is released, upgrade the control plane Lambda in place. Migrations run automatically.
wraps selfhost upgradeAfter upgrading the CLI, redeploy your Vercel dashboard project to pick up any frontend changes.
Add DKIM, SPF, and DMARC records to start sending from your own domain.
Domain verification →SES starts in sandbox mode. Request production access to send to any recipient.
Production access →