Web app for managing infrastructure across Cloudways, Cloudflare, and Bunny.net from a single dashboard.
- Secure Authentication — Email/Password login with NextAuth.js, protecting all routes and API endpoints
- Multi-provider management — connect and sync Cloudways servers/apps, Cloudflare DNS zones, and Bunny.net CDN pull/storage zones
- One-click actions — purge caches, reboot servers, trigger backups with confirmation modals
- Cross-provider linking — automatically links Cloudflare zones and Bunny pull zones to Cloudways apps by domain matching
- Manual link overrides — override auto-detected Bunny CDN links per-app
- Action history — tracks all operations with status, duration, and error details
- Encrypted credentials — all provider credentials are AES-256-GCM encrypted at rest
├── app/ # Next.js App Router
│ ├── login/ # Login page
│ ├── api/auth/ # NextAuth API routes
│ ├── page.tsx # Dashboard (overview stats)
│ ├── connections/ # Provider connection management
│ ├── servers/ # Cloudways server cards + reboot
│ ├── apps/ # Apps & Sites with CDN linking
│ ├── cloudflare/zones/ # Cloudflare zone list + purge
│ ├── bunny/pullzones/ # Bunny pull zone list + purge
│ ├── actions/ # Action history + new action form
│ └── api/clients/[clientId]/ # REST API routes
├── components/ # Shared UI components (ConfirmModal, LogoutButton)
├── hooks/ # Custom React hooks (useToast)
├── lib/
│ ├── auth.ts # NextAuth configuration & callbacks
│ ├── connectors/ # Provider SDK wrappers (Cloudflare, Bunny, Cloudways)
│ ├── crypto.ts # AES-256-GCM credential encryption
│ ├── db.ts # Prisma client singleton
│ ├── getDefaultClient.ts # Shared org→client lookup helper
│ ├── triggerAction.ts # Client-side action dispatch utility
│ └── apiResponse.ts # API response envelope helpers
├── middleware.ts # Authentication middleware
├── prisma/
│ ├── schema.prisma # Database schema
│ ├── seed.ts # Database seed script
│ └── migrations/ # Prisma migration history
└── scripts/ # CLI utilities and debug scripts
-
Install dependencies:
npm install
-
Set environment variables (or create a
.envfile):DATABASE_URL=postgresql://user:pass@localhost:5432/cloudmanager CREDENTIALS_ENC_KEY=<32 bytes base64> CREDENTIALS_ENC_KID=v1 # NextAuth NEXTAUTH_URL=http://localhost:3000 NEXTAUTH_SECRET=changeme123 -
Run Prisma migrations:
npx prisma migrate dev
-
Seed the database:
# Set ADMIN_EMAIL and ADMIN_PASSWORD in .env to create an admin user npx prisma db seedOr create a user manually:
npx tsx scripts/create-user.ts admin@example.com 'yourPassword' "Your Name" -
Start the dev server:
npm run dev
The easiest way to deploy this application is using Vercel.
- Push your code to GitHub.
- Import your repository into Vercel.
- Configure the following Environment Variables in Vercel before deploying:
DATABASE_URL(Use your production database URL, e.g., Supabase connection pooler URL)CREDENTIALS_ENC_KEY(Secure 32-byte base64 string)CREDENTIALS_ENC_KID(e.g.,v1)NEXTAUTH_SECRET(Secure random string)
Note: You do not need to set
NEXTAUTH_URLon Vercel; it relies onVERCEL_URLautomatically. - Deploy! Vercel will automatically detect Next.js and handle the build and Prisma generation for you.
| Page | Path | Description |
|---|---|---|
| Login | /login |
Secure authentication page |
| Dashboard | / |
Overview stats: connections, resources, actions |
| Connections | /connections |
Add, validate, sync, and delete provider connections |
| Servers | /servers |
Cloudways server cards with reboot action |
| Apps & Sites | /apps |
Applications with Cloudflare/Bunny linking and cache actions |
| Cloudflare Zones | /cloudflare/zones |
Zone list with cache purge |
| Bunny Pull Zones | /bunny/pullzones |
Pull zone list with cache purge |
| Actions | /actions |
Action history with filters and new action form |
- Authentication — All routes are protected by NextAuth.js middleware.
- Provider Credentials — Encrypted using AES-256-GCM before database storage.
- Encryption Key — Managed via environment variables.
| Method | Path | Description |
|---|---|---|
| POST | /api/clients/{clientId}/connections |
Create provider connection |
| DELETE | /api/clients/{clientId}/connections/{connectionId} |
Delete connection + resources |
| POST | /api/clients/{clientId}/connections/{connectionId}/validate |
Validate credentials |
| POST | /api/clients/{clientId}/connections/{connectionId}/sync |
Sync inventory (batched) |
| GET | /api/clients/{clientId}/resources |
List resources (filterable by provider, type, query) |
| GET | /api/clients/{clientId}/resources/{resourceId} |
Get single resource |
| GET | /api/clients/{clientId}/apps |
List apps with Cloudflare/Bunny links |
| POST | /api/clients/{clientId}/apps/{appId}/override-bunny |
Set Bunny pull zone override |
| GET | /api/clients/{clientId}/servers |
List Cloudways servers |
| GET | /api/clients/{clientId}/cloudflare/zones |
List Cloudflare zones |
| GET | /api/clients/{clientId}/bunny/pullzones |
List Bunny pull zones |
| POST | /api/clients/{clientId}/actions |
Create and execute action request |
| GET | /api/clients/{clientId}/actions |
List actions (cursor-paginated, filterable) |
| Provider | Auth | Resources | Actions |
|---|---|---|---|
| Cloudflare | API Token or Global API Key + Email | Zones | Purge cache |
| Bunny.net | Access Key | Pull Zones, Storage Zones | Purge cache |
| Cloudways | Email + API Key (OAuth v2) | Servers, Apps | Purge cache, Reboot, Backup, Cloudflare CDN purge |
# Create a new user or update an existing user's password
# Note: Wrap your password in single quotes to prevent terminal errors with special characters!
npx tsx scripts/create-user.ts admin@example.com 'mySecretPass' "My Name"
# Verify a Cloudflare Token independently of the UI (useful for debugging)
export CLOUDFLARE_API_TOKEN=your_token
npx tsx scripts/verify-cloudflare.ts
# Debug: list failed actions
node scripts/check-failed-actions.js
# Debug: inspect app metadata
node scripts/check-meta.js
# Debug: inspect override data
npx tsx scripts/debug-overrides.ts