zfsify

Set up ZFS when creating a VPS

Use cloud-init when you want a newly provisioned Ubuntu server to convert its boot disk or an attached data disk automatically. Use the one-command installer over SSH when the server already exists or you want to review its plan in a terminal.

The templates download and run the same reformat.sh entry point. They do not require a custom Ubuntu image, an ISO, or a cloud API token inside the guest. They create a systemd job that starts after cloud-init has finished configuring users and networking.

Target Template Default behavior
Boot drive, including / and /boot cloud-init/root.yml Preserve the existing Ubuntu installation
One attached disk cloud-init/volume.yml Preserve ext4 data; explicit opt-in required to erase

Use one template for each server launch: both use the same service and launcher paths. To convert more disks, run the installer once per target afterward. The underlying conversion paths have DigitalOcean acceptance evidence; these first-boot templates have not been separately tested end to end.

Convert the root drive at first boot

  1. Create a normal Ubuntu VPS with a supported image and disk layout. Follow the root requirements, including at least 512 MiB RAM and working space for package preparation and conversion. A fresh, mostly empty image is the usual starting point.
  2. Select your SSH public key in the provider’s creation form.
  3. Paste cloud-init/root.yml into the provider’s user data or cloud-init field, then create the server.

The root template uses automatic selection. It performs the preflight, selects the available preserving method, stages a compressed RAM environment, reboots to migrate the disk, and reboots through ZFSBootMenu into Ubuntu on ZFS. Expect two SSH disconnects and installation downtime. Install or start application workloads after that boot.

When 50/50 does not fit, the installer selects slice-by-slice if enough working space remains. Otherwise it stops so you can run the installer over SSH and select a backup destination; erase is never an automatic fallback. See the backup setup guide.

Ensure the recovery SSH key is available

The root installer requires your public key in /root/.ssh/authorized_keys so you can reconnect while it is running from RAM. DigitalOcean’s root-login images normally receive the selected key there. Providers that inject keys only into ubuntu or another default account need an explicit root key in cloud-init.

Add this top-level section to the root template, replacing the example with your public key. If your configuration already has a users list, merge the entries instead of adding a second list:

users:
  - default
  - name: root
    lock_passwd: true
    ssh_authorized_keys:
      - ssh-ed25519 REPLACE_WITH_YOUR_PUBLIC_KEY

The template disables SSH password authentication. A private key or provider API token does not belong in user data.

Convert an attached volume at first boot

Attach the volume when provisioning the server, then customize cloud-init/volume.yml:

The target must be attached and discoverable when the job starts. The script converts that one disk while Ubuntu stays running; it does not install a bootloader or reboot for a data-volume conversion. Existing mount points are retained. Unmounted inputs receive a generated mount point printed in the logs.

Cloud-init does not create the cloud Volume itself. Use the provider’s creation form/API or your provisioning tools for that, then give the guest the exact device identity. The volume guide covers layout requirements, remote backup, named pools, and provider helpers.

Follow progress and confirm the result

Connect over SSH and inspect the first-boot job:

sudo journalctl -u zfsify-first-boot.service -f

For root conversion, reconnect after the first reboot and run:

sudo zfs-on-boot-status

After Ubuntu boots from ZFS, inspect its root filesystem and pool:

findmnt /
findmnt --target /boot
sudo zpool status

For a data-volume conversion, inspect the selected mount point instead. Its work directory and conversion.log path appear in the service journal.

Each template records an attempt in /var/lib/zfsify/first-boot.started. This prevents unattended retries after a partial conversion or later reboot. If it stops, inspect the journal, disk layout, and any /var/lib/zfs-on-boot or /var/lib/zfsify-volume.* staging state before deciding how to recover. Do not clear the marker or staging directories blindly: a temporary pool may hold the verified copy. Once the failure state is understood, use the regular installer for a deliberate retry or recovery.

Reproducible provisioning

The templates fetch the published installer when the job starts. For a fleet that requires a fixed build, host or pin the reviewed installer artifact and change the URL in the launcher. Record its SHA-256 with your provisioning configuration. The signed Ubuntu package repositories can still provide newer packages during preparation; a fixed shell-script checksum does not pin every Ubuntu package.