Wraps Logo
Guide

Self-Hosted Deployment

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.

30–45 min

Overview

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.

  • Control plane API on Lambda

    Deployed into your AWS account via Pulumi — you own the function, logs, and billing

  • Your Postgres database

    Bring any Postgres-compatible DB (Neon, Supabase, Railway, self-hosted), or let Wraps provision a Neon project automatically

  • Dashboard on Vercel

    Deploy apps/web from the Wraps repo to your own Vercel project

  • Zero stored credentials

    Dashboard authenticates to AWS via Vercel OIDC federation — no static keys

Prerequisites

  • Wraps CLI installed (npm install -g @wraps.dev/cli)
  • AWS CLI configured with credentials that have IAM, Lambda, DynamoDB, SQS, and EventScheduler permissions
  • Postgres database connection string (or a Neon API key to provision one automatically)
  • Wraps enterprise license key — contact wraps.dev/contact to get one
  • Vercel account and a project to deploy the dashboard

1
Deploy the Control Plane API

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.

Terminal
# 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 deploy

The CLI will:

  1. Prompt for AWS region if not specified via flag
  2. Prompt for license key, app URL, and any missing database details
  3. Run database migrations on your Postgres instance
  4. Deploy the Lambda function, DynamoDB tables, SQS queues, and EventBridge scheduler via Pulumi
  5. Print the API URL (e.g. 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.

2
Deploy Email Infrastructure

Initialise email sending with AWS SES. This creates IAM roles, configures SES, and sets up event processing for open and click tracking.

GNU Bashterminal.sh
wraps email init

If you only need SMS, skip this step and run wraps sms init instead.

3
Get Your Environment Variables

Generate the .env block for your Vercel dashboard deployment. This reads your local Wraps metadata and prints all required variables in KEY=value format.

GNU Bashterminal.sh
wraps selfhost env

The output looks like this — copy it and keep it ready for Step 4:

.ENV.env
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=123456789012

4
Deploy the Dashboard to Vercel

The Wraps dashboard lives in apps/web in the Wraps monorepo. Fork or clone the repo and deploy that directory to Vercel.

  1. Fork the Wraps repo and connect it to a new Vercel project. Set the root directory to apps/web.
  2. Add all environment variables from the wraps selfhost env output into Vercel → Project Settings → Environment Variables. Scope them to Production (and Preview if needed).
  3. Trigger a deployment — Vercel will build and deploy the dashboard. The first deploy will succeed but the dashboard will not be able to call AWS until you complete Step 5.

5
Set Up Vercel OIDC Authentication

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.

Step 5a — Get your Vercel OIDC provider URL

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.

Step 5b — Add an OIDC identity provider in AWS

In the AWS Console, go to IAM → Identity providers → Add provider:

  • Provider type: OpenID Connect
  • Provider URL: paste your Vercel OIDC URL from 5a
  • Audience: sts.amazonaws.com
Step 5c — Create an IAM role that trusts the OIDC provider

Create 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:

JSONtrust-policy.json
{  "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:

JSONpermissions-policy.json
{  "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.

Step 5d — Set AWS_ROLE_ARN in Vercel

Add one more environment variable to your Vercel project using the role ARN from 5c:

.ENV.env
# 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.

6
Create Your Account and Connect

With the dashboard running, create your account, then authenticate the CLI against your instance and register the AWS connection.

  1. Open your dashboard URL in a browser and sign up with email and password.
  2. Create your organization — you will be prompted to do this during onboarding. The CLI requires an organization to exist before it can connect.
  3. Sign in the CLI — run the command below. It reads your deployment metadata to find the dashboard URL, then opens a browser for device authorization against your own instance.
GNU Bashterminal.sh
wraps selfhost login

Why 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.

GNU Bashterminal.sh
wraps selfhost connect

Single-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.

7
Verify Your Deployment

Check the health of your self-hosted control plane from the CLI:

GNU Bashterminal.sh
wraps selfhost status

A 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.

Upgrading

When a new Wraps CLI version is released, upgrade the control plane Lambda in place. Migrations run automatically.

GNU Bashterminal.sh
wraps selfhost upgrade

After upgrading the CLI, redeploy your Vercel dashboard project to pick up any frontend changes.

Next Steps

Verify your domain

Add DKIM, SPF, and DMARC records to start sending from your own domain.

Domain verification →

Request production access

SES starts in sandbox mode. Request production access to send to any recipient.

Production access →