Creating a virtual machine using Fedora Server Edition disk image

Peter Boy, Jocelyn Gould Version F39-F44 Last review: 2026-07-30
Installation of Fedora Server Edition in a virtual machine is a supported way for a long time by using the standard installation program in a Virtual Machine. Another option is to download a pre-built Fedora Server Edition virtual disk image and mount that in a virtual machine. The former can be quite flexibly adapted to a specific, individual requirement. The latter entails a default installation, but requires much less time and effort. It is the scope of this guidance.

There are 2 ways to create a Fedora Server in a virtual machine. System administrators can use the standard installation program as described in Installing a Fedora Server virtual machine using Cockpit. In this process, a number of properties and functionalities can be adapted to local requirements. Or they can download a Fedora Server virtual disk image containing an already preinstalled, pre-configured and ready-to-run operating system and mount it in a virtual machine.

There exist a multitude of virtual disk images that claim to provide a 'Fedora server'. An example of this is the virt-builder system. However, it is not a Fedora Server, but its own, deviating concept for the configuration of a server, more or less based on the Fedora distribution. And accordingly, e.g., the Fedora Server administration tools and principles will likely not fit.

What you get

To begin with, you gain time. Instantiating a virtual disk image takes only a few minutes, as opposed to running through the standard installation routines. The workload is significantly lower and correspondingly faster.

Fedora Server KVM image resembles all features and properties of a Fedora Server as close as possible, except for directly hardware-related measures, of course. In general, the system administrator of a virtual server (guest system) can perform configuration and administration largely independently and autonomously from the system administrator of the host system. Ideally, they should not notice any difference in everyday practice. As the system administrator of the host is limited by the available hardware resources, the administrator of the guest system is just limited only by the virtual hardware resources.

Fedora Server Edition and Fedora Cloud Edition

Unlike a cloud image, Fedora Server VM is designed to run like any autonomous standalone server, albeit optimized for a hypervisor (here QEMU/KVM/libvirt) rather than bare-metal hardware.

Both have in common that they adhere to the build process and control of the distribution. However, they follow different principles of data administration and organization, and are subject to different workflows.

How it works

The creation of a virtual machine image involves two steps.

  1. Provisioning the server VM image

    Basically you will download the distributed image file and keep it available for creating one or mostly several virtual servers. The appropriate location for this is /var/lib/libvirt/boot.

  2. Instantiation of a Server virtual machine

    To do this, first create a copy of the distribution image in the pool of disk images (/var/lib/libvirt/images) with the name of the VM to be instantiated. This image is then imported into Libvirt using one of the following methods.

    1. Import via CLI using minimal integrated initial configuration

    2. Import via Cockpit with comfortable minimal initial configuration

    Each of these alternatives then follows a more detailed, mission-specific follow-up customization.

Overall, the process is very straightforward and efficient.

Provisioning the server VM image

We assume a complete installation of virtualization support according to the Adding Virtualization Support guide.

  1. Download the Fedora Server Edition virtual disk image

    If not already done, download and verify the image in the Installation media storage pool. For ARM machines replace 'x86_64' by 'aarcb64' in the following example.

    $ sudo -i
    # cd /var/lib/libvirt/boot
    # wget https://download.fedoraproject.org/pub/fedora/linux/releases/44/Server/x86_64/images/Fedora-Server-Guest-Generic-44-1.7.x86_64.qcow2
    # wget https://dl.fedoraproject.org/pub/fedora/linux/releases/44/Server/x86_64/images/Fedora-Server-44-1.7-x86_64-CHECKSUM
    # curl -O https://fedoraproject.org/fedora.gpg
    # gpgv --keyring ./fedora.gpg Fedora-Server-44-1.7-x86_64-CHECKSUM
    # sh -c ' cd /var/lib/libvirt/boot/  &&  sha256sum --ignore-missing -c *-CHECKSUM '
    Fedora-Server-Guest-Generic-44-1.7.x86_64.qcow2: OK
    sha256sum: WARNING: 17 lines are improperly formatted

    You can safely ignore the warning. Important is just the OK status of the image.

    If you copy or move files directly from elsewhere, you should check the correct SELinux label and correct it if necessary.

    # ls -alZ /var/lib/libvirt/boot/*
    # restorecon -R -vF /var/lib/libvirt/boot/*
  2. Adjust the image file as required

    The size of the distribution file optimises efficient deployment and file transfer. The maximum disk size of the server VM image file is 10 GiB. This is not intended for productive operation, but as a starting point for customization.

    The minimal recommended size is about 20G. To save your adjustment for further instantiations, create a customized base image.

    # cd /var/lib/libvirt/boot
    # cp Fedora-Server-Guest-Generic-44-1.7.x86_64.qcow2 Fedora-Server-VM-44-custom.qcow2
    # qemu-img info   /var/lib/libvirt/boot/Fedora-Server-VM-44-custom.qcow2
    # qemu-img resize /var/lib/libvirt/boot/Fedora-Server-VM-44-custom.qcow2 40G
    # qemu-img info   /var/lib/libvirt/boot/Fedora-Server-VM-44-custom.qcow2

    The example above expands the maximal capacity to 40 GiB. You can resize the virtual disk later, too. Therefore, there is no reason to plan too generously in terms of size now. Due to the qcow2 format resizing does not affect the current image file size. It is dynamically adjusted as needed up to the maximum specified.

Instantiation of a server virtual machine

Alternative 1: Efficiently import via CLI

Copy the customized distribution file into the disk image pool, then use virt-install to create the new virtual machine. In this example, we will assume that the VM has two interfaces: one for connecting to the public network and one for connecting to the internal, protected network. Adjust this according to your needs. You can even install the VM without any interfaces. If you do so, you must use the virsh console ("virsh console <VM_NAME>") to log in and obtain a terminal window.

# cp /var/lib/libvirt/boot/Fedora-Server-VM-44-custom.qcow2  /var/lib/libvirt/images/${VM_NAME}.qcow2
# virt-install  --name ${VM_NAME} \
     --memory 4096  --cpu host --vcpus 2 --graphics none \
     --os-variant fedora-unknown \
     --import  \
     --disk /var/lib/libvirt/images/${VM_NAME}.qcow2,format=qcow2,bus=virtio \
     --network type=direct,source=enp1s0,source_mode=bridge,model=virtio \
     --network bridge=virbr0,model=virtio

We use here "fedora-unknown" as os variant. The reason is that the list of known OS versions is usually only updated at a later stage. You could also try “--os-variant fedora44”.

The parameters are quite descriptive and must be adjusted as needed. This example configures two network interfaces. One interface shares the physical public interface in direct mode. the other provides an internal interface via a virtual bridge, as defined during the libvirt installation process. If your public interface resembles a virtual bridge, adjust the command accordingly. Leave out the ones you do not need. You will find a more detailed explanation in the upstream documentation.

Then, a lot of messages scroll across the screen. If the network interface does not provide DHCP, in includes a NetworkManager error message. You can safely ignore this message for now. Finally, it ends with a simple, text-based input mask for the first-boot-configuration.

Starting install...
Running text console command: virsh --connect qemu:///system console rbox03
Connected to domain 'rbox03'
Escape character is ^] (Ctrl + ])
...
[  OK  ] Reached target User and Group Name Lookups.
         Starting User Login Management...
[  OK  ] Started NTP client/server.
[   21.523663] NET: Registered PF_QIPCRTR protocol family
================================================================================
================================================================================

1) [x] Language settings                 2) [x] Time settings
       (English (United States))                (Etc/UTC timezone)
3) [x] Network configuration             4) [x] Root password
       (Connected: enp2s0, enp1s0)              (Root account is disabled)
5) [ ] User creation
       (No user will be created)

Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
refresh]:

Specifically, with networks without DHCP you may get a [FAILED] Failed to start NetworkMan…[0m - Network Manager Wait Online. which you safely can ignore for now.

We continue with this form in the step after describing the Cockpit way of instantiation.

Alternative 2: Comfortably import via Cockpit

  1. Open Cockpit on your host system. The import expects the virtual hard disk at the final location. Therefore, select terminal at the bottom of the left navigation column and copy the prepared customized disk image into the disk image pool, as you did in alternative 1 (CLI import).

    diskimg fedoraserver 01
    Figure 1. Cockpit initial terminal
  2. Select "Virtual Machines" in the left navigation column and select "Import VM" at the right top of the central window area.

    diskimg fedoraserver 02
    Figure 2. Cockpit import screen

    Fill in the input fields as appropriate and leave "Connection" on "System" as preselected.

  3. If the VM to be created should only have one network interface connected to the internal libvirt bridge (virbr0), select Import and run. In all other cases, select Import and edit to set up the correct network connection before the first boot.

    diskimg fedoraserver 03
    Figure 3. Cockpit new virtual machine overview screen
  4. Scroll down to get to the network and devices section

    diskimg fedoraserver 04
    Figure 4. Network and devices screen

    In the network section, you see one Interface with Source default, i.e. virbr0. In order to easily manage the default route, this interface - the first one created - should connect to the public external network. Therefore, we start with changing this interface into the public one. Important: To keep the intended order of interfaces, do nothing else at tis point as to edit this interface!

  5. Select the Edit button to adjust the network connection setup.

    diskimg fedoraserver 05
    Figure 5. Network re-configuration screen

    Modify Interface type to Direct attachment and Source to the physical host external interface (enp1s0) and select bridge mode. Leave Model and MAC address unchanged!

    Finally, select Save. You will return to Network and devices.

  6. In the row "Network interfaces" select Add network interface on the right side.

    diskimg fedoraserver 06
    Figure 6. Add network interface

    The form opening already has Network Type selected and correctly configured. Leave all settings unchanged and close the form with the Add button.

  7. The network and devices part of the screen now contains 2 network interfaces in the correct order.

    diskimg fedoraserver 07
    Figure 7. Two network interfaces configured
  8. Scroll up and select Start in the middle of the central window. In the console window you will see the creation and startup of the virtual machine. Expand the console window.

    diskimg fedoraserver 08
    Figure 8. Minimal initial configuration form

    Finally, the screen displays the same configuration menu as with a CLI setup. Continue with the minimal initial configuration.

Minimal initial configuration

You have to use the terminal for this step, whether you performed the instantiation via CLI or via Cockpit.

  1. Complete the first boot configuration

    ================================================================================
    ================================================================================
    
    1) [x] Language settings                 2) [x] Time settings
           (English (United States))                (Etc/UTC timezone)
    3) [x] Network configuration             4) [x] Root password
           (Connected: enp2s0, enp1s0)              (Root account is disabled)
    5) [ ] User creation
           (No user will be created)
    
    Please make a selection from the above ['c' to continue, 'q' to quit, 'r' to
    refresh]:

    The clear majority of the input options are already preset with values that correspond exactly to a default installation using the Anaconda Fedora Server Edition installation program. The ROOT account is locked, as is common security practice. The only mandatory remaining task is the creation of a user account granted with administrator privileges.

    The selection of a menu item to be edited is made via the digit in front of it. Somewhat unusual in these days and age. The process is unfortunately a bit cumbersome. A "5" navigates to the item "User creation" and a "1" then to the creation of a new user.

    ================================================================================
    ================================================================================
    
    User creation
    
    1) [x] Create user
    2) Full name
    3) User name
    4) [x] Use password
    5) Password
    6) [x] Administrator
    7) Groups
       wheel
    
    Please make a selection from the above ['c' to continue, 'h' to help, 'q' to
    quit, 'r' to refresh]:

    The "[x]" in front of Create user indicates that the user creation process is activ. Accordingly, password authentication is enabled for the new user as well as administrator privileges. Fill in the required information and in any case ensure to activate the adminstrator privileges! It automatically adds "wheel" to Groups.

    ================================================================================
    ================================================================================
    
    User creation
    
    1) [x] Create user
    2) Full name
       Peter
    3) User name
       peter
    4) [x] Use password
    5) Password
       Password set.
    6) [x] Administrator
    7) Groups
       wheel
    
    Please make a selection from the above ['c' to continue, 'h' to help, 'q' to
    quit, 'r' to refresh]:

    With all user options set, the 'c' returns back to the overview screen.

    All non-British users may grab the opportunity to adjust the time zone using option 2 now.

    Another "c" continues with the execution of the entire configuration process. The operation takes some time and then ends in a login prompt.

    ...
    ...
    [  OK  ] Finished Initial Setup configuration program.
    [  OK  ] Reached target Preparation for Logins.
    [  OK  ] Started Getty on tty1.
    [  OK  ] Started Serial Getty on ttyS0.
    [  OK  ] Reached target Login Prompts.
    [  OK  ] Reached target Multi-User System.
             Starting Record Runlevel Change in UTMP...
    [  OK  ] Finished Record Runlevel Change in UTMP.
    
    Fedora Linux 44 (Server Edition)
    Kernel 6.19.10-300.fc44.x86_64 on an x86_64 (ttyS0)
    
    Web console: https://localhost:9090/ or https://192.168.158.155:9090/
    
    linux login:

    In the first lines you may see two SELinux messages alike "systemd-gpt-auto-generator[xxxx]: Failed to dissect: Permission denied". You can safely ignore these messages.

    The virtual server is up and running now, and ready for login. The initial configuration process is idiosyncratic, but it is simple and straightforward.

  2. Login

    Login with your credentials you have choosen in the first boot screen described above.

  3. Optionally: Adjust locale and non-US keyboard layout

    Users of a non-US keyboard layout probably want to customize the keyboard layout first of all. This facilitates any subsequent operation. First, check the current locale configuration

    # sudo -i
    # localectl
    System Locale: LANG=en_US.UTF-8
        VC Keymap: us
       X11 Layout: us
       X11 Model: pc105

    List available keyboard mappings filtered by your short county code part

    # localectl list-keymaps  | grep de-
    de-T3
    de-deadacute
    de-deadgraveacute
    de-deadtilde
    de-mac
    de-mac_nodeadkeys
    de-neo
    de-nodeadkeys
    ...

    Determine applicable key mapping and apply it

    # localectl set-keymap de-nodeadkeys

    The setting is immediately active.

  4. Set hostname

    A correct hostname is specifically important for DHCP of the internal network to work properly. A correct time is important for various tasks, specifically synchronization.

    1. Check hostname. You need a correct static hostname.

      # hostnamectl
    2. Set hostname if required:

      # hostnamectl  set-hostname  <YourFQDN>
  5. Check time zone and time synchronisation if you missed that previously

    1. Check time settings

      # timedatectl
    2. Correct time zone if necessary:

      # timedatectl set-timezone  <ZONE>
    3. If necessary, activate time synchronisation:

      # timedatectl set-ntp true
    4. Correct time if necessary:

      # timedatectl set-time  <TIME>

      If you get a warning about RTC time set to local time, follow the instructions to fix it.

  6. Consolidate the network configuration

    1. At first check your interfaces

      If you followed the example installation above you should find

      # ip a
      1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
          link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
          inet 127.0.0.1/8 scope host lo
          ....
      2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state ...
          link/ether 52:54:00:3e:0e:f0 brd ff:ff:ff:ff:ff:ff
          ...
      3: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 8000 qdisc fq_codel state ...
          link/ether 52:54:00:cc:e7:ba brd ff:ff:ff:ff:ff:ff
          inet 192.168.122.42/24 brd 192.168.122.255 scope global dynamic noprefixroute enp2s0
          ...

      If the external interface does not provide DHCP you will not find an assigned IP address for enp1s0. That is what we would need to fix next.

    2. Next let’s check and fix NetworkManager naming

      # nmcli con
      NAME    UUID                                  TYPE      DEVICE
      'Wired connection 2'  8d971f49-033f-398a-9714-3a4e848178fb  ethernet  enp2s0
      'Wired connection 1'  8d971f49-033f-398a-9714-3a4e848178fb  ethernet  ---

      Most likely your interfaces are a named somewhat awkward way. Let’s fix that to make administration of network easier and more comfortable. Do not forget to adjust the naming to your specific installation!

      # nmcli con mod 'Wired connection 1' connection.id enp1s0
      # nmcli con mod 'Wired connection 2' connection.id enp2s0
    3. In case DHCP is missing on an interface, configure a static network connection

      We take the external interface as an example here.

      # nmcli con mod enp1s0 ipv4.method manual \
           ipv4.address "xxx.xxx.xxx.xxx/yy" \
           ipv4.gateway "xxx.xxx.xxx.zzz" \
           ipv4.dns "xxx.xxx.xxx.vvv" \
           ipv6.method manual \
           ipv6.addresses xxxx:xxxx:xxxx:xxxx::yyyy/64 \
           ipv6.gateway xxxx:xxxx:xxxx:xxxx::zz \
           ipv6.dns "xxxx.xxxx.xxxx.xxxx::vvv"  \
           connection.zone "FedoraServer"
      # nmcli con up enp1s0
      # systemctl  restart  NetworkManager
    4. The interface enp2s0 for the internal libvirt network may show an IPv6 IP, which we do not use. Therefore, you should disable IPv6 on the internal interface

      # nmcli con mod enp2s0 ipv6.method disabled \
           connection.zone "trusted"
      # nmcli con up enp2s0
      # systemctl  restart  NetworkManager
    5. Check the default routes if you have 2 interfaces, one with an external public connection, one with the internal network, which uses NAT by default. So you have 2 parallel connection paths to access the public network and will find something like

      # ip r
      default via 192.168.158.1 dev enp1s0 proto dhcp src 192.168.158.160 metric 100
      default via 192.168.122.1 dev enp2s0 proto dhcp src 192.168.122.107 metric 101
      192.168.122.0/24 dev enp2s0 proto kernel scope link src 192.168.122.107 metric 101
      192.168.158.0/24 dev enp1s0 proto kernel scope link src 192.168.158.160 metric 100

      Delete the NAT route to avoid issues because of ambigous routes by some application software.

      # nmcli con mod enp2s0 ipv4.never-default yes
      # nmcli con down enp2s0
      # nmcli con up enp2s0
      # systemctl reload NetworkManager
      # ip r
      default via 192.168.158.1 dev enp1s0 proto dhcp src 192.168.158.160 metric 100
      192.168.122.0/24 dev enp2s0 proto kernel scope link src 192.168.122.107 metric 101
      192.168.158.0/24 dev enp1s0 proto kernel scope link src 192.168.158.160 metric 100
  7. Adjust firewall setting of the internal interface

    The installer assigns all interfaces to the FedoraServer zone, which limits access to ssh (and Cockpit). For the internal, protected network a broader accessibility may be appropriate, depending on the use case. If appropriate, modify the configuration (check alternative zone and select a suitable one).

    # firewall-cmd   --get-active-zones
    # firewall-cmd   --permanent  --zone=trusted  --change-interface=<internalIF>
    # firewall-cmd   --reload
    # firewall-cmd   --get-active-zones
  8. Optionally adjust default editor

    By default nano is the default system editor in Fedora. Many experienced system administrators prefer vim. If you are among the latter, adjust the default editor.

    # dnf install vim-default-editor --allowerasing
  9. F43 & 44: Fix the partition table’s LVM partition type

    The F44 release assigns a wrong type to one partition. Open the partition editor.

    […]# cfdisk /dev/vda
                                     Disk: /dev/vda
                   Size: 40 GiB, 42949672960 bytes, 83886080 sectors
              Label: gpt, identifier: BAD551E3-F483-4FB3-BF4C-EF516A914C13
    
        Device         Start         End     Sectors    Size Type
    >>  /dev/vda1       2048        6143        4096                2M BIOS boot
        /dev/vda2       6144     1030143     1024000             500M EFI System
        /dev/vda3    1030144     5126143     4096000      2G Linux extended boot
        /dev/vda4    5126144    83886039    78759896   37.6G Linux root (x86-64)
    
    
     ┌──────────────────────────────────────────────────────────────────────────┐
     │Partition UUID: 0534CD20-25E4-481A-AD28-E643E5328FDE                        │
     │Partition type: BIOS boot (21686148-6449-6E6F-744E-656564454649)            │
     └──────────────────────────────────────────────────────────────────────────┘
         [ Delete ]  [ Resize ]  [  Quit  ]  [  Type  ]  [  Help  ]  [  Write ]
         [  Dump  ]
           Device is currently in use, repartitioning is probably a bad idea.
                          Quit program without writing changes

    Select partition vda4, select type, scroll down and assign type "Linux LVM".

  10. Finally perform an update and reboot

    # dnf update
    # reboot
  11. Close the virsh console mode

    You were automatically in virsh’s console mode until now. Exit this mode and you will be back on the host system.

    # <ctrl>]
    Domain creation completed.
    #

If you opted for Cockpit to instantiate the VM you may use Cockpits graphical interface for the last 4 steps.

Anyway, you should now test to connect via ssh to the system using the usual way, i.e. using one of the configured interfaces.

Set up storage

Fedora Server VM guest basically follows the same storage organization principles as a bare metal installation. The Fedora Server Installation Guide explains the principles and the available choices. You have to make the same choice here.

The distributed disk image features a disk size of about 10 gb. This is not intended as a default value to use but as a starting value for adaptation to the specific installation requirement. You have probably already adjusted the desired maximum size during the [Provisioning the Server VM image]. Check the output from cfdisk to see whether the last partition has actually been adjusted accordingly. If not, shutdown the virtual machine and adjust the size now.

When qemu-img increases the maximum size of the image file, the last partition is also enlarged accordingly by default. However, the programme can neither adjust the volume group contained within the partition nor the logical volume of the root filesystem.

When installing on bare metal, there is the option to create a separate partition and volume group for user data. This would also be possible with a virtual disk image. However, as such an image generally requires significantly less storage space and a system partition cannot be installed separately, this is generally not advisable.

So you have to adjust the size of the Volume Group anyway.

Partition vda4 contains the Volume Group (VG).

# pvresize    /dev/vda4
  Physical volume "/dev/vda4" changed
  1 physical volume(s) resized or updated / 0 physical volume(s) not resized
# vgdisplay
  --- Volume group ---
  VG Name               systemVG
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  3
  VG Access             read/write
  VG Status             resizable
  ...
  VG Size               37.55 GiB
  PE Size               4.00 MiB
  Total PE              9613
  Alloc PE / Size       799 / 3.12 GiB
  Free  PE / Size       8814 / <34.43 GiB
  ...

The Volume Group now provides 37.55 GiB which is the size of the partition.

If you look at the Logical Volumes, there is one volume defined containing the root file system.

# lvdisplay
  --- Logical volume ---
  LV Path                /dev/systemVG/LVRoot
  LV Name                LVRoot
  VG Name                systemVG
  ...
  LV Size                3.12 GiB
  Current LE             799
  Segments               1
  ...

It is still 3.12 GiB as defined in the distribution file and needs adjustment, too.

Available alternatives

  1. Enlarge the Logical Volume to utilise all the free space, and expand the root filesystem accordingly.

    This way, there is no separation between system and user data. Whilst this is simple, it is by no means recommended.

  2. Enlarge the Logical Volume to utilise a reasonable amount of space and expand the root filesystem accordingly. Create logical volumes for user data or applications as required.

    This is the recommended approach. It provides separation of system and user data.

Alternative 2: Enlarge the LV and use the remaining free space for user data

  1. Enlarge the LV and the root file system.

    A recommended size is 8 - 15G max, depending on the total disk size. As an example, setting the new size is 12 G.

    # lvextend -L 12G  /dev/mapper/systemVG-LVRoot
      Size of logical volume systemVG/LVRoot changed from 3.12 GiB (799 extents) to 12.00 GiB (3072 extents).
      Logical volume systemVG/LVRoot successfully resized.
  2. Enlarge the XFS root filesystem to fill the LV

    # xfs_growfs /dev/mapper/systemVG-LVRoot
      meta-data=/dev/mapper/systemVG-LVRoot isize=512    agcount=4, agsize=204544 blks
               =                       sectsz=512   attr=2, projid32bit=1
               =                       crc=1        finobt=1, sparse=1, rmapbt=1
      ...
      data blocks changed from 818176 to 3145728
  3. Create an application specific storage space

    As an example, one of your service maybe a Jamstack based CMS with decentralized GIT repositories, e.g. Hugo, Jekyll or alike. You need a place where to store the Git repository with the static HTML files and other data. A /srv/<MYWEBAPP> would be a perfect place.

    1. The simple static way

      Create a Logical Volume and file system of appropriate size, mount it at /srv/ and create a subdirectory for each application therein.

      # lvcreate -L 20G -n srv  systemVG
       Logical volume "srv" created.
      # mkfs.xfs -L srv /dev/mapper/systemVG-srv
       meta-data=/dev/mapper/systemVG-srv isize=512    agcount=4, agsize=655360 blks
       ...
       Discarding blocks...Done.
      # echo "UUID=$(blkid -s UUID -o value /dev/systemVG/srv) /srv              auto    defaults    0 0"  >> /etc/fstab
      # mount -a
      # df -h
      # mkdir /srv/<MYWEBAPP>

      This creates a Logical Volume and XFS file system of 20G, mounts t at /srv and creates a Subdirectory for the Webapp’s data. Add additional subdirectories for each application.

    2. The elaborate way using thin provisioning

      In the case of thin provisioning, you create a dynamic logical volume which initially occupies only the space immediately required and then grows as needed up to a specified maximum size. This dynamic volume is mounted in a corresponding subdirectory within /srv/ on the root filesystem. Each application thus receives its own logical volume, which simplifies many maintenance processes and makes more effective use of the physically available space. All other features that make logical volumes so attractive from a maintenance and data security perspective are retained.

      The dynamic logical volumes reside in a thin pool, which technically must have a fixed size. The sum of the respective maximum sizes of the dynamic LVs it contains may nominally exceed the size of the pool, but in practice can only be utilised up to the specified physical size. The size of the thin pool can be expanded at any time, provided the physical or virtual disk allows it.

      Thin provisioning takes place in three steps.

      • Creating a thin provisioning pool

        In the example we specify a size of 20 G, which nearly occupies the available space. A following `lvs`checks if the result meets the expectation.

        # lvcreate -L 20G --thin systemVG/thinpool
          Thin pool volume with chunk size 64.00 KiB can address at most <15.88 TiB of data.
          Logical volume "thinpool" created.
        # lvs
          LV       VG       Attr       LSize  Pool Origin ...
          LVRoot   systemVG -wi-ao---- 12.00g                   thinpool systemVG twi-a-tz-- 20.00g             ...
      • Creating a thinly provisioned Logical Volume

        In this example we create a Logical Volume of 4G at maximum. The system will create it with an much lower initial size.

        # lvcreate -V 4G -T systemVG/thinpool -n <MYWEBAPP>
          Logical volume "<MYWEBAPP>" created.
        # lvs
          LV         VG       Attr       LSize  Pool      ...
          LVRoot     systemVG -wi-ao---- 12.00g
          <MYWEBAPP> systemVG Vwi-a-tz--  4.00g thinpool  ...
          thinpool   systemVG twi-aotz-- 20.00g           ...

        Repeat this step fot every application you have to provide with storage.

      • Mounting the file system at the intended location

        # mkdir /srv/<MYWEBAPP>
        # echo "UUID=$(blkid -s UUID -o value /dev/systemVG/<MYWEBAPP>) /srv/<MYWEBAPP>              auto    defaults    0 0"  >> /etc/fstab
        # mount -a
        # df -h

        Repeat this step for every application you have to provide with storage.

    Instead of using the command line, you can also switch to Cockpit and perform each of these operations in a graphical User Interface.

Creating additional storage ressources

Another way so separate system and user data is to create a separate virtual data disk.

You can use either CLI or Cockpit for this step.

Using CLI

  1. On the host system, create a new virtual disk in /var/lib/libvirt/images

    # qemu-img create -f qcow2 /var/lib/libvirt/images/${VM_NAME}-usr.qcow2  20G
    Formatting '/var/lib/libvirt/images/vm01-test-usr.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=21474836480 lazy_refcounts=off refcount_bits=16
    
    # qemu-img info  /var/lib/libvirt/images/${VM_NAME}-usr.qcow2
    file format: qcow2
    virtual size: 20 GiB (21474836480 bytes)
    disk size: 196 KiB
    cluster_size: 65536
    Format specific information:
        compat: 1.1
        compression type: zlib
        lazy refcounts: false
        refcount bits: 16
        corrupt: false
        extended l2: false
  2. Continue on the host and add the disk to the virtual machine. Use the first available diskname. The system disk is vda, so the next available disk name is vdb. If you are unsure check in the virtual machine, e.g. using 'lsblk'.

    # virsh attach-disk ${VM_NAME} /var/lib/libvirt/images/${VM_NAME}-usr.qcow2  vdb --cache default --persistent --targetbus=virtio --subdriver qcow2
    Disk attached successfully

    The command needs the absolute path to the image file as noted. Otherwise it will fail. The disk is available immediately.

    If you want to modify something, detach the file first.

    # virsh detach-disk ${VM_NAME}   vdb  --persistent
    Disk detached successfully
  3. On the virtual machine, use cfdisk to partition the disk according to your requirements. The example creates one partition spanning the entire disk capacity.

    First, cfdisk displays a list for selecting the partitioning type. Select GPT.

    # cfdisk  /dev/vdb
                                     Disk: /dev/vdb
                       Size: 192.5 KiB, 197120 bytes, 385 sectors
              Label: gpt, identifier: 2842C26B-A2F1-4946-9D89-AB8832E5FCEC
    
        Device                 Start        End      Sectors       Size Type
    >>  Free space                34        351          318       159K
    
    
    
               [   New  ]  [  Quit  ]  [  Help  ]  [  Write ]  [  Dump  ]
    
    
                          Create new partition from free space
  4. Create a Physical Volume (PV) in the new partition (adjust the device accordingly!)

    # pvcreate /dev/vdb1
      Physical volume "/dev/vdb1" successfully created.
  5. Create a Volume Group (VG) in the new Physical Volume (adjust the device accordingly!)

    # vgcreate  usrvg  /dev/vdb1

Later, use usrvg to create LVs for user data as needed.

Using Cockpit

  1. Open Cockpit on your host system, select Virtual Machines in the navigation column, and then select the machine to which you want to add a disk. Scroll down until you see the disk section. Finally, select Add disk on the right side of the subtitle bar.

    Cockpit add disk form

    Most of the input fields are suitably preconfigured. Enter a (file) name for the disk image. Use a consistent naming scheme to facilitate long-term system maintenance. Specify the intended maximum size of the disk and decide on "Always attach". It is best to leave the other properties untouched.

    Select Add to complete the task.

  2. Open Cockpit on the virtual machine you added the device to and select Storage. Cockpit assigns automatically the next disk identifier, /dev/vdb in case of Server VM.

    VM storage view
  3. Select the new disk and create a partition table and file system as needed.

    VM disk partitioning

Follow-up customization

It is advisable to review all the tasks in the general post-installation guide for virtual machines as well.