Skip to main content
You can create custom boot disk images based on existing images by using Packer and the Nebius Packer plug-in. The Nebius Packer plug-in creates a temporary virtual machine (VM) from a base image, connects to it over SSH, runs provisioners and then creates a new boot disk image. Use this workflow to:
  • Pre-install packages and system dependencies
  • Prepare versioned images for repeated VM creation
  • Standardize environments across teams or workloads

Before you start

  1. Install Packer.
  2. Make sure your project has sufficient quotas for image creation:
    • Number of images
    • Total storage capacity of all images
  3. Set up authentication by using one of the following methods.
    • Service account
      1. Create a service account and generate a key pair. The key pair is saved to a JSON file, for example, ~/.nebius/<service_account_ID>_credentials.json.
      2. Open the file and copy the value of the private_key field.
      3. Save the key to the private.pem file:
        -----BEGIN PRIVATE KEY-----
        ...
        -----END PRIVATE KEY-----
        
      4. Use the values from the JSON file in your Packer configuration.
    • Access token Generate an access token:
      nebius iam get-access-token
      
      An access token is valid for 12 hours. After it expires, create a new one.

Steps

Install the Nebius Packer plug-in

  1. Create the config.pkr.hcl file and add the Nebius plug-in configuration:
    packer {
      required_plugins {
        nebius = {
          source  = "github.com/nebius/nebius"
          version = ">= 0.0.4"
        }
      }
    }
    
  2. Initialize the plug-in in the directory that contains your Packer configuration files:
    packer init .
    

Build the disk image

The Nebius image builder creates a VM from a base image, provisions it over SSH and publishes a new image.
  1. Create the build.pkr.hcl file and add the nebius-image source to it:
    source "nebius-image" "ubuntu2404" {
      communicator = "ssh"
      ssh_username = "ubuntu"
    
      # Service account credentials used for image creation
      service_account {
        private_key_file = "./private.pem"
        public_key_id    = "<public_key_ID>"
        account_id       = "<service_account_ID>"
      }
      # Alternatively, use an access token
      # token        = <token>
     
      # Boot disk configuration for the temporary VM
      disk {
        size_gibibytes = 60
      }
    
      # Source image used to create the temporary VM
      base_image {
        family = "ubuntu24.04-driverless"
      }
    
     # Network configuration for the temporary VM
      network {
        subnet_id = "<subnet_ID>"
        associate_public_ip_address = true
      }
    
      # Compute resources for the temporary VM
      instance {
        platform = "cpu-d3"
        preset   = "16vcpu-64gb"
      }
    
      # Parameters of the resulting image
      image {
        name                        = "ubuntu24.04-131-0.0.1"
        version                     = "0.0.1"
        image_family                = "ubuntu24.04-131"
        cpu_architecture            = "amd64"
        image_family_human_readable = "Ubuntu 24.04 CUDA 13.1 Hackathon"
      }
      # Project where the image will be created
      parent_id = "<project_ID>"
    }
    
    The nebius-image source has the following parameters: General parameters
    • communicator (optional): Specifies how Packer connects to the VM. Supported value: ssh (default).
    • parent_id: ID of the project where the resulting image will be created.
    • ssh_username: Username used to connect to the VM.
    Authentication
    • service_account.private_key_file: Path to the private key file.
    • service_account.public_key_id: ID of the public key.
    • service_account.account_id: Service account ID.
    • token: Access token used for authentication. Use this as an alternative to service_account.
    Disk configuration
    • disk.size_gibibytes: Size of the disk in GiB.
    Base image
    • base_image.family: Image family name.
    • base_image.id: Specific image ID.
    Network
    • network.subnet_id (optional): ID of an existing subnet that will be used to create a VM. If not provided, the plug-in attempts to find the project’s default network.
    • network.associate_public_ip_address (optional): Assigns a public IP address. Use a public IP if your build environment connects directly via SSH.
    VM configuration
    • instance.platform: VM platform.
    • instance.preset: VM platform preset (number of GPUs and vCPUs, RAM size).
    Output image configuration
    • image.name: Image name.
    • image.version (optional): Image version.
    • image.image_family (optional): Image family identifier.
    • image.image_family_human_readable (optional): Display name for the image family.
    • image.cpu_architecture (optional): CPU architecture.
  2. Add the build block to the build.pkr.hcl file:
    build {
      sources = ["source.nebius-image.ubuntu2404"]
    
      provisioner "file" {
        # Path to a local script in your project
        source      = "some-local-file.txt"
        destination = "/tmp/helloworld.txt"
      }
    
      provisioner "shell" {
        inline = [
        "cd /tmp",
        "echo Installing hello world text",
        "sudo mv /tmp/helloworld.txt /root",
        "echo Resetting cloud-init and caches",
        "sudo apt clean",
        "sudo uv cache clean",
        "sudo cloud-init clean --logs",
        "sudo sync",
        ]
      }
    }
    
  3. From the directory with the configuration files, run:
    packer init .
    packer build build.pkr.hcl
    

Check the image

  1. In the web console, go to https://mintcdn.com/nebius-ai-cloud/1Ha0sWR6e1mnIaHS/_assets/sidebar/storage.svg?fit=max&auto=format&n=1Ha0sWR6e1mnIaHS&q=85&s=0a2dad6b48aea10e85f6f3e2343aee26 Storage → Disks.
  2. Go to the Images tab and locate your image.

Example: CUDA® 13.1 image

The following example builds an image with CUDA 13.1 from a driverless image. It uses a single configuration file that includes both the plug-in and build configuration.
packer {
  required_plugins {
    nebius = {
      version = ">= 0.0.4"
      source  = "github.com/nebius/nebius"
    }
  }
}

source "nebius-image" "ubuntu2404-cu131" {
  communicator = "ssh"
  ssh_username = "ubuntu"
  service_account {
    private_key_file = "./private.pem"
    public_key_id    = "<public_key_ID>"
    account_id       = "<service_account_ID>"
  }
  disk {
    size_gibibytes = 60
  }
  base_image {
    family = "ubuntu24.04-driverless"
  }
  network {
    associate_public_ip_address = true
  }
  instance {
    platform = "cpu-d3"
    preset   = "16vcpu-64gb"
  }
  image {
    name                        = "ubuntu24.04-131-0.0.1"
    version                     = "0.0.1"
    image_family                = "ubuntu24.04-131"
    cpu_architecture            = "amd64"
    image_family_human_readable = "Ubuntu 24.04 CUDA 13.1 Hackathon"
  }
  parent_id = "project-..."
}

build {
  sources = ["source.nebius-image.ubuntu2404-cu131"]

  provisioner "file" {
    source      = "guest.config"
    destination = "/tmp/guest.config"
  }

  provisioner "file" {
    source      = "install-gpu-cuda13.1-ubuntu24.04.sh"
    destination = "/tmp/install-gpu-cuda13.1-ubuntu24.04.sh"
  }

  provisioner "shell" {
    inline = [
      "cd /tmp",
      "echo Installing cuda 13.1 et al",
      "sudo bash /tmp/install-gpu-cuda13.1-ubuntu24.04.sh",
      "echo Resetting cloud-init and caches",
      "sudo apt clean",
      "sudo uv cache clean",
      "sudo cloud-init clean --logs",
      "sudo sync",
    ]
  }
}
The file and shell provisioners are used to copy files to the VM and execute commands during the build. Create your own scripts depending on the software and configuration you want to include in the image.