User Tools

Site Tools


manuals:vps:kvm

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
manuals:vps:kvm [2016/10/30 14:44] – created tomsmanuals:vps:kvm [2026/08/17 11:09] (current) – Link source and virtualization tests and correct the shared translation ID aither
Line 1: Line 1:
-====== Using KVM on vpsFree.cz  ======+<page>manuals:vps:kvm</page>
  
-This information page contains manuals on how to install and run KVM on Alpine Linux 3.4+, CentOS 7 and Debian 8.+<kb-managed 
 +  source="contract/pages/manuals-vps-kvm.txt" 
 +  test="kb/kvm#*" 
 +/>
  
-First, go the details of your VPS in vpsAdmin and turn on the following options:+====== KVM and libvirt inside a VPS ======
  
-  * Bridge – enables the creation of a network bridge that the KVM virtual machines will be connected to later, +===== Installing libvirt =====
-  * iptables – enables iptables, an option necessary to configure the IP masquerade, +
-  * KVM – enables KVM (for hardware support of virtualization).+
  
 +vpsAdminOS runs VPSes as containers, not as virtual machines. KVM inside a VPS
 +is therefore not nested virtualization: virtual machines use the physical
 +node's hardware virtualization directly. This guide uses the current **Debian
 +(latest)** template, libvirt and the ''qemu:///system'' system connection.
  
-===== KVM on Alpine Linux  =====+<vpsadmin-nav id="vps.features.open"> 
 +The **KVM** feature is required for virtualization. **TUN/TAP** is required for 
 +TAP-based virtual-machine network interfaces. Both features are enabled by 
 +default for new VPSes in the **Features** section of the VPS detail in 
 +vpsAdmin. 
 +</vpsadmin-nav>
  
-Install the required packages (ip6tables is optional):+{{:en:screenshots:vpsadmin:vps-details:feature-settings.png?direct|Default VPS features}}
  
-<code shell> +Install QEMU, libvirt and ''virt-install'' from Debian:
-apk update +
-apk add qemu-system-x86_64 qemu-openrc qemu-img bridge iptables ip6tables +
-</code>+
  
-Configure the bridge for Qemu/KVM virtual machines – create the ///etc/network/interfaces.tail// file (of course, you can choose any IP address from your private range):+<code bash> 
 +#!/usr/bin/env bash 
 +set -euo pipefail
  
-<code shell> +apt-get update 
-auto br0 +apt-get install --yes \ 
-iface br0 inet static +  iptables \ 
-     pre-up brctl addbr br0 +  libvirt-clients \ 
-     address 172.17.1.1 +  libvirt-daemon-system \ 
-     netmask 255.255.255.0 +  qemu-system-x86 \ 
-     post-down brctl delbr br0+  qemu-utils \ 
 +  virtinst 
 + 
 +virsh --connect qemu:///system version
 </code> </code>
  
-Since OpenVZ rewrites the ///etc/network/interfaces// file rather clumsily (this is also why we add the configuration of the bridge to //interfaces.tail//), it is safest to restart the container at this point.+Use the ''qemu:///system'' system connection. For remote administration, use 
 +libvirt over SSH, for example ''qemu+ssh://root@HOST/system'', and protect SSH 
 +with a keyDo not expose an unencrypted libvirt TCP socket to the Internet.
  
-Give the user in the //qemu// group permissions to manage the newly-created bridge:+===== Disk images and ZFS =====
  
-<code shell> +Use a separate [[manuals:vps:datasets|subdataset]] for disk imagesThis lets 
-echo "allow br0" > /etc/qemu/bridge.conf +you change ZFS properties for the workload later without affecting the VPS root 
-chown root:qemu /etc/qemu/bridge.conf +datasetPrepare the storage as follows:
-chmod 0640 /etc/qemu/bridge.conf +
-</code>+
  
-Configure the IP masquerade so that the Qemu/KVM virtual machines have access to the public Internet.+  * <vpsadmin-nav id="datasets.edit.open">In the VPS details, use **Edit** on the root dataset and reduce its reference quota by the capacity intended for images.</vpsadmin-nav> 
 +  * <vpsadmin-nav id="datasets.create.open">Use **Create dataset** to create a ''vm-images'' subdataset with the freed capacity.</vpsadmin-nav> 
 +  * <vpsadmin-nav id="datasets.mount.open">Use **Mount** on ''vm-images'' and mount it in the VPS at ''/srv/libvirt/images''.</vpsadmin-nav>
  
-If you have configured iptablesall you need to add is this rule:+For examplefrom the standard 120 GiB allocation you can leave 20 GiB for the 
 +root dataset and assign 100 GiB to ''vm-images''. You can then give the first 
 +virtual-machine disk 80 GiB and leave 20 GiB free for growth and snapshots.
  
-<code> +The subdataset is [[manuals:vps:backups|snapshotted]] separately from the VPS 
-iptables -t nat -A POSTROUTING -s 172.17.1.0/24 ! -o br0 -j MASQUERADE+root dataset. 
 + 
 +{{:en:screenshots:vpsadmin:vps-details:datasets.png?direct|VPS datasets}} 
 + 
 +Add the mounted directory to libvirt as a persistent storage pool: 
 + 
 +<code bash
 +#!/usr/bin/env bash 
 +set -euo pipefail 
 + 
 +virsh --connect qemu:///system pool-define-as \ 
 +  vm-images dir --target /srv/libvirt/images 
 +virsh --connect qemu:///system pool-start vm-images 
 +virsh --connect qemu:///system pool-autostart vm-images 
 +virsh --connect qemu:///system pool-info vm-images
 </code> </code>
  
-If notyou can follow our paragraph on [[#nastaveni_iptables|configuring iptables]].+Then create disks through libvirt''virt-install'' or ''virt-manager'' in the 
 +''vm-images'' pool.
  
 +Leave the subdataset's ZFS properties at their defaults unless measurements
 +show a reason to change them. Compression is enabled by default. The default
 +''recordsize=128K'' is the maximum record size for files; ZFS uses smaller
 +records when appropriate. A ''recordsize'' change applies only to newly created
 +files.
  
-==== Creating and Running Virtual Machine ====+For images on ZFS, ''raw'' is suitable default because it does not add another 
 +copy-on-write layer. Choose ''qcow2'' when you need backing files, internal 
 +snapshots, or other image-format features.
  
-This manual presupposes that you will be using [[https://github.com/jirutka/qemu-openrc|qemu-openrc]] – an OpenRC init script used to start Qemu/KVM. Of course, if you’re on Alpine, you can use libvirt as well, but do you really want and need its clumsy XML configuration files and/or the click interface above it...? ;) Qemu-openrc is a much simpler and more transparent solution. Each virtual machine is represented by an init script. Just like with other programs, you can declare dependencies between virtual machines, etc.+See [[https://openzfs.github.io/openzfs-docs/Performance%20and%20Tuning/Workload%20Tuning.html|OpenZFS Workload Tuning]] for workload-based tuning and the [[https://www.qemu.org/docs/master/system/images|QEMU documentation]] for image formats.
  
-Creating a new virtual machine consists only of preparing an image disk, creating a symlink for the init script and modifying a simple configuration script. Let’s say that the new virtual machine is called “myvirt.”+===== Virtual-machine networking =====
  
-Prepare raw image for myvirt with the required size:+The VPS network interface is connected to the node through routed layer-3 
 +link. Do not add the VPS interface to a bridge managed by libvirt. Two setups 
 +are suitable for connecting virtual machines:
  
-<code shell> +^ Setup ^ Addresses in the domain ^ Advantages ^ Disadvantages ^ 
-mkdir -p /var/lib/qemu/myvirt/ +| libvirt NAT | Private IPv4 and private ULA IPv6 | Works with the ordinary VPS addresses and easily serves several domains| Inbound services need port forwarding and traffic passes through NAT44 and NAT66| 
-qemu-img create -f raw /var/lib/qemu/myvirt/disk0.img 5G +| Routed public addresses | A public IPv4 ''/32'' and addresses from a separate IPv6 ''/64'' | The domain is directly reachable, without NAT or port translation| Requires a private IPv4 on the VPS, another routed IPv6 network, and a carefully configured firewall. |
-chown qemu:qemu /var/lib/qemu/myvirt/disk0.img +
-chmod 0600 /var/lib/qemu/myvirt/disk0.img +
-</code>+
  
-Copy the default configuration file /etc/conf.d/qemu to /etc/conf.d/qemu.myvirt and modify it as needed:+NAT is usually simpler for one or a few domains with a small number of exposed 
 +servicesUse routed addresses when a domain needs its own public addresses, 
 +all ports, or protocols that are awkward to handle with port forwardingFor 
 +backend-only communication between domains, you can attach another isolated 
 +libvirt network; outbound access still uses one of the setups above.
  
-<code shell+==== Public addresses on the VPS with dual-stack NAT ==== 
-cd /etc/conf.d + 
-cp qemu qemu.jarvis +The public IPv4 ''/32'' and IPv6 ''/64'' remain on the VPS. The domain receives 
-vi qemu.jarvis  # read comments and edit+''192.168.124.10/24'' and ''fd5f:6d2e:9c4a:124::10/64'' from the 
 +''dualstack-nat'' network. Libvirt translates outbound IPv4 with NAT44 and IPv6 
 +with NAT66. The ''default'' network in a typical libvirt installation is 
 +normally IPv4-only and uses ''192.168.122.0/24'', so this example defines an 
 +explicit dual-stack network with a distinct IPv4 subnet. NAT66 is enabled with 
 +''<nat ipv6='yes'/>''; see the 
 +[[https://libvirt.org/formatnetwork.html|libvirt network XML documentation]] for 
 +details
 + 
 +The ULA ''fd5f:6d2e:9c4a::/48'' is an example for a standalone installation. 
 +If you later join several private networks through a VPN or routing, generate a 
 +different random ULA ''/48'' for each network and change both ''HOST_IPV6'' and 
 +''GUEST_IPV6'' to addresses from the same ''/64''
 + 
 +The essential part of the network definition is: 
 + 
 +<code xml> 
 +<network> 
 +  <name>dualstack-nat</name> 
 +  <forward mode='nat'> 
 +    <nat ipv6='yes'/> 
 +  </forward> 
 +  <bridge name='virbr-nat'/> 
 +  <ip address='192.168.124.1' prefix='24'/> 
 +  <ip family='ipv6' address='fd5f:6d2e:9c4a:124::1' prefix='64'/> 
 +</network>
 </code> </code>
  
-Most importantlyadd the prepared image:+Attach the created domain to ''dualstack-nat'', for example with 
 +''--network network=dualstack-nat,model=virtio'' in ''virt-install''. Configure 
 +stable addresses and gateways in the domain: 
 + 
 +<code conf> 
 +auto ens3 
 +iface ens3 inet static 
 +    address 192.168.124.10/24 
 +    gateway 192.168.124.1
  
-<code shell> +iface ens3 inet6 static 
-disk1_file="/var/lib/qemu/myvirt/disk0.raw" +    address fd5f:6d2e:9c4a:124::10/64 
-disk1_format="raw"+    gateway fd5f:6d2e:9c4a:124::1
 </code> </code>
  
-You will probably also need to add the installation CD of a distribution that you have already downloaded:+A port forward consists of DNAT to the domain address and permission for the 
 +corresponding forwarded traffic. For an IPv4 web service, these are the 
 +essential commands:
  
-<code shell+<code bash
-cdrom0_file="/var/lib/qemu/alpine-virt-3.4.1-x86_64.iso"+iptables -t nat -I PREROUTING 1 -p tcp -d VPS_IPV4 --dport 80 \ 
 +  -j DNAT --to-destination 192.168.124.10:80 
 +iptables -t filter -I FORWARD 1 -p tcp -d 192.168.124.10 --dport 80 \ 
 +  -j ACCEPT
 </code> </code>
  
-Create a symlink for the init script and run myvirt.+Equivalent ''ip6tables'' rules are needed for IPv6. Rules entered by hand, 
 +however, are not preserved across libvirt network changes. The complete script 
 +below therefore creates the network, a forwarding configuration file, and a 
 +hook that restores the rules when the network starts or reconnects. By default, 
 +it exposes the domain's web service on port 80 and SSH on port 2222 over both 
 +IPv4 and IPv6.
  
-<code shell> +Save it as, for example, ''/root/configure-nat-port-forwards.sh'', then run it 
-cd /etc/init.d +with one public IPv4 and one address from the VPS IPv6 ''/64'' configured on the 
-ln -s qemu qemu.myvirt+VPS:
  
-rc-service qemu.myvirt start+<code bash> 
 +PUBLIC_IPV4=VPS_IPV4 PUBLIC_IPV6=VPS_IPV6 \ 
 +  /root/configure-nat-port-forwards.sh
 </code> </code>
  
 +Run the script when creating the network and again when changing its input
 +values, not after every VPS reboot. The network is set to autostart and its hook
 +loads the rules when it starts.
  
-==== Configuring iptables ====+<code bash> 
 +#!/usr/bin/env bash 
 +set -euo pipefail
  
-If you aren’t using any tool to generate iptables rules (like e.g. [[https://github.com/MaxKellermann/ferm|ferm]]), I recommend basing them on [https://gist.github.com/jirutka/3742890|existing rule templates]]. These are already in the iptables format, which can be loaded using iptables-restore.+: "${PUBLIC_IPV4:?set PUBLIC_IPV4 to the VPS public IPv4 address}" 
 +"${PUBLIC_IPV6:?set PUBLIC_IPV6 to a public IPv6 address of the VPS}"
  
-Download the modified rule template with the added masquerade for our bridge to /etc/iptables:+guest_ipv4=${GUEST_IPV4:-192.168.124.10} 
 +guest_ipv6=${GUEST_IPV6:-fd5f:6d2e:9c4a:124::10} 
 +host_ipv4=${HOST_IPV4:-192.168.124.1} 
 +host_ipv6=${HOST_IPV6:-fd5f:6d2e:9c4a:124::1} 
 +connection=qemu:///system 
 +network=dualstack-nat 
 +hook=/etc/libvirt/hooks/network.d/50-port-forwards 
 +config=/etc/libvirt/port-forwards.conf 
 +xml=$(mktemp) 
 +trap 'rm -f "$xml"' EXIT
  
-<code shell> +network_uuid=$(virsh --connect "$connection" net-uuid "$network" 2>/dev/null || :) 
-rmdir /etc/iptables +uuid_element= 
-wget -/etc/iptables http://haste.fit.cvut.cz/raw/iwuqoso +if [[ -n $network_uuid ]]; then 
-</code>+  uuid_element="  <uuid>$network_uuid</uuid>" 
 +fi 
 +cat >"$xml" <<EOF 
 +<network> 
 +  <name>$network</name> 
 +$uuid_element 
 +  <forward mode='nat'> 
 +    <nat ipv6='yes'/
 +  </forward> 
 +  <bridge name='virbr-nat' stp='on' delay='0'/> 
 +  <ip address='$host_ipv4' prefix='24'> 
 +    <dhcp> 
 +      <range start='192.168.124.100' end='192.168.124.254'/
 +    </dhcp> 
 +  </ip> 
 +  <ip family='ipv6' address='$host_ipv6' prefix='64'/> 
 +</network> 
 +EOF
  
-Modify the /etc/conf.d/iptables configuration file (IPv4):+if virsh --connect "$connection" net-list --name \ 
 +  | grep -Fx "$network" >/dev/null; then 
 +  printf '%s is activeShut down its attached domains, run ' "$network" >&
 +  printf 'virsh net-destroy %s, then rerun this script.\n' "$network" >&
 +  exit 1 
 +fi
  
-<code shell> +install -d -m 0755 /etc/libvirt/hooks/network.d 
-/etc/conf.d/iptables+install -d -m 0755 /etc/libvirt 
 +cat >"$hook" <<'HOOK' 
 +#!/usr/bin/env bash 
 +set -euo pipefail
  
-IPTABLES_SAVE="/etc/iptables" +PATH=/usr/sbin:/usr/bin:/sbin:/bin 
-#SAVE_RESTORE_OPTIONS="-c+network=${1-} 
-SAVE_ON_STOP="no+action=${2-} 
-IPFORWARD="yes+config=/etc/libvirt/port-forwards.conf 
-</code>+nat_chain=VPSFREE_KVM_DNAT 
 +filter_chain=VPSFREE_KVM_FWD 
 + 
 +[[ $network == dualstack-nat ]] || exit 0 
 +exec 9>/run/lock/vpsfree-kvm-port-forwards.lock 
 +flock 9 
 + 
 +delete_jumps() { 
 +  local tool 
 +  for tool in iptables ip6tables; do 
 +    while "$tool" -w -t nat -C PREROUTING -j "$nat_chain" 2>/dev/null; do 
 +      "$tool" -w -t nat -D PREROUTING -j "$nat_chain" 
 +    done 
 +    while "$tool" -w -t filter -C FORWARD -j "$filter_chain" 2>/dev/null; do 
 +      "$tool" -w -t filter -D FORWARD -j "$filter_chain" 
 +    done 
 +  done 
 +
 + 
 +delete_chains() { 
 +  local tool 
 +  for tool in iptables ip6tables; do 
 +    if "$tool" -w -t nat -S "$nat_chain" >/dev/null 2>&1; then 
 +      "$tool" -w -t nat -F "$nat_chain" 
 +      "$tool" -w -t nat -X "$nat_chain" 
 +    fi 
 +    if "$tool" -w -t filter -S "$filter_chain" >/dev/null 2>&1; then 
 +      "$tool" -w -t filter -F "$filter_chain" 
 +      "$tool" -w -t filter -X "$filter_chain" 
 +    fi 
 +  done 
 +
 + 
 +cleanup() { 
 +  delete_jumps 
 +  delete_chains 
 +
 + 
 +valid_ip_address() { 
 +  local family=$1 address=$2 
 + 
 +  perl -MSocket=AF_INET,AF_INET6,inet_pton -e ' 
 +    my ($family, $address) = @ARGV; 
 +    my $af = $family eq "ipv4" ? AF_INET : AF_INET6; 
 +    exit(defined(inet_pton($af, $address)) ? 0 : 1); 
 +  ' "$family" "$address" 
 +
 + 
 +if [[ $action == stopped ]]; then 
 +  cleanup 
 +  exit 0 
 +fi 
 +[[ $action == started || $action == reconnect ]] || exit 0 
 + 
 +entries=() 
 +while read -r family protocol public_ip public_port guest_ip guest_port extra \ 
 +    || [[ -n ${family:-} ]]; do 
 +  [[ -n ${family:-} && $family != \#* ]] || continue 
 +  [[ $family == ipv4 || $family == ipv6 ]] || { 
 +    printf 'Invalid address family in %s: %s\n' "$config" "$family" >&2 
 +    exit 1 
 +  } 
 +  [[ $protocol == tcp || $protocol == udp ]] || { 
 +    printf 'Invalid protocol in %s: %s\n' "$config"$protocol" >&
 +    exit 1 
 +  } 
 +  for address in "$public_ip" "$guest_ip"; do 
 +    valid_ip_address "$family" "$address" || { 
 +      printf 'Invalid %s address in %s: %s\n' \ 
 +        "$family" "$config" "$address" >&
 +      exit 1 
 +    } 
 +  done 
 +  [[ $public_port =~ ^[0-9]{1,5}$ && $guest_port =~ ^[0-9]{1,5}$ ]] || { 
 +    printf 'Invalid port in %s\n' "$config>&2 
 +    exit 1 
 +  } 
 +  public_port=$((10#$public_port)) 
 +  guest_port=$((10#$guest_port)) 
 +  ((public_port >= 1 && public_port <= 65535)) || exit 1 
 +  ((guest_port >= 1 && guest_port <= 65535)) || exit 1 
 +  [[ -z ${extra:-} ]] || { 
 +    printf 'Too many fields in %s\n' "$config" >&
 +    exit 1 
 +  } 
 +  entries+=("$family|$protocol|$public_ip|$public_port|$guest_ip|$guest_port"
 +done <"$config"
  
-…and the /etc/conf.d/ip6tables configuration file (IPv6):+cleanup 
 +for tool in iptables ip6tables; do 
 +  "$tool" -w -t nat -N "$nat_chain" 
 +  "$tool" -w -t filter -N "$filter_chain" 
 +done 
 +for entry in "${entries[@]}"; do 
 +  IFS='|' read -r family protocol public_ip public_port guest_ip guest_port \ 
 +    <<<"$entry" 
 +  tool=iptables 
 +  destination="$guest_ip:$guest_port" 
 +  if [[ $family == ipv6 ]]; then 
 +    tool=ip6tables 
 +    destination="[$guest_ip]:$guest_port" 
 +  fi 
 +  "$tool" -w -t nat -A "$nat_chain" -p "$protocol" -d "$public_ip"
 +    --dport "$public_port" -j DNAT --to-destination "$destination" 
 +  "$tool" -w -t filter -A "$filter_chain" -p "$protocol" -d "$guest_ip"
 +    --dport "$guest_port" -j ACCEPT 
 +done 
 +for tool in iptables ip6tables; do 
 +  "$tool" -w -t nat -I PREROUTING 1 -j "$nat_chain" 
 +  "$tool" -w -t filter -I FORWARD 1 -j "$filter_chain" 
 +done 
 +HOOK 
 +chmod 0755 "$hook"
  
-<code shell+cat >"$config" <<EOF 
-/etc/conf.d/ip6tables+FAMILY PROTOCOL PUBLIC_IP PUBLIC_PORT GUEST_IP GUEST_PORT 
 +ipv4 tcp $PUBLIC_IPV4 80 $guest_ipv4 80 
 +ipv4 tcp $PUBLIC_IPV4 2222 $guest_ipv4 22 
 +ipv6 tcp $PUBLIC_IPV6 80 $guest_ipv6 80 
 +ipv6 tcp $PUBLIC_IPV6 2222 $guest_ipv6 22 
 +EOF
  
-IP6TABLES_SAVE="/etc/iptables" +virsh --connect "$connection" net-define "$xml" 
-SAVE_RESTORE_OPTIONS="-T filter+virsh --connect "$connection" net-autostart "$network" 
-SAVE_ON_STOP="no+systemctl restart libvirtd.service 
-IPFORWARD="yes"+if ! virsh --connect "$connection" net-list --name \ 
 +  | grep -Fx "$network>/dev/null; then 
 +  virsh --connect "$connection" net-start "$network
 +fi 
 +"$hook"$network" started begin - 
 +virsh --connect "$connection" net-dumpxml "$network"
 </code> </code>
  
-Run iptables and ip6tables and add them to the runlevel boot:+Add another port to ''/etc/libvirt/port-forwards.conf'' as 
 +''FAMILY PROTOCOL PUBLIC_IP PUBLIC_PORT GUEST_IP GUEST_PORT''. For example, 
 +expose HTTPS on port 8443 over both protocols with:
  
-<code shell+<code conf
-rc-service iptables start +ipv4 tcp VPS_IPV4 8443 192.168.124.10 443 
-rc-service ip6tables start +ipv6 tcp VPS_IPV6 8443 fd5f:6d2e:9c4a:124::10 443
-rc-update add iptables boot +
-rc-update add ip6tables boot+
 </code> </code>
  
-==== Contacts ====+The supported protocols are ''tcp'' and ''udp''. A syntactically invalid line 
 +is rejected before the active rules are changed. Reload the rules after editing 
 +the file:
  
-  * [[jakub@jirutka.cz|Jakub Jirůtka]] (on [[irc://chat.freenode.net/vpsfree|#vpsfree]] under the name “jirutka”)+<code bash> 
 +/etc/libvirt/hooks/network.d/50-port-forwards   dualstack-nat started begin - 
 +</code>
  
-===== KVM on CentOS 7  =====+Port 2222 keeps the domain's SSH service separate from SSH on the VPS itself. 
 +Restrict the VPS firewall further according to who should reach each service.
  
-<note warning> +==== Private IPv4 on the VPS with public addresses in the domain ====
-This manual can only be used for CentOS 7.1. The internal network between VPS and VM currently isn’t working on CentOS 7.2. Until this problem is solved, please use either CentOS 7.1 or Debian 8. +
-</note>+
  
-I use KVM using libvirt on an updated CentOS 7.+In this setup, the VPS has a private IPv4 ''/32'' and its ordinary public IPv6 
 +''/64''. The domain receives a public IPv4 ''/32'' and an address from a 
 +separate IPv6 ''/64'' routed through an address in the VPS's first ''/64''. The 
 +private VPS IPv4 works on the internal vpsFree.cz network and reaches the 
 +Internet through NAT on our routers; libvirt does not translate the domain'
 +public addresses.
  
-I recommend fully updating CentOS 7configuring it and installing the required software. Because of iptables permissions, it is necessary to either configure or turn off firewalld.+For IPv4first ask support to assign a private IPv4 ''/32'' to the VPS.
  
-<code shell+<vpsadmin-nav id="networking.routable-addresses.open"
-yum group install virtualization-host-environment +Under **Networking → Routable addresses**, select the public ''/32'' in 
-yum install virt-manager xauth +**Address**, the VPS private address in **Via**, and the target VPS interface. 
-systemctl enable libvirtd +The public address is not configured on any interface inside the VPS; vpsAdminOS 
-systemctl disable firewalld +routes it to the VPS via the private address. 
-reboot+</vpsadmin-nav> 
 + 
 +<vpsadmin-nav id="networking.routable-addresses.open"> 
 +For IPv6, use another ''/64'' available to you under **Networking → Routable 
 +addresses** and route it through an address in the VPS's ordinary ''/64''. If 
 +you already have a larger routed network such as a ''/48'', select a dedicated 
 +''/64'' from it for the domain. Use the first address of this second ''/64'' as 
 +the gateway on the libvirt bridge; for example, ''ROUTED_IPV6_PREFIX::1'' for 
 +''ROUTED_IPV6_PREFIX::/64''
 +</vpsadmin-nav> 
 + 
 +IPv4 uses a small transit network only between the VPS and the domain: 
 + 
 +<code> 
 +Internet → public /32 → VPS → 192.168.123.1/30 
 +                                 ↓ 
 +                           192.168.123.2/30 → public /32 in the domain
 </code> </code>
  
-==== Creating Virtual Machine Using virt-manager on the Side of the Server ====+In the libvirt XML, the public IPv4 is separate route through the domain'
 +transit address. The routed IPv6 ''/64'', on the other hand, is directly on the 
 +bridge:
  
-MotivationWhen you’re working on a slow connection (which the ADSL that the O2 provides in villages definitely is), you will need to minimize the data flow through your primary computerThe local virt-manager would download at least the kernel and initramdisk using the relatively slow download speedThe typically extremely slow upload speed would be used to upload to the host container.+<code xml> 
 +<network> 
 +  <name>public-routed</name> 
 +  <forward mode='open'/> 
 +  <bridge name='virbr-public'/> 
 +  <ip address='192.168.123.1' prefix='30'/> 
 +  <ip family='ipv6' address='ROUTED_IPV6_PREFIX::1' prefix='64'/> 
 +  <route family='ipv4' address='PUBLIC_IPV4' prefix='32' 
 +         gateway='192.168.123.2'/> 
 +</network> 
 +</code>
  
-<code shell+The VPS must forward both protocols: 
-ssh root@your-host-name -Y virt-manager+ 
 +<code bash
 +sysctl -w net.ipv4.ip_forward=1 
 +sysctl -w net.ipv6.conf.all.forwarding=1
 </code> </code>
  
-You can start the installation on the remote running instanceHoweverdisplaying the installer using the default SPICE doesn’t work for me. Since I think switching libvirt to VNC is extremely impracticalI recommend running virt-manager locally and adding the path to the server for both the installation and further use.+The following script creates this network and persists forwarding in 
 +''/etc/sysctl.d/90-libvirt-routing.conf''. Save it as, for example, 
 +''/root/configure-routed-network.sh'' and run it with the routed IPv4 and the 
 +first address of the routed IPv6 ''/64'':
  
 +<code bash>
 +PUBLIC_IPV4=PUBLIC_IPV4 \
 +IPV6_GATEWAY=ROUTED_IPV6_PREFIX::1 \
 +  /root/configure-routed-network.sh
 +</code>
  
-===== KVM on Debian 8  =====+As with NAT, run the script when creating the network or changing its 
 +addresses. Network autostart and the settings in ''/etc/sysctl.d'' handle VPS 
 +reboots.
  
-This manual was made using Debian 8. It should function without issues on CentOS as well (with different commands, see above). I have tried to run KVM on Ubuntu 14.04, but sadly, to no avail.+<code bash> 
 +#!/usr/bin/env bash 
 +set -euo pipefail
  
-If you’re using Windows, you need to install and turn on Xming (if you at least want to install and configure the virtual machine using a graphical interface, like I did). Then we start Putty (don’t forget to run Xming and select the “Enable X11 forwarding” option) and let the magic begin.+: "${PUBLIC_IPV4:?set PUBLIC_IPV4 to the routed public IPv4 address}" 
 +: "${IPV6_GATEWAY:?set IPV6_GATEWAY to the first address of the routed IPv6 /64}"
  
-We’ll start with the usual:+host_transit_ipv4=${HOST_TRANSIT_IPV4:-192.168.123.1} 
 +guest_transit_ipv4=${GUEST_TRANSIT_IPV4:-192.168.123.2} 
 +connection=qemu:///system 
 +network=public-routed 
 +forwarding_config=/etc/sysctl.d/90-libvirt-routing.conf 
 +xml=$(mktemp) 
 +trap 'rm -f "$xml"' EXIT
  
-<code shell+export LC_ALL=C 
-apt-get update +network_uuid=$(virsh --connect "$connection" net-uuid "$network" 2>/dev/null || :) 
-apt-get upgrade+uuid_element= 
 +if [[ -n $network_uuid ]]; then 
 +  uuid_element="  <uuid>$network_uuid</uuid>" 
 +fi 
 +cat >"$xml" <<EOF 
 +<network> 
 +  <name>$network</name> 
 +$uuid_element 
 +  <forward mode='open'/> 
 +  <bridge name='virbr-public' stp='on' delay='0'/> 
 +  <ip address='$host_transit_ipv4' prefix='30'/> 
 +  <ip family='ipv6' address='$IPV6_GATEWAY' prefix='64'/> 
 +  <route family='ipv4' address='$PUBLIC_IPV4' prefix='32' 
 +         gateway='$guest_transit_ipv4'/> 
 +</network> 
 +EOF 
 + 
 +if virsh --connect "$connection" net-list --name \ 
 +  | grep -Fx "$network" >/dev/null; then 
 +  printf '%s is active. Shut down its attached domains, run ' "$network" >&
 +  printf 'virsh net-destroy %s, then rerun this script.\n' "$network" >&
 +  exit 1 
 +fi 
 + 
 +install -d -m 0755 "$(dirname "$forwarding_config")" 
 +cat >"$forwarding_config" <<'EOF' 
 +net.ipv4.ip_forward = 1 
 +net.ipv6.conf.all.forwarding = 1 
 +EOF 
 +sysctl --quiet --load "$forwarding_config" 
 + 
 +virsh --connect "$connection" net-define "$xml" 
 +virsh --connect "$connection" net-autostart "$network" 
 +virsh --connect "$connection" net-start "$network" 
 +virsh --connect "$connection" net-dumpxml "$network"
 </code> </code>
  
-Then we install the libvirt library+If the network is already active, the script leaves it unchanged. Shut down its 
-<code shell+attached domains, stop it with ''virsh net-destroy public-routed'', rerun the 
-apt-get install qemu-kvm libvirt-bin +script, and start the domains again. The script preserves the existing network 
-apt-get install virt-manager+UUID. 
 + 
 +Attach the domain to ''public-routed''. In a Debian guest, for example, save the 
 +following as ''/etc/network/interfaces.d/public-routed''; replace ''ens3'', 
 +''PUBLIC_IPV4'', ''GUEST_IPV6'', and ''IPV6_GATEWAY'' with the actual values: 
 + 
 +<code conf
 +auto ens3 
 +iface ens3 inet static 
 +    address 192.168.123.2/30 
 +    up ip address add PUBLIC_IPV4/32 dev ens3 
 +    up ip route replace default via 192.168.123.1 src PUBLIC_IPV4 
 +    down ip address del PUBLIC_IPV4/32 dev ens3 
 + 
 +iface ens3 inet6 static 
 +    address GUEST_IPV6/64 
 +    gateway IPV6_GATEWAY
 </code> </code>
-Altogether, these two packages should be around 320 MB. The next step is downloading the image of the distribution that we want to install on the virtual machine. I installed Ubuntu Server 14.04. Choose the folder where you want to download the image and download the ISO image using “wget”. 
-<code shell> 
-cd /home 
-wget http://releases.ubuntu.com/14.04.3/ubuntu-14.04.3-server-amd64.iso 
-</code> 
-Run virt-manager. 
-<code shell> 
-virt-manager 
-</code> 
-Using Xming, you can now use Windows to configure and start the installation of the virtual server on your VPS remotely. Note that the SPICE display doesn’t work under X11, so if you want to use a graphical interface to install the virtual machine, you need to select the “Display VNC” option in the settings and restart the virtual machine. If you do this and restart the server, it can lose the information that the .iso image for the installation has been connected, so you will have to go back to the settings of the “CD-ROM” tab and in “Source-path” connect the .iso image for the installation again.  The next step is installing the chosen Linux distro. The only action left is setting up the correct port forwarding on your VPS so that you can access your virtual machine using the VPS from the outside. 
  
 +''forward mode='open''' leaves filtering of forwarded traffic to the VPS
 +firewall. Allow only traffic that the domain should receive, and remember rules
 +for both IPv4 and IPv6. The public IPv4 is configured only in the domain. The
 +IPv6 gateway and domain addresses come from the second, routed ''/64''; only an
 +address from the VPS's ordinary ''/64'' remains on its outer interface. Neither
 +protocol uses NAT in this setup.
 +
 +===== Installer ISO on NFS =====
 +
 +It is safer to copy an installer ISO to a local dataset first. On an older NFSv3
 +export without working network locking, QEMU can hang while waiting for a lock
 +or fail with an error such as ''Failed to lock byte 100'' or
 +''Failed to get ... lock''.
 +
 +For one client and a read-only installer ISO only, you can use ''nolock'':
 +
 +<code bash>
 +#!/usr/bin/env bash
 +set -euo pipefail
 +
 +: "${NFS_SERVER:?set NFS_SERVER to the NAS server address}"
 +: "${NFS_EXPORT:?set NFS_EXPORT to the exported dataset path}"
 +
 +mountpoint=${ISO_MOUNTPOINT:-/mnt/installer-iso}
 +install -d -m 0755 "$mountpoint"
 +mount -t nfs -o ro,vers=3,nolock \
 +  "${NFS_SERVER}:${NFS_EXPORT}" "$mountpoint"
 +
 +findmnt --noheadings --output FSTYPE,OPTIONS --target "$mountpoint"
 +</code>
  
-==== Contacts ====+''nolock'' disables NLM network locking, so other clients do not see local 
 +locks. Never use it for a writable or shared virtual-machine disk. Locking is 
 +part of the NFSv4 protocol and this option is not a solution there. See 
 +[[https://man7.org/linux/man-pages/man5/nfs.5.html|nfs(5)]].
  
-  * [[:uzivatele/pavlix]] 
manuals/vps/kvm.1477838690.txt.gz · Last modified: by toms