This guide covers everything you need to self-host or deploy CloakMetric, from local development to production.
Before you begin, make sure you have:
- Node.js 18+ and pnpm installed
- PostgreSQL 15+ (local or hosted via Neon)
- AWS Account with SES, S3, Lambda, and SNS access
- Resend Account for transactional emails
- GitHub Account for CI/CD
- Vercel Account for deployment (recommended)
-
Clone the repository
git clone https://github.com/cloakmetric/cloakmetric.git
-
Install dependencies
-
Set up environment variables
Edit .env with your configuration (see Environment Variables below).
-
Set up the database
-
Start the development server
Open http://localhost:3000 in your browser.
Create a .env file in the project root with the following variables:
| Variable | Description | Example |
|---|
DATABASE_URL | PostgreSQL connection string | postgresql://user:pass@localhost:5432/cloakmetric |
NEXTAUTH_URL | Your app URL | http://localhost:3000 |
NEXTAUTH_SECRET | Random secret for NextAuth | openssl rand -base64 32 |
| Variable | Description | Example |
|---|
AWS_ACCESS_KEY_ID | AWS IAM access key | AKIA... |
AWS_SECRET_ACCESS_KEY | AWS IAM secret key | wJalr... |
AWS_REGION | AWS region for SES | us-east-1 |
AWS_S3_BUCKET | S3 bucket for email storage | cloakmetric-emails |
AWS_SNS_TOPIC_ARN | SNS topic for email events | arn:aws:sns:us-east-1:... |
| Variable | Description | Example |
|---|
RESEND_API_KEY | Resend API key for transactional emails | re_... |
| Variable | Description | Example |
|---|
POLAR_ACCESS_TOKEN | Polar access token | polar_... |
POLAR_WEBHOOK_SECRET | Polar webhook signing secret | whsec_... |
POLAR_ORGANIZATION_ID | Your Polar organization ID | org_... |
| Variable | Description | Example |
|---|
UPSTASH_REDIS_REST_URL | Upstash Redis REST URL | https://...upstash.io |
UPSTASH_REDIS_REST_TOKEN | Upstash Redis REST token | AX... |
-
Install PostgreSQL (if not already installed)
brew install postgresql@15
brew services start postgresql@15
sudo apt install postgresql-15
sudo systemctl start postgresql
-
Create the database
-
Set your DATABASE_URL
DATABASE_URL="postgresql://your_user:your_password@localhost:5432/cloakmetric"
-
Run migrations
Neon is the recommended hosted PostgreSQL for production deployments.
-
Create a Neon account and project at console.neon.tech
-
Copy the connection string from the dashboard
-
Set it as your DATABASE_URL
DATABASE_URL="postgresql://user:pass@ep-cool-name-123456.us-east-1.aws.neon.tech/cloakmetric?sslmode=require"
-
Run migrations against the remote database
CloakMetric uses AWS SES for sending and receiving emails. This section covers the full setup.
- Go to AWS Console → SES → Verified Identities
- Click Create Identity and select Domain
- Enter your domain (e.g.,
yourdomain.com)
- AWS will provide DNS records to add
Add these records to your domain’s DNS:
| Type | Name | Value | Purpose |
|---|
| TXT | _amazonses.yourdomain.com | (provided by AWS) | Domain verification |
| CNAME | selector1._domainkey.yourdomain.com | (provided by AWS) | DKIM signing |
| CNAME | selector2._domainkey.yourdomain.com | (provided by AWS) | DKIM signing |
| CNAME | selector3._domainkey.yourdomain.com | (provided by AWS) | DKIM signing |
| MX | yourdomain.com | 10 inbound-smtp.us-east-1.amazonaws.com | Inbound email |
| TXT | yourdomain.com | v=spf1 include:amazonses.com ~all | SPF record |
-
Create an S3 bucket (e.g., cloakmetric-emails)
-
Add a bucket policy to allow SES to write:
"Service": "ses.amazonaws.com"
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::cloakmetric-emails/*",
"AWS:SourceAccount": "YOUR_AWS_ACCOUNT_ID"
-
Set AWS_S3_BUCKET in your .env
Receipt rules tell SES what to do with incoming emails.
- Go to SES → Email Receiving → Rule Sets
- Create a new rule set (or use the default)
- Create a rule with these actions:
- S3 action — Store email in your S3 bucket
- Lambda action — Invoke your email processing Lambda
- Set the recipient condition to your domain
The Lambda function processes incoming emails stored in S3.
- Create a new Lambda function (Node.js 18+ runtime)
- Set the handler to process S3 events from SES
- Add environment variables:
DATABASE_URL, AWS_S3_BUCKET
- Grant the Lambda role permissions to read from S3 and write to your database
- Connect it to the SES receipt rule
SNS topics handle email event notifications (bounces, complaints, deliveries).
-
Create an SNS topic (e.g., cloakmetric-email-events)
-
In SES, go to Configuration Sets
-
Create a configuration set and add an SNS event destination
-
Subscribe your API endpoint to the SNS topic:
https://yourdomain.com/api/webhooks/ses
-
Set AWS_SNS_TOPIC_ARN in your .env
- Go to SES → Configuration Sets
- Create a new configuration set (e.g.,
cloakmetric)
- Add event destinations:
- Bounce → SNS topic
- Complaint → SNS topic
- Delivery → SNS topic
- The application will use this configuration set when sending emails
- Go to SES → Account Dashboard
- Click Request Production Access
- Fill out the form with your use case, expected volume, and bounce/complaint handling procedures
- AWS typically reviews within 24 hours
Resend handles transactional emails (account verification, password resets, notifications).
- Create a Resend account at resend.com
- Go to API Keys and create a new key
- Set
RESEND_API_KEY in your .env
- Go to Domains in the Resend dashboard
- Add your domain
- Add the DNS records Resend provides (DKIM, SPF)
- Wait for verification (usually a few minutes)
Polar handles payments and subscription management.
-
Create a Polar organization at polar.sh
-
Create subscription products matching your plans:
- Free — $0/month
- Pro — $29/month
- Business — $79/month
-
Go to Settings → Developers and create an access token
-
Set up a webhook endpoint:
https://yourdomain.com/api/webhooks/polar
-
Add to your .env:
POLAR_ACCESS_TOKEN=polar_...
POLAR_WEBHOOK_SECRET=whsec_...
POLAR_ORGANIZATION_ID=org_...
Upstash provides serverless Redis for rate limiting and caching.
-
Create an Upstash account at upstash.com
-
Create a new Redis database
-
Copy the REST URL and token from the dashboard
-
Add to your .env:
UPSTASH_REDIS_REST_URL=https://...upstash.io
UPSTASH_REDIS_REST_TOKEN=AX...
-
Connect your repository to Vercel
Import your GitHub repository at vercel.com/new.
-
Set environment variables
Add all environment variables from your .env to the Vercel project settings under Settings → Environment Variables.
-
Configure the build
Vercel auto-detects Next.js. The default settings should work:
- Build Command:
pnpm build
- Output Directory:
.next
-
Set up the production database
Use your Neon production connection string as DATABASE_URL.
-
Deploy
Push to main to trigger automatic deployment.
For Pro+ plans, users can connect custom domains for their aliases.
- In Vercel, go to Settings → Domains
- Add your custom domain (e.g.,
docs.cloakmetric.com)
- Update DNS records as instructed by Vercel
- SSL is provisioned automatically
The repository includes two GitHub Actions workflows:
Runs on every pull request:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- run: pnpm install --frozen-lockfile
Runs on push to main:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- run: pnpm install --frozen-lockfile
# Run database migrations
DATABASE_URL: ${{ secrets.DATABASE_URL }}
# Vercel handles the actual deployment via its GitHub integration
# This step runs migrations before the deploy completes
Emails not being received
- Check MX records point to SES inbound SMTP
- Verify the SES receipt rule is active
- Check Lambda function logs in CloudWatch
- Ensure the S3 bucket policy allows SES writes
Bounces increasing suddenly
- Check SES sending quotas
- Verify domain DNS records haven’t changed
- Review SES reputation dashboard
- Check if your domain was added to any blocklists
Authentication errors
- Verify
NEXTAUTH_SECRET is set
- Check
NEXTAUTH_URL matches your deployment URL
- Ensure database is accessible and migrations are current
Rate limiting issues
- Check Upstash Redis connection
- Verify
UPSTASH_REDIS_REST_URL and token are correct
- Monitor rate limit usage in the Upstash dashboard
Payment webhook failures
- Verify
POLAR_WEBHOOK_SECRET matches your Polar config
- Check that the webhook URL is publicly accessible
- Review webhook delivery logs in the Polar dashboard
Database connection errors
- For Neon: ensure
?sslmode=require is in your connection string
- Check that your IP is allowed (if using IP allowlists)
- Verify credentials haven’t expired
Before going live, verify everything on this list:
Infrastructure
DNS
Services
Testing