image-orientation CSS property

The other day I was investigating an issue with Chrome 83 and a MJPEG stream embedded in an <img />

The MJPEG stream was streaming an iPhone screen to the end user. When the user decided to rotate the screen (switching between portrait and landscape), the MJPEG stream was updated accordingly when viewing the stream inside a separate tab, but it was not showing correctly when embedded in a HTML image tag.

Turns out that since Chrome 81, the browser will look at the EXIF data to decide the correct orientation. The issue I was experiencing was happening because the EXIF data did not update after each rotation.

The solution was to use image-orientation and apply this CSS rule to the image tag. Once that was in place, the MJPEG stream was showing correctly after each rotation.

More information is available in this Chromium ticket.


WireGuard: an alternative to OpenVPN

This week I’ve been experimenting with WireGuard, which is a relatively new alternative to OpenVPN. It claims to be faster and more secure than other VPN products, partly because its codebase is very small compared to other VPN products.

WireGuard is easy to configure. It is compatible with many Linux distro’s, including Ubuntu. For my testing purposes, I’ve set up a new Ubuntu 18.04 LTS VM with Hardware Enablement.

First, make sure you’ve installed WireGuard correctly:
apt-get install wireguard

You should now be able to use wg and wg-quick
Let’s create a public and private key, which we’ll be using to set up a secure connection:

wg genkey | tee privatekey | wg pubkey > publickey

On the server VM, create a new configuration file /etc/wireguard/wg0.conf
Add the private key you just generated in the PrivateKey section.

This should contain configuration like this:

PrivateKey = <private key>
Address =
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth1 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth1 -j MASQUERADE
SaveConfig = false

PublicKey = <public key>
AllowedIPs =

The next thing you’ll need to do is add the Peers that will be able to connect to this server. Simply create another VM (Windows, Linux or MacOS) and follow the same steps:

  • install WireGuard
  • generate private and public key
  • create a new /etc/wireguard/wg0.conf configuration file
PrivateKey = <private key>
Address =

PublicKey = <public key of the server>
Endpoint = <ip4-of-server>:51820
AllowedIPs =, ::/0 # Forward all traffic to server

The AllowedIPs instructs WireGuard to forward all traffic through the tunnel.

Finally, you can start up WireGuard on both the server and client:

wg-quick up /etc/wireguard/wg0.conf

Now both VMs should be connected and able to ping each other.
You can check the status of the connection with:

wg show

I saw a notable increase in throughput compared to OpenVPN. Try it out yourself and let me know in the comments.


Speeding up your OpenVPN tunnel

Here are some settings to speed up the transmission rate through your OpenVPN tunnel:

  • proto udp
  • mssfix 0
  • fragment 0

mssfix: Even though MSS itself is a TCP feature, this OpenVPN option targets encapsulated UDP packets. It will change the MSS value of the TCP protocol inside the tunnel in such a way that after UDP encryption/encapsulation, the resulting UDP packet size (minus IP/UDP headers), will not exceed the mssfix value.
By setting the value to 0, we disable this feature.

fragment: This will disable OpenVPN’s internal fragmentation routines (OpenVPN 2.x actually does this by default).

Another improvement is raising the MTU (Maximum Transmission Units), which is the maximum datagram size in bytes that can be sent unfragmented over a network path.

First make sure your OpenVPN server has set the same MTU size:

ip link set eth0 mtu 9000

Next, add this to your OpenVPN configuration:

tun-mtu 9000


A gateway to forward all traffic to a remote VPN server

Suppose you’ve setup a VM and configured it as a site-to-site VPN with OpenVPN, using iroute and staticclients. You are using this VM as a default gateway for other VMs and now want to forward all traffic from the VMs not through the default gateway‘s adapter, but through the VPN tunnel.

Why would you want to do this? One use-case might be because you want your VMs to have the same originating IP address as the VPN server.

To get started, make sure you add these commands in a terminal on your default gateway:

  • ip route add ip-address-of-vpn-server/32 via default-gateway-ip dev enp0s5 (providing enp0s5 is your current adapter)
  • ip route del default
  • ip route add default via dev tun0 (providing is the private IP you got from your VPN)

The commands above will make sure your gateway can still reach the VPN server. Once the default route is deleted, we add a new default route that goes through the tunnel.

On the other side of the tunnel, on your VPN server, you will need to add these commands:

  • iptables -I FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
  • iptables -I FORWARD -i tun0 -o eth0 -s -m conntrack --ctstate NEW -j ACCEPT
  • iptables -t nat -I POSTROUTING -s -o eth0 -j MASQUERADE
  • iptables -t nat -I POSTROUTING -o tun0 -j MASQUERADE
  • iptables -I FORWARD -i eth0 -o tun0 -j ACCEPT
  • iptables -I FORWARD -i tun0 -o eth0 -j ACCEPT
  • iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT

Now the VMs will be able to connect through the VPN tunnel and use the VPN server as default gateway.



If you’re running macOS with QEMU, you’ll notice that the UI might be slow. This is because, by default, QEMU will use a basic display adapter with low display memory (VRAM).

There’s two ways to fix this problem:

  • Pass-through your GPU with vfio
  • Use another display adapter, such as VMsvga2

This post will focus on VMsvga2, which is a macOS kext that enables you to use the vmvga video model with libvirt.

Unfortunately VMsvga2 is an old project that is no longer maintained, same goes for the vmvga QEMU driver. Currently there’s no QXL driver available for macOS so this is the only choice we have.

Simply replace your existing video XML with this:

  <model type='vmvga' vram='16384' heads='1'/>
  <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> 

You can increase the vram to the amount you desire.
If you are using the Clover bootloader, you might have to add wmv_option_fb=0x06 to the arguments section in your config.plist

You will also need to make sure you have the VMsvga2 kext installed on your system.

Once you reboot, you’ll notice a more responsive UI.


Resizing an OSX VM with apfs and QEMU

Looking to resize an existing qcow2 or raw data volume with QEMU?

I had to do the same thing and went through some trouble in trying to do this. My first idea was to use GParted and boot from the live-cd iso to extend the apfs partition. However, it turns out that GParted does not support apfs (yet?).

First, you’ll need to expand the disk space available to the VM. Depending on the disk format, you can use:

  • qcow2: qemu-img resize image.qcow2 +20G
  • lvm: lvextend -L /dev/lvmpool/vm +20G

Now you can expand the apfs container from inside the OSX VM. Simply find out the identifier of your partition:

/usr/sbin/diskutil info / | awk '/Part of Whole/ {print $4}'

And use that identifier together with this command:

/usr/sbin/diskutil apfs resizeContainer /dev/{identifier} 0

This will expand to use up all available free disk space.


Hyper-V Enlightenments with Libvirt

With Windows 10, it’s helpful to enable Hyper-V Enlightenments, to save CPU and increase VM responsiveness.

To use these enlightenments, edit your libvirt xml:

    <relaxed state='on'/>
    <vapic state='on'/>
    <spinlocks state='on' retries='8191'/>
    <vpindex state='on'/>
    <synic state='on'/>
    <stimer state='on'/>
    <reset state='on'/>

More information available on

Another interesting note: if you want to run Windows 10 or similar in a VM, you might want to use these clock timer settings, to avoid high load even when your VM is idle:

<clock offset='localtime'>
  <timer name='rtc' tickpolicy='catchup'/>
  <timer name='pit' tickpolicy='delay'/>
  <timer name='hpet' present='no'/>
  <timer name='hypervclock' present='yes'/>

Content Caching on OSX VMs

Apple’s Content Caching is not available when running OSX in a VM.

It seems Apple is detecting if it’s running inside a VM:

$ sudo /usr/bin/AssetCacheManagerUtil activate
AssetCacheManagerUtil[] Failed to activate content caching: Error Domain=ACSMErrorDomain Code=5 "virtual machine"...

To get around this, you can patch the kernel to remove the cpuid features check:

  • First disable SIP
  • Next: sudo mount -uw /
  • /System/Library/Kernels/kernel
  • sudo kextcache -i /