DigitalOcean spans a wide range: raw Droplets (VMs you administer yourself), App Platform (their PaaS), and Managed Databases. Your migration path to PandaStack depends heavily on which you're using. This guide covers all three, with the most attention on the common case: moving off self-managed Droplets onto a managed platform.
First, identify what you're running
| DigitalOcean product | What it is | PandaStack target |
|---|---|---|
| Droplet | A VM you fully manage | Container app (you containerize) |
| App Platform | Their managed PaaS | Container / static app (near 1:1) |
| Managed Database | Managed PG/MySQL/Redis/Mongo | Managed database |
| Spaces | Object storage | Object storage (bring your own) |
| Load Balancer | Managed LB | Built-in (Kong ingress) |
If you're on App Platform, migration is close to 1:1 — it's already a Git-push PaaS. If you're on Droplets, the work is containerizing what you currently run by hand. Let's cover both.
Path A: From Droplets (the bigger lift)
A Droplet is a server you SSH into and configure. The migration is really a *containerization* exercise — turning hand-installed software into a reproducible image.
Step 1: Inventory the Droplet
SSH in and catalog what's actually running:
# What's listening?
ss -tlnp
# What's installed via the package manager?
dpkg -l | grep -E 'nginx|node|python|postgres|redis'
# What runs at boot?
systemctl list-unit-files --state=enabled
# Cron jobs?
crontab -l; ls /etc/cron.*The goal is a complete picture: your app, its runtime, any services it depends on (a local Postgres? Redis? nginx as a reverse proxy?), and any cron jobs.
Step 2: Containerize the app
Write a Dockerfile that reproduces your app's runtime. For a Node app:
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 8080
CMD ["node", "server.js"]Key shift in thinking: separate concerns that lived together on the Droplet. Your local Postgres becomes a managed database. Your nginx reverse proxy becomes the platform's ingress. Your cron entries become PandaStack cronjobs. The container should contain *only your app*.
If you'd rather not write a Dockerfile, PandaStack can auto-detect buildpacks for Node/Python/Go and more.
Step 3: Move the database off the Droplet
If Postgres ran on the Droplet itself, dump it and restore into a managed database:
pg_dump "postgres://user:pass@localhost:5432/mydb" -Fc -f mydb.dump
pg_restore --no-owner --no-acl -d "$PANDASTACK_DATABASE_URL" mydb.dumpOnce the database is attached in PandaStack, DATABASE_URL is injected automatically — your app stops carrying a hardcoded localhost connection.
Step 4: Move cron jobs
Each crontab line becomes a PandaStack cronjob with the same schedule expression. This is a quiet upgrade: instead of cron output vanishing into /var/log on one server, you get managed execution and logs.
Path B: From App Platform (near 1:1)
App Platform is already a managed PaaS, so this is mostly remapping config.
- 1Connect the same Git repo to PandaStack. App Platform deploys from Git too, so your build is likely already reproducible.
- 2Translate the app spec. App Platform's
app.yamldefines components, env vars, and routes. Recreate the build command, run command, port, and env vars in PandaStack. Container components map to container apps; static-site components map to static sites. - 3Re-point your managed database. If you used a DO Managed Database, either keep it (PandaStack apps can connect to external databases) or migrate it (Path A's dump/restore) to a PandaStack managed database to get auto-wiring and one bill.
Step: Migrate a DO Managed Database
DO Managed Databases are reachable over the network, which makes migration clean:
# Dump from DO (use the connection details from the DO console)
pg_dump "$DO_DATABASE_URL" -Fc -f prod.dump
# Restore into PandaStack
pg_restore --no-owner --no-acl -d "$PANDASTACK_DATABASE_URL" prod.dumpPandaStack supports PostgreSQL (14.x/16.x), MySQL (5.7/8.x), MongoDB, and Redis, with scheduled and manual backups. Match major versions when dumping/restoring.
Step: Domains and SSL
If you managed nginx + certbot on a Droplet, you get to delete that whole chore. Point your domain at PandaStack and SSL is issued and renewed automatically. No more 3 a.m. expired-cert pages.
What you stop doing
Migrating off Droplets specifically, you stop: patching the OS, configuring nginx, renewing certs by hand, babysitting systemd units, and SSHing in to deploy. You trade root-level control for not having to use it. If you genuinely need that control (custom kernel modules, specific OS tuning), a managed platform is a worse fit — be honest about that. For the large majority of web apps, it's pure upside.
Cutover checklist
- [ ] App containerized (or App Platform spec translated)
- [ ] Database dumped and restored; counts verified
- [ ] Cron jobs recreated as cronjobs
- [ ] Env vars / secrets moved (and rotated)
- [ ] Domain + SSL re-pointed (SSL auto-issues)
- [ ] Staging tested; DNS cutover scheduled
- [ ] Old Droplet/app kept briefly for rollback
References
- [DigitalOcean App Platform app spec](https://docs.digitalocean.com/products/app-platform/reference/app-spec/)
- [DigitalOcean Managed Databases](https://docs.digitalocean.com/products/databases/)
- [PostgreSQL backup and restore](https://www.postgresql.org/docs/current/backup-dump.html)
- [Dockerfile best practices](https://docs.docker.com/build/building/best-practices/)
- [Crontab expression format](https://man7.org/linux/man-pages/man5/crontab.5.html)
---
The biggest win moving off Droplets is everything you stop maintaining. PandaStack's free tier (5 web services, 1 database, cronjobs and edge functions included) lets you containerize and test before you cut over. Start at [dashboard.pandastack.io](https://dashboard.pandastack.io).