I am going to build this based on a series of small howto QEMU / KVM posts I've made as I feel much of the information is actually hard to find and piece together from the rest of the web.
What I'm going to focus on is how to use virtio as the NIC because if you don't you get very slow NIC speeds but with the virtio NIC model you basically get host speeds.
/usr/libexec/qemu-kvm -enable-kvm -smp 8 -m 16000 -net user -net nic,model=virtio -drive file=ubuntu-gpt2large.img,if=virtio
How To Create and Start a QEMU VM Manually:
On most distributions you'll find /dev/kvm is owned by the root user and group kvm.
Just add yourself to the kvm group and logoff and logon.
sudo usermod -a -G kvm username
If you don't want to logout you can try this:
exec su -l $USER
Just use
-drive file=/dev/sdb
If /dev/sdb was the drive you wanted to boot from.
This is an excellent way to save development time and boot Linux directly.
-kernel /arch/x86_64/boot/bzImage
Just pass the kernel option to the location of the kernel file.
If you need an initrd then pass it -initrd:
-initrd /path/to/initrd.img
How do I specify local NAT network only?
By default if you don't specify "-net" as network type it defaults to user mode networking. Basically you get a standard NAT IP that allows the VM to surf the net, download etc.. but it's not possible to remotely access the VM.
How to not have any NIC on the VM
-nic none
For security or testing reasons, you may not want the VM to have any NIC to prevent any access to the LAN/WAN.
Use this option to have no NIC, as by default prevents a NIC with usermode networking, which is essentially a NAT IP that takes you out to the internet.
How do specify my NIC as being virtio?
-net nic,model=virtio
How do you start in bridged mode and use the virtio accelerated network card/driver?
-netdev bridge,id=hn1 -device virtio-net-pci,netdev=hn1
You can also specify the mac, which is necessary as if you start multiple VMs they will default to the same MAC which breaks things of course
-netdev bridge,id=hn1 -device virtio-net-pci,netdev=hn1,mac="DE:AD:BE:EF:06:02"
*Newer QEMU requires the macaddr instead of mac:
-netdev bridge,id=hn1 -device virtio-net-pci,netdev=hn1,macaddr="DE:AD:BE:EF:06:02"
An example of using user mode networking instead of bridge:
qemu-system-x86_64 -enable-kvm -m 8096 -smp 8 Debian11-Wazuh.qcow2 -net nic,macaddr=DE:AD:BE:EF:AF:E8,netdev=hn1 -netdev user,id=hn1
For networking you must specify a netdev device netname and then on the -net nic line you must specify the same netname (eg. hn1), or you get errors like this and networking that is broken:
qemu-system-x86_64: warning: hub 0 is not connected to host network
qemu-system-x86_64: warning: netdev hn1 has no peer
Below enables the AC97 driver
-audiodev driver=pa,id=pa1,server=unix:/run/user/1000/pulse/native -device AC97,audiodev=pa1
-audiodev driver=pa,id=pa1,server=unix:/run/user/1000/pulse/native -device ich9-intel-hda -device hda-duplex,audiodev=pa1
Use the -bios switch and pass it the BIOS firmware location.
-bios /usr/share/ovmf/OVMF.fd
In Ubuntu/Debian you can install OVMF EFI firmware with:
sudo apt install ovmf
The bios file will be located in /usr/share/ovmf/OVMF.fd
Add these two options and you can boot a kernel or Linux iso straight from the terminal without needing any GUI (great for embedded/industrial solutions).
-append console=ttyS0 -nographic
This will enable a VNC port on localhost 5900. The number indicates 59xx so -vnc :0 means port 5900 or :1 means port 5901:
-vnc :1
You can securely connect to it by using SSH port forwarding eg.
ssh -L 6000:localhost:5901 user@host
The left side 6000 means the port on your local machine will take you to port 5901 on the remote machine that runs a QEMU VM on VNC port 5901.
This example forwards host port 2222 to port 22 on the VM for SSH. Of course it can used for any number of services and ports, with the exception that the host port must be unused of course (since ports cannot be shared).
Note that you do need the - after the 2222 or it will not work.
-net nic,netdev=hn1 -netdev user,hostfwd=tcp::2222-:22,id=hn1
-net nic,netdev=hn1 -netdev user,smb=/path/to/folder,id=hn1
You will need the OVMF firmware:
sudo apt install ovmf
The firmware will be installed to: /usr/share/ovmf/OVMF.fd
To boot from the network you need the "-boot n" flag which means boot from the network.
If you don't specify hte OVMF firmware the default BIOS image will be MBR so EFI won't work.
Specify the OVMF EFI BIOS with: -bios /usr/share/ovmf/OVMF.fd
qemu-system-x86_64 -smp 8 -m 4096 -enable-kvm -net nic,netdev=hn1 -netdev bridge,id=hn1 -boot n -bios /usr/share/ovmf/OVMF.fd -vnc :1
It's the same as EFI except we just don't specify the -bios as OVMF which was for EFI only. Without this flag and specifying an EFI BIOS we will boot in MBR mode.
qemu-system-x86_64 -smp 8 -m 4096 -enable-kvm -net nic,netdev=hn1 -netdev bridge,id=hn1 -boot n -vnc :1
By using the nbd driver we can do something similar to kpartx on a raw image, only with qcow2.
First load the nbd module
sudo modprobe nbd
Let's create the nbd device from the .qcow2 file
Change the DebianEFItest.qcow2 to the name and path of your qcow2 file.
sudo qemu-nbd -c /dev/nbd0
DebianEFItest.qcow2
Once you are done with the nbd0 device, make sure you disconnect it to prevent issues with corruption on the .qcow2
sudo qemu-nbd -d /dev/nbd0
/dev/nbd0 disconnected
Now we can access and partition the qcow2 through /dev/nbd0 like a normal disk/block device
sudo fdisk -l /dev/nbd0
Disk /dev/nbd0: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Full example of manipulating the qcow2 via the nbd block device:
realtechtalk.com VMs$:sudo fdisk /dev/nbd0
Welcome to fdisk (util-linux 2.34).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xc335a2a1.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p):
Using default response p.
Partition number (1-4, default 1):
First sector (2048-20971519, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-20971519, default 20971519): +500M
Created a new partition 1 of type 'Linux' and of size 500 MiB.
Command (m for help): n
Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p):
Using default response p.
Partition number (2-4, default 2):
First sector (1026048-20971519, default 1026048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (1026048-20971519, default 20971519):
Created a new partition 2 of type 'Linux' and of size 9.5 GiB.
Command (m for help): p
Disk /dev/nbd0: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc335a2a1
Device Boot Start End Sectors Size Id Type
/dev/nbd0p1 2048 1026047 1024000 500M 83 Linux
/dev/nbd0p2 1026048 20971519 19945472 9.5G 83 Linux
Command (m for help): t
Partition number (1,2, default 2): 1
Hex code (type L to list all codes): L
0 Empty 24 NEC DOS 81 Minix / old Lin bf Solaris
1 FAT12 27 Hidden NTFS Win 82 Linux swap / So c1 DRDOS/sec (FAT-
2 XENIX root 39 Plan 9 83 Linux c4 DRDOS/sec (FAT-
3 XENIX usr 3c PartitionMagic 84 OS/2 hidden or c6 DRDOS/sec (FAT-
4 FAT16 <32M 40 Venix 80286 85 Linux extended c7 Syrinx
5 Extended 41 PPC PReP Boot 86 NTFS volume set da Non-FS data
6 FAT16 42 SFS 87 NTFS volume set db CP/M / CTOS / .
7 HPFS/NTFS/exFAT 4d QNX4.x 88 Linux plaintext de Dell Utility
8 AIX 4e QNX4.x 2nd part 8e Linux LVM df BootIt
9 AIX bootable 4f QNX4.x 3rd part 93 Amoeba e1 DOS access
a OS/2 Boot Manag 50 OnTrack DM 94 Amoeba BBT e3 DOS R/O
b W95 FAT32 51 OnTrack DM6 Aux 9f BSD/OS e4 SpeedStor
c W95 FAT32 (LBA) 52 CP/M a0 IBM Thinkpad hi ea Rufus alignment
e W95 FAT16 (LBA) 53 OnTrack DM6 Aux a5 FreeBSD eb BeOS fs
f W95 Ext'd (LBA) 54 OnTrackDM6 a6 OpenBSD ee GPT
10 OPUS 55 EZ-Drive a7 NeXTSTEP ef EFI (FAT-12/16/
11 Hidden FAT12 56 Golden Bow a8 Darwin UFS f0 Linux/PA-RISC b
12 Compaq diagnost 5c Priam Edisk a9 NetBSD f1 SpeedStor
14 Hidden FAT16 <3 61 SpeedStor ab Darwin boot f4 SpeedStor
16 Hidden FAT16 63 GNU HURD or Sys af HFS / HFS+ f2 DOS secondary
17 Hidden HPFS/NTF 64 Novell Netware b7 BSDI fs fb VMware VMFS
18 AST SmartSleep 65 Novell Netware b8 BSDI swap fc VMware VMKCORE
1b Hidden W95 FAT3 70 DiskSecure Mult bb Boot Wizard hid fd Linux raid auto
1c Hidden W95 FAT3 75 PC/IX bc Acronis FAT32 L fe LANstep
1e Hidden W95 FAT1 80 Old Minix be Solaris boot ff BBT
Hex code (type L to list all codes): ef
Changed type of partition 'Linux' to 'EFI (FAT-12/16/32)'.
Command (m for help): p
Disk /dev/nbd0: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc335a2a1
Device Boot Start End Sectors Size Id Type
/dev/nbd0p1 2048 1026047 1024000 500M ef EFI (FAT-12/16/32)
/dev/nbd0p2 1026048 20971519 19945472 9.5G 83 Linux
Command (m for help): wq
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
realtechtalk.com VMs$:sudo mkfs.vfat /dev/nbd0p1
mkfs.fat 4.1 (2017-01-24)
realtechtalk.com VMs$:sudo mkfs.ext4 /dev/nbd0p2
mke2fs 1.45.5 (07-Jan-2020)
Discarding device blocks: failed - Input/output error
Creating filesystem with 2493184 4k blocks and 623392 inodes
Filesystem UUID: 77ab4895-80ea-45c1-b08f-975024f8b231
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632
Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
No protocol specified
Unable to init server: Could not connect: Connection refused
gtk initialization failed
This usually happens because the DISPLAY env variable is not set. You can normally fix it this way, assuming your display is :0
declare -x DISPLAY=":0"
qemu, kvm, guidei, posts, ve, virtio, nic, speeds, usr, libexec, enable, smp, user, ubuntu, gpt, img, specify, nat, default, quot, defaults, mode, networking, ip, allows, vm, surf, download, etc, remotely,