Automate DigitalOcean Droplet lifecycle: snapshot → delete → recreate → health-check on a recurring weekly schedule.
| Step | What happens |
|---|---|
| Deletion | Creates a snapshot, waits for it to complete, then deletes the Droplet |
| Recreation | Recreates the Droplet from the latest snapshot, waits for it to become active |
| Health check | Sends an ICMP ping + HTTP probe to the new Droplet's public IP |
| Cleanup | Auto-deletes the snapshot 2 hours after a successful recreation |
| Reporting | Every event is logged; optional email report via SMTP after each cycle |
Schedules are stored in PostgreSQL and survive server restarts — no jobs are lost if the app is restarted.
Click the button above, or:
- Fork this repo to your GitHub account
- Go to DigitalOcean App Platform
- Click Create App → GitHub and select your fork
- App Platform will auto-detect the Next.js app — keep all defaults
- Click Deploy
Persistence note: The included
.do/app.yamlprovisions a dev-tier PostgreSQL 16 managed database (db) and automatically injectsDATABASE_URLinto the app. Schedules, API keys, and reports persist across restarts and redeployments. No volume mount is needed.
- API key auth — Enter your DigitalOcean Personal Access Token; validated against the API before storing
- Droplet listing — Fetches all Droplets with name, IP, region, size, status, and tags
- Tag filter — Filter the Droplet list by tag; "Select All" respects the active filter
- Weekly schedules — Pick day-of-week + time for deletion and recreation; supports any IANA timezone
- Persistent jobs — Schedules survive app restarts (PostgreSQL-backed, reloaded on boot)
- Retry & backoff — All DigitalOcean API calls retry on 429 / 5xx with exponential backoff
- Reports log — Paginated event log with filtering by event type
- Email notifications — Optional SMTP config to receive an HTML report after each recreation cycle
Requirements: Node.js 18+
docker run -d --name pg -e POSTGRES_DB=scheduler -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres
echo 'DATABASE_URL=postgresql://postgres:postgres@localhost:5432/scheduler' > .env.local
echo 'DATABASE_SSL_MODE=disable' >> .env.local
npm install && npm run devEnter your DigitalOcean Personal Access Token on the login screen.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
(required) | Managed PostgreSQL connection string used by the app for all persistent data |
DATABASE_SSL_MODE |
verify-full |
PostgreSQL TLS mode (disable, require, verify-ca, verify-full). Use verify-full for managed production databases; use disable only for local non-TLS PostgreSQL. TLS params in DATABASE_URL query are ignored in favor of this setting |
DATABASE_CA_CERT |
(unset) | Optional CA certificate content (PEM) for strict TLS verification when required by your PostgreSQL provider. Supports multiline PEM or single-line values with \n escapes |
PORT |
3000 |
Port the server listens on |
NODE_ENV |
development |
Set to production in deployment |
- Create/attach a Managed PostgreSQL database to your App Platform app.
- Set
DATABASE_URLas an App Platform environment variable from the managed database connection. - Keep
DATABASE_SSL_MODE=verify-fullin App Platform. - If your setup requires a custom CA chain, also set
DATABASE_CA_CERTin App Platform.
| Layer | Technology |
|---|---|
| Framework | Next.js 14 (App Router) |
| Database | PostgreSQL |
| Scheduler | node-cron (persisted in PostgreSQL) |
| DO API client | axios with retry/backoff |
| nodemailer | |
| Styling | Tailwind CSS |
app/
├── api/
│ ├── auth/ # POST to validate + store API key
│ ├── droplets/ # GET fetches live from DigitalOcean
│ ├── schedules/ # CRUD — registers/unregisters cron jobs
│ ├── reports/ # Paginated event log
│ ├── settings/ # SMTP + timezone config
│ └── init/ # Boot-time scheduler reload
lib/
├── db.ts # PostgreSQL schema + typed helpers
├── digitalocean.ts # DO API client (snapshot, delete, recreate, poll)
├── scheduler.ts # LifecycleScheduler singleton + workflows
└── mailer.ts # SMTP report emails
The scheduler runs as a global singleton inside the Next.js server process. On startup it loads all active schedules from PostgreSQL and re-registers their cron jobs — so workflows continue running even after the app restarts.
MIT