{
  "manifest_version": "1",
  "slug": "migrate-digitalocean-droplet",
  "title": "Droplets from DigitalOcean",
  "headline": "Migrate a DigitalOcean Droplet to exe.dev",
  "description": "Move a DigitalOcean Droplet to an exe.dev VM: the same packages, files, databases, containers, and cron jobs, rehearsed and checked before DNS moves.",
  "category": "migration",
  "tags": [
    "digitalocean droplet",
    "migrate off digitalocean",
    "move droplet",
    "server migration",
    "rsync",
    "wordpress",
    "docker compose",
    "nginx"
  ],
  "url": "https://exe.dev/deploy/migrate-digitalocean-droplet",
  "markdown_url": "https://exe.dev/deploy/migrate-digitalocean-droplet.md",
  "upstream": {
    "website": "https://www.digitalocean.com/products/droplets",
    "source": "https://github.com/RsyncProject/rsync",
    "docs": "https://www.digitalocean.com/community/tutorial_series/how-to-migrate-to-a-new-linux-server",
    "license": "GPL-3.0 (rsync)"
  },
  "example_vm_name": "my-server",
  "time": "1 hour",
  "stack": [
    {
      "name": "Your droplet's software",
      "detail": "The same packages, users, services, containers, and cron jobs, at the same paths",
      "data": "wherever it was on the droplet"
    },
    {
      "name": "Your web server",
      "detail": "nginx, Apache, or Caddy, on port 8000 behind exe.dev's HTTPS proxy, in place of 80 and 443",
      "port": 8000
    },
    {
      "name": "Your databases",
      "detail": "PostgreSQL and MySQL or MariaDB, restored from dumps; others copied while stopped",
      "data": "/var/lib/postgresql, /var/lib/mysql"
    },
    {
      "name": "The move kit",
      "detail": "survey, plan, copy, check, and move; also your record of what moved",
      "data": "~/droplet"
    }
  ],
  "access": [
    {
      "url": "https://my-server.exe.xyz/",
      "who": "private",
      "what": "your main site, until you make the move"
    },
    {
      "url": "https://example.com/",
      "who": "public",
      "what": "your sites, once your domains point at the VM and it's public"
    },
    {
      "url": "ssh my-server.exe.xyz",
      "who": "private",
      "what": "the shell, as `exedev` with sudo, in place of `root@\u003cdroplet\u003e`"
    }
  ],
  "inputs": [
    {
      "name": "DROPLET_IP",
      "description": "the droplet's public IPv4 address, from the **Droplets** page of DigitalOcean's control panel"
    },
    {
      "name": "DROPLET_USER",
      "description": "the user you SSH in to the droplet as; `root`, or a user with passwordless sudo"
    }
  ],
  "delivers": [
    "The VM reaches the droplet with a key of its own, and nothing on the droplet has changed or stopped.",
    "A survey of the droplet in `~/droplet/survey.txt`, and the plan of what moves in `~/droplet/plan`.",
    "The droplet's packages, users, files, databases, containers, and services on the VM, at the same paths and major versions, set to start on boot; its workers and cron jobs installed but off until the move.",
    "Its sites served on port 8000 behind `https://\u003cvm\u003e.exe.xyz/`, with `~/droplet/check` finding every page the same as on the droplet.",
    "A report in `~/droplet/report.md`: what moved, what changed for exe.dev, what couldn't move, and the owner's steps for the move."
  ],
  "deploy": {
    "new_vm_url": "https://exe.dev/new?prompt=DROPLET_IP%3D%3Cfill-this-in%3E%0ADROPLET_USER%3D%3Cfill-this-in%3E%0A%0ASet%20up%20Droplets%20from%20DigitalOcean%20on%20this%20VM%20by%20following%20the%20exe.dev%20recipe%20at%20https%3A%2F%2Fexe.dev%2Fdeploy%2Fmigrate-digitalocean-droplet.md%20from%20top%20to%20bottom.%0A%0AThe%20values%20at%20the%20top%20of%20this%20message%20are%20mine%3A%0A-%20DROPLET_IP%3A%20the%20droplet%27s%20public%20IPv4%20address%2C%20from%20the%20%2A%2ADroplets%2A%2A%20page%20of%20DigitalOcean%27s%20control%20panel%0A-%20DROPLET_USER%3A%20the%20user%20you%20SSH%20in%20to%20the%20droplet%20as%3B%20%60root%60%2C%20or%20a%20user%20with%20passwordless%20sudo%0AAsk%20me%20for%20any%20that%20still%20say%20%3Cfill-this-in%3E%20before%20you%20need%20them.%0A%0AThe%20recipe%27s%20example%20VM%20name%20is%20my-server.%20This%20VM%27s%20name%20is%20the%20output%20of%20%60hostname%60%3A%20use%20it%20wherever%20the%20recipe%20writes%20my-server.%20Skip%20the%20step%20that%20creates%20the%20VM%3B%20you%20are%20on%20it.%0A%0AYou%20are%20done%20when%20all%20of%20these%20are%20true.%20Check%20each%20one%20yourself%3A%0A-%20The%20VM%20reaches%20the%20droplet%20with%20a%20key%20of%20its%20own%2C%20and%20nothing%20on%20the%20droplet%20has%20changed%20or%20stopped.%0A-%20A%20survey%20of%20the%20droplet%20in%20%60~%2Fdroplet%2Fsurvey.txt%60%2C%20and%20the%20plan%20of%20what%20moves%20in%20%60~%2Fdroplet%2Fplan%60.%0A-%20The%20droplet%27s%20packages%2C%20users%2C%20files%2C%20databases%2C%20containers%2C%20and%20services%20on%20the%20VM%2C%20at%20the%20same%20paths%20and%20major%20versions%2C%20set%20to%20start%20on%20boot%3B%20its%20workers%20and%20cron%20jobs%20installed%20but%20off%20until%20the%20move.%0A-%20Its%20sites%20served%20on%20port%208000%20behind%20%60https%3A%2F%2F%3Cvm%3E.exe.xyz%2F%60%2C%20with%20%60~%2Fdroplet%2Fcheck%60%20finding%20every%20page%20the%20same%20as%20on%20the%20droplet.%0A-%20A%20report%20in%20%60~%2Fdroplet%2Freport.md%60%3A%20what%20moved%2C%20what%20changed%20for%20exe.dev%2C%20what%20couldn%27t%20move%2C%20and%20the%20owner%27s%20steps%20for%20the%20move.%0A%0ARead%20the%20whole%20recipe%2C%20including%20the%20closed%20details%2C%20and%20do%20%22Rehearse%20the%0Amove%20by%20hand%22%20in%20order%2C%20skipping%20VM%20creation%3B%20the%20walkthrough%20above%20it%20is%0Afor%20the%20owner.%20You%20need%20the%20owner%20once%2C%20early%3A%20show%20them%20the%20command%20in%0A%22Let%20the%20VM%20in%22%20with%20this%20VM%27s%20name%20and%20the%20droplet%27s%20address%20and%20user%2C%0Aand%20wait%20until%20%60ssh%20droplet%20sudo%20-n%20true%60%20works.%0AOnly%20read%20from%20the%20droplet%3A%20never%20stop%2C%20restart%2C%20install%2C%20or%20change%0Aanything%20there.%20Never%20run%20~%2Fdroplet%2Fmove%2C%20change%20DNS%2C%20or%20run%20share%0Aset-public%3A%20the%20move%20is%20the%20owner%27s%20call.%20Until%20then%2C%20keep%20the%20plan%27s%0Aworkers%20and%20cron%20off%20on%20this%20VM.%0AKeep%20passwords%2C%20keys%2C%20and%20.env%20values%20you%20come%20across%20out%20of%20your%0Areplies%20and%20the%20report.%0AIf%20the%20droplet%20runs%20something%20exe.dev%20can%27t%20%28a%20mail%20server%2C%20inbound%20ports%0Aother%20than%20HTTP%20and%20SSH%29%2C%20or%20something%20you%27d%20have%20to%20rewrite%20rather%20than%0Amove%2C%20don%27t%20work%20around%20it%20silently%3A%20put%20it%20in%20the%20report%20and%20ask.%0AFinish%20with%20the%20report%27s%20summary%2C%20https%3A%2F%2F%3Cvm%3E.exe.xyz%2F%2C%20and%20the%20owner%27s%0Asteps%20in%20%22Make%20the%20move%22%20with%20this%20VM%27s%20name%20and%20the%20droplet%27s%20domains.%0A%0AFinish%20with%20the%20URLs%20I%20should%20open.%0A",
    "terminal": "curl -fsSL https://exe.dev/deploy/migrate-digitalocean-droplet/prompt.txt | ssh exe.dev new --prompt=/dev/stdin",
    "prompt": "DROPLET_IP=\u003cfill-this-in\u003e\nDROPLET_USER=\u003cfill-this-in\u003e\n\nSet up Droplets from DigitalOcean on this VM by following the exe.dev recipe at https://exe.dev/deploy/migrate-digitalocean-droplet.md from top to bottom.\n\nThe values at the top of this message are mine:\n- DROPLET_IP: the droplet's public IPv4 address, from the **Droplets** page of DigitalOcean's control panel\n- DROPLET_USER: the user you SSH in to the droplet as; `root`, or a user with passwordless sudo\nAsk me for any that still say \u003cfill-this-in\u003e before you need them.\n\nThe recipe's example VM name is my-server. This VM's name is the output of `hostname`: use it wherever the recipe writes my-server. Skip the step that creates the VM; you are on it.\n\nYou are done when all of these are true. Check each one yourself:\n- The VM reaches the droplet with a key of its own, and nothing on the droplet has changed or stopped.\n- A survey of the droplet in `~/droplet/survey.txt`, and the plan of what moves in `~/droplet/plan`.\n- The droplet's packages, users, files, databases, containers, and services on the VM, at the same paths and major versions, set to start on boot; its workers and cron jobs installed but off until the move.\n- Its sites served on port 8000 behind `https://\u003cvm\u003e.exe.xyz/`, with `~/droplet/check` finding every page the same as on the droplet.\n- A report in `~/droplet/report.md`: what moved, what changed for exe.dev, what couldn't move, and the owner's steps for the move.\n\nRead the whole recipe, including the closed details, and do \"Rehearse the\nmove by hand\" in order, skipping VM creation; the walkthrough above it is\nfor the owner. You need the owner once, early: show them the command in\n\"Let the VM in\" with this VM's name and the droplet's address and user,\nand wait until `ssh droplet sudo -n true` works.\nOnly read from the droplet: never stop, restart, install, or change\nanything there. Never run ~/droplet/move, change DNS, or run share\nset-public: the move is the owner's call. Until then, keep the plan's\nworkers and cron off on this VM.\nKeep passwords, keys, and .env values you come across out of your\nreplies and the report.\nIf the droplet runs something exe.dev can't (a mail server, inbound ports\nother than HTTP and SSH), or something you'd have to rewrite rather than\nmove, don't work around it silently: put it in the report and ask.\nFinish with the report's summary, https://\u003cvm\u003e.exe.xyz/, and the owner's\nsteps in \"Make the move\" with this VM's name and the droplet's domains.\n\nFinish with the URLs I should open.\n",
    "prompt_url": "https://exe.dev/deploy/migrate-digitalocean-droplet/prompt.txt"
  },
  "updated": "2026-10-16",
  "related": [
    "migrate-durable-objects",
    "n8n",
    "claude-code",
    "openclaw",
    "code-server",
    "uptime-kuma"
  ],
  "alternatives": [
    "DigitalOcean Droplets"
  ]
}
