Network
You can deploy a cloud server from your own custom image. This is useful when you need:
For the purpose of this article, images are grouped into two categories:
This guide covers how to create, customize, and prepare a virtual machine (VM) image and then upload it to the customer portal to deploy a cloud server. It walks through three scenarios:
This article does not cover the operating system installation process.
Our cloud services are built on OpenStack. You can configure all parameters and applications as needed, and ensure your VM meets the following core OpenStack image requirements:
| Requirement | Linux | FreeBSD | OpenBSD | NetBSD |
|---|---|---|---|---|
| Architecture | x64 OS | |||
| Image format | qcow2 (recommended) |
|||
| Boot firmware | Only BIOS boot firmware. UEFI is not supported | |||
| Disk layout | Use the standard disk layout provided by your distribution's cloud images. Enable automatic root expansion on first boot with cloud-init's growpart and resizefs modules. |
Use GPT with two partitions. The first partition is The root partition must be the last one on the disk. This is required for correct auto-resize during the first boot with |
Use GPT with the root partition placed as the last one on the disk. Automatic root expansion (auto-grow) is supported via growfs in OpenBSD 7.3 and later. |
Use GPT (recommended). Automatic root expansion is not supported. Resizing requires manual steps: gpt resize + growfs. |
| No hard-coded networking | Use DHCP and remove any static IP and MAC assignments from network configuration files (such as /etc/network/interfaces, /etc/netplan/*.yaml, etc). |
Use DHCP on vtnet0 and remove any static network configuration from /etc/rc.conf (or related includes). |
Use DHCP on vio0 and remove any static network configuration from /etc/hostname.* files. |
Use DHCP on vioif0 and remove any static network configuration from /etc/ifconfig.* files. |
| Configured remote access | Ensure that the SSH server is enabled and starts on boot. | Ensure that sshd is enabled. bsd-cloudinit injects SSH keys automatically. Grant sudo access to the target user if required. |
sshd is enabled by default |
Ensure that sshd is enabled. root SSH login may be disabled by default depending on the image. |
| Hypervisor/driver compatibility |
Modern Linux distributions include all necessary virtio drivers. Only very old kernels (pre-3.0) may require adding virtio and network drivers. Legacy Xen-PV is not needed. |
Ensure that virtio disk and network drivers are enabled and that comconsole is configured. Verify that the image boots correctly under KVM/QEMU. |
Ensure that virtio disk ( Virtio is fully supported in modern OpenBSD 5.3 and later, and provides optimal performance under KVM. |
Ensure that basic virtio disk and network support virtio(4) is available in the image. |
| Image size | Upload size: ≤ 5 GB | |||
For the complete list of requirements, see the OpenStack Image Guide.
Cloud-init supports a wide range of Linux and BSD distributions. For the list of supported platforms, see: https://docs.cloud-init.io/en/latest/reference/availability.html.
You can find unofficial BSD images that include cloud-init and have been tested on OpenStack at: https://bsd-cloud-image.org/.
In this guide we use QEMU, a free and open-source cross-platform virtualization environment. After installing QEMU, you can start a VM with your OS image.
QEMU is required only if you plan to customize an image (Case 2) or prepare a non–cloud-compatible ISO (Case 3).
If you want to deploy a vendor-provided cloud image as is (Case 1), you can skip this section and proceed directly to uploading the image to the customer portal.
sudo apt-get install qemu-system
sudo dnf install qemu qemu-kvm
#or
dnf install @virtualization
sudo yum install qemu qemu-kvm
zypper install qemu
sudo pacman -S qemu
From Homebrew:
brew install qemu
From MacPorts:
sudo port install qemu
Open PowerShell and run the following command with administrator rights:
winget install SoftwareFreedomConservancy.QEMU
Or use a ready-made installer for Windows.
Cloud-init is a cross-platform tool used to initialize a virtual machine during its first boot and apply configuration through metadata. Typical tasks include setting the hostname, configuring networking, adding SSH keys, creating users, and running initialization commands or scripts.
To provide initialization data when preparing an image locally, this guide uses a small ISO file called seed.iso. During the first boot, cloud-init reads the contents of this ISO and applies the defined settings.
The ISO contains two files:
user-data – defines users, SSH keys, and other initialization settings
meta-data – specifies basic instance parameters, such as hostname
Create two plain text files named user-data and meta-data (without file extensions) and place them in the same directory before building the ISO.
Example user-data:
#cloud-config
users:
- name: cloud-user
shell: /bin/bash
groups: sudo
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- INSERT_YOUR_SSH_KEY_HERE
- name: admin
shell: /bin/bash
groups: sudo
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- INSERT_YOUR_SSH_KEY_HERE
ssh_pwauth: false
hostname: fedora-vmIn the example above, ssh_pwauth is set to false to allow authentication only with SSH keys. Setting it to true can be helpful during testing or when verifying that cloud-init applied your configuration.
Before uploading your prepared image to the customer portal, make sure to disable password authentication again and rely on SSH keys only.
Example meta-data:
local-hostname: fedora-vm
Specifying local-hostname in meta-data is sufficient; instance-id is generated automatically by cloud-init.
Then pack these files into an ISO image that will later be attached to the virtual machine.
Use one of the supported tools to generate a compatible ISO. The recommended method is cloud-localds. If not available, use mkisofs or genisoimage.
Run the command directly in the directory that contains these files.
cloud-localds seed.iso user-data meta-data
Alternatives:
mkisofs -output seed.iso -volid cidata -joliet -rock user-data meta-data
or
genisoimage -output cidata.iso -volid cidata -joliet -rock -graft-points user-data=./user-data meta-data=./meta-data
C:\path-to-oscdimg-exe-file -j1 -lcidata C:\path-to-cloud-init-config-files .\seed.iso
The oscdimg.exe utility is typically located at:
%ProgramFiles(x86)%\Windows Kits\<Windows version>\Assessment and Deployment Kit\Deployment Tools\<architecture>\Oscdimg\oscdimg.exe
Where:
amd64 or arm64, depending on your systemA seed.iso file will be created in the same directory.
Start the virtual machine with your OS image and the seed.iso attached.
Before starting the VM, note the following parameter used in the launch command: -netdev user,id=net0,hostfwd=tcp::2222-:22
This option sets up port forwarding from the host to the VM. It maps host port 2222 to port 22 inside the VM. You will use this forwarded port later when connectiong the VM after it boots.
Using -m and -smp parameters, set the VM's memory and vCPUs to match the configuration you plan to use on the cloud server.
qemu-system-x86_64 \
-m 2048 -smp 2 \
-drive file=cloud-image.qcow2,format=qcow2,if=virtio \
-drive file=seed.iso,format=raw,if=virtio \
-netdev user,id=net0,hostfwd=tcp::2222-:22 \
-device virtio-net,netdev=net0 \
-nographicFor subsequent boots, remove the line -drive file=seed.iso,format=raw,if=virtio
qemu-system-x86_64 \
-accel tcg,thread=multi \
-m 2048 -smp 2 \
-boot once=d \
-drive file=generic_alpine.qcow2,if=virtio,format=qcow2 \
-cdrom seed.iso \
-device virtio-net-pci,netdev=n1 \
-netdev user,id=n1,hostfwd=tcp::2222-:22 \
-nographicFor subsequent boots, remove lines -boot once=d and -cdrom seed.iso
Navigate into the QEMU installation directory (%ProgramFiles%\qemu, by default) and run the VM with the following command:
.\qemu-system-x86_64.exe ^
-m 2048 -smp 2 ^
-boot once=d ^
-drive file=,if=virtio,format=qcow2 ^
-cdrom ^
-device virtio-net-pci,netdev=n1 ^
-netdev user,id=n1,hostfwd=tcp::2222-:22 For subsequent boots, remove the lines -boot once=d and -cdrom <C:\path-to-seed.iso>.
After the VM starts, connect to it via SSH using the command:
ssh -p 2222 <user>@localhost
To verify cloud-init behavior, run:
cloud-init status --long
On non-cloud ISO images, this command often shows status: disabled in output, because the VM does not receive any cloud metadata during local testing. This is expected. After you upload the prepared image to the customer portal and deploy a cloud server, our provisioning system provides the proper OpenStack datasource, cloud-init runs normally, and the default cloud-user is created with the SSH key you selected during deployment.
You can deploy a cloud server directly from a vendor-provided cloud-compatible image without creating a local virtual machine first. This method is useful if you need to deploy a cloud server from a vendor-provided image that is not available in our catalog and you do not require any customization. To do this:
alpine:ssh alpine@<cloud_server_public_ip>
Some cloud-compatible images come with only a minimal default user. For example, an Alpine cloud image may include only the alpine default user with limited permissions. After you deploy a cloud server from such an image and connect over SSH as the default user, create a separate privileged account (for example, an admin user with sudo access) and use it for further work with the server.
Example: Creating a privileged user after creating a cloud server
doas -s
apk update
apk add sudo
adduser alpine wheel
adduser cloud-user
adduser cloud-user wheel
mkdir -p /home/cloud-user/.ssh
echo 'ssh-rsa your_public_SSH_key' > /home/cloud-user/.ssh/authorized_keys
chmod 700 /home/cloud-user/.ssh
chmod 600 /home/cloud-user/.ssh/authorized_keys
chown -R cloud-user:cloud-user /home/cloud-user/.ssh
/etc/ssh/sshd_config with vi or install nano (recommended):apk add nano
nano /etc/ssh/sshd_config
PubkeyAuthentication yes
PasswordAuthentication no
Check if the user is unlocked
Open /etc/shadow and ensure the line for cloud-user does not contain "!"
If it does, replace it with:
cloud-user:*:::::::
This allows SSH login while keeping password authentication disabled.
rc-service sshd restart
ssh admin@<server_ip>
The server now supports login using the admin account with key-based SSH authentication and administrative privileges via sudo.
This section explains how to customize a vendor-provided cloud-compatible image before uploading it to the customer portal.
Since these images already include cloud-init, you only apply your changes and save the updated image. These images already include cloud-init, so you can configure the VM, install software, adjust system settings, create users, and then save the updated image for deployment.
user-data and meta-data) and generate the seed.iso
This section covers preparing a VM created from an ISO image, that does not include cloud-init or any cloud-specific configuration. The goal is simply to make the image boot correctly in OpenStack and accept initialization meta-data during the first launch.
When installing an OS from an ISO, you must first create a virtual disk, because the ISO is not a disk image. This creates the disk file.
Note: it does not mount it anywhere (QEMU will mount it when you run -drive file=…). You can choose any <disk-size> that fits your OS installation requirements (for example, 4G).
qemu-img create -f qcow2 path-to-cloud-image.qcow2 <disk-size>
Navigate into the QEMU installation directory (%ProgramFiles%\qemu, by default), and run the following command:
.\qemu-img.exe create -f qcow2 C:\path-to-cloud-image.qcow2 <disk-size>
The first boot must use the installation ISO (for example, ubuntu-25.10-live-server-amd64.iso). The seed.iso is not used at this stage, because cloud-init is not yet installed.
Attach the ISO as a virtual CD-ROM device. See Launching a VM with QEMU.
...
-cdrom ubuntu-25.10-live-server-amd64.iso \
-boot order=d \
...
This lets the VM boot from the OS installer instead of booting from the empty virtual disk.
Cloud-init does not require a "clean" system. Your ISO-based image may already contain:
boot order=d parameterboot order=d tells QEMU to boot from the CD-ROM. After the OS is installed, the VM must boot from its virtual disk instead.
sudo apt install openssh-server
sudo systemctl enable ssh
sudo systemctl start ssh
cloud-init is a common init that will:
Utilities such as cloud-utils or cloud-utils-growpart provide growpart for automatically expanding the root partition when the flavor disk is larger than the original image.
sudo dnf install -y cloud-init
sudo systemctl enable cloud-init
sudo apt update
sudo apt install -y cloud-init
sudo systemctl enable cloud-init
/etc/cloud/cloud.cfg.d/99-openstack-datasource.cfg
/etc/cloud/cloud.cfg.d/ directory is the standard place for user overrides. The 99- prefix in the file name makes sure this configuration is loaded last. Files are processed in alphabetical order, so 99-openstack-datasource.cfg overrides earlier datasource_list settings.datasource_list: [NoCloud, Ec2, ConfigDrive]
This tells cloud-init to look for instance metadata and user data using standard OpenStack-compatible datasources, including NoCloud, which you will emulate via iso.To provide initialization data for your image, attach the previously created seed.iso (see Cloud-init setup). When the ISO is attached to the VM, cloud-init reads it as a NoCloud datasource and applies the configuration from user-data and meta-data during the first boot. After initialization completes, seed.iso is no longer required and can be removed for all subsequent VM launches.
OpenStack expects the image to expand the root partition and filesystem on first boot if the flavor disk size is larger than the original image.
Do the following:
growpart and resizefs are present in the module lists in /etc/cloud/cloud.cfggrep -A3 -i growpart /etc/cloud/cloud.cfg
grep -A3 -i resizefs /etc/cloud/cloud.cfg
For modern Ubuntu (netplan):
/etc/netplan/*.yaml and make sure dhcp4: true is used,If the system is configured for DHCP by default, you usually do not need to change anything.
If the file 70-persistent-net.rules exists, it is recommended to remove it to avoid persisting old MAC addresses:
cat /etc/udev/rules.d/70-persistent-net.rules
rm /etc/udev/rules.d/70-persistent-net.rules
Remove VM-specific state and temporary data so that each new instance starts "clean":
/var/lib/cloud)systemd journals~/.ssh/authorized_keys files (keys will be injected through cloud-init)After you verify that the virtual machine (VM) meets the image requirements, finalize the disk so it is ready for upload to the customer portal. Some preparation steps differ depending on the operating system.
sudo cloud-init clean --logs
sudo rm -rf /var/lib/cloud/*
For Ubuntu/Debian, also confirm that /etc/cloud/cloud.cfg.d/*.cfg does not contain test-specific datasource overrides.
sudo rm -f /etc/ssh/ssh_host_*
sudo rm -f /home/*/.ssh/authorized_keys
sudo rm -f /root/.ssh/authorized_keys
sudo rm -f /etc/udev/rules.d/70-persistent-net.rules
Remove host keys and cloud-init or bsd-cloudinit state:
sudo rm /etc/ssh/ssh_host_*
sudo rm -rf /var/db/cloud/*
sudo shutdown -h now
sudo shutdown -p now
The resulting QCOW2 disk is your OpenStack-compatible image.
Use this command to optimize the image:
qemu-img convert -O qcow2 -c original.qcow2 optimized.qcow2
Check the resulting size:
qemu-img info optimized.qcow2
Now the image file is ready for upload to the customer portal.
We recommend disabling any VPN when uploading an image. If the uploading fails, try to restart the process. If the issue persists, contact our support team for assistance.
user-data.Wait for cloud server deployment and get a public IP address to connect to the server in the server's details page.
Access to the deployed server depends on the operating system in the image. See the How to access the cloud server.
SSH access with root is disabled in most vendor images by default.
When a cloud server is provisioned from a custom image, the cloud-user is created and injects the SSH key you selected during server creation into its ~/.ssh/authorized_keys.
Usernames can vary slightly between distributions or custom vendor builds – check the image description page for confirmation.
Use this table to find the default login user for common vendor cloud images.
| Ubuntu | ubuntu |
| Debian | debian |
| Fedora | fedora |
| AlmaLinux | almalinux |
| Alpine Linux | alpine |
| RHEL | cloud-user |
| openSUSE | opensuse |
| FreeBSD | freebsd |
| OpenBSD | openbsd |
| NetBSD | netbsd |