- mofos
Mofos is a tool designed to create, run, and manage virtual machines. It leverages Libvirt/QEMU/KVM, and Python, making it compatible with any Linux distribution. Heavily inspired by Qubes OS (https://www.qubes-os.org/), Mofos aims to replicate many of its features.
The tool has been extensively tested on Debian with Debian-based virtual machines. While other Linux distributions are expected to work, some additional configuration may be necessary. More details to be added.
Mofos provides a range of features focused on securely managing virtual machines, including:
- Seamless window integration using Xpra.
- A clipboard system that enables sending and receiving clipboard content between the host and virtual machines.
- SSH communication with virtual machines.
- Default network restrictions, with flexible options to route or tunnel traffic from one virtual machine through others or remote servers.
A mofos machine consists of two disks combined using overlayfs. The first disk, known as the lower layer, is a read-only template disk, while the second disk stores all the changes made by the virtual machine. This template disk is shared across multiple virtual machines. As a result, creating a new virtual machine only requires cloning an empty disk that’s already partitioned to hold the modified data. This approach ensures that new virtual machines can be created quickly, while allowing the template to be updated independently. Any updates to the template will take effect for dependent virtual machines upon their next reboot.
Depending on the Linux distribution, the Makefile can be utilized to either generate a deb
package or install the files directly.
$ make deb
# apt install ./mofos-VERSION.deb
During the apt
installation, various settings will be prompted. The default options can generally be accepted. The only setting that requires attention is the subnet address used by the mofos libvirt network (default: 192.168.90.0/24
).
OR
Install the following dependancies:
- libvirt
- make
- python3-click
- python3-click-completion
- python3-colorama
- python3-lxml
- python3-prettytable
- python3-pyroute2
- python3-tqdm
- socat
- sudo
- virt-install
- virt-manager
- xpra
# make local_install
# make configure
Mofos uses the QEMU/KVM system session, so to allow the virsh command to access virtual machines and related resources, set the environment variable LIBVIRT_DEFAULT_URI
to qemu:///system
:
export LIBVIRT_DEFAULT_URI=qemu:///system
Using QEMU/KVM system sessions improves isolation between the host and guest virtual machines by running qemu instances under a dedicated user (libvirt-qemu
) and applying specific security profiles to each instance.
However, by default, regular users cannot interact with the libvirtd
system socket to manage machines, networks, and other resources. To gain access, users must either be members of the libvirt Unix group or use sudo. Historically, local privilege escalation vulnerabilities have exploited membership in the libvirt group to obtain root privileges.
To mitigate these risks, this repository provides a strengthened AppArmor profile for the libvirtd
process on systems using AppArmor. This profile significantly restricts where libvirtd
can write files and which programs it can execute.
Additionally, polkit
rules are included to further control the actions permitted for members of the libvirt
group.
Note that the AppArmor profiles are packaged in the deb
package but are not installed by the Makefile’s install_files
target and therefore must be installed separately.
Mofos requires a configuration file located at $HOME/.config/mofos/config.toml
with minimal settings to function correctly. A minimal example configuration can be found at /usr/share/mofos/config.minimal.toml
, while a more comprehensive configuration is documented in /usr/share/mofos/config.sample.toml
.
The following error indicates that the configuration file was not found:
[-] Copy the sample configuration file from /usr/share/mofos/config.minimal.toml to ~/.config/mofos/config.toml
The following error indicates that the current user is not a member of the libvirt group:
[-] libvirtError("authentication unavailable: no polkit agent available to authenticate action 'org.libvirt.unix.manage'")
The key configuration settings to customize in the configuration files are as follows:
- key (path): The SSH private key file used to access virtual machines. It is recommended to create a dedicated key for this purpose.
- user (string): The username for SSH access to the virtual machines.
- root_password (hashed value): The hashed root password to be set during the installation of a new template.
- root_ssh_pubkey (string): The public SSH key to be installed in the root user’s directory during template installation.
Additionally, the following parameters must be configured for template installation:
- ntp
- dns (optional if a proxy is provided)
- proxy
Since the installation process relies on PXE netboot, an active internet connection is required. The following firewall rules should be configured:
sysctl net.ipv4.ip_forward=1
iptables -t nat -I POSTROUTING -s 192.168.90.0/24 -j MASQUERADE
iptables -t nat -I POSTROUTING -s 192.168.91.0/24 -j MASQUERADE
Or with nftables:
sysctl net.ipv4.ip_forward=1
nft insert inet nat postrouting iifname "install-*" masquerade
nft insert inet nat postrouting iifname "mof0" masquerade
When the ip_forward
parameter is set to 1, the FORWARD chain should be configured to prevent other devices on the network from using the host as a router.
Overall, the following rules are recommended:
iptables -I INPUT -i mof0 -p udp --sport 68 --dport 67 -j ACCEPT -m comment --comment "mofos dhcp"
iptables -I INPUT -i mof0 -p udp --dport 69 -j ACCEPT -m comment --comment "mofos tftp"
iptables -I OUTPUT -o mof0 -j ACCEPT -m comment --comment "host -> mofos"
iptables -I FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -I FORWARD -i mof0 -j ACCEPT -m comment --comment "mofos ->"
iptables -t nat -I POSTROUTING -s 192.168.90.0/24 -j MASQUERADE
iptables -t nat -I POSTROUTING -s 192.168.91.0/24 -j MASQUERADE
Or with nftables
:
table inet filter {
chain input {
iifname "install-*" ip daddr 255.255.255.255 udp sport 68 udp dport 67 accept comment "mofos dhcp"
iifname "install-*" udp dport 69 accept comment "mofos tftp"
}
chain forward {
ct state established,related accept;
ct state invalid drop;
iifname "mof0" counter accept
iifname "install-*" counter accept
}
chain output {
oifname "mof0" counter accept
}
}
table ip nat {
chain postrouting {
iifname "mof0" masquerade
iifname "install-*" masquerade
}
}
It is recommended to restrict masquerade and forwarding rules based on your specific needs, to prevent mofos virtual machines from accessing the entire host network.
Isolation between virtual machines is automatically enforced by a libvirt hook, which requires nft to function properly.
The first step is to build the initial layer: the template. By default, Mofos can install a Debian 12–based template.
mofos template create debian-template
Note: For every command, the --debug
option can be used to obtain detailed technical information in case of unexpected behavior. Specifically for this command, the --debug
flag also forces a graphical window to display the installation progress. Alternatively, the installation can be monitored using virt-manager.
Currently, only the Debian 12 template is supported for installation. The Python dictionary below specifies the installation image to be used:
NETBOOT = {
"debian-stable-amd64": {
"variant": "debian11",
"url": "https://deb.debian.org/debian/dists/stable/main/installer-amd64/current/images/netboot/netboot.tar.gz",
}
}
The variant is set to debian11
because in Debian 12, the osinfo
variant for Debian 12 is not yet installable via libvirt.
To install another distribution, modify the dictionary located in /usr/lib/python3/dist-packages/mofos/settings.py
.
When the above command is run, Mofos downloads the netboot files and caches the tar.gz
archive in $HOME/.cache/template-installer
. Currently, if the netboot archive already exists, Mofos will not download it again. This can cause errors if the cached archive is outdated. If such errors occur during installation, removing the cached archive will force Mofos to download an updated version, which should resolve the issue.
Next, the archive is extracted into /tmp
, and libvirt is configured to serve its contents via TFTP.
The template virtual machine is then created and set to boot via PXE, installing the specified distribution using the provided preseed file (by default /usr/share/mofos/templates/debian/preseed.cfg.j2
). This file is a jinja2
template; before copying it to the TFTP root directory, variables from the configuration files (ntp
, proxy
, dns
, root_password
) are injected.
At the end of the installation, the postinstall
script is placed in the TFTP directory and executed on the template. By default, the script located at /usr/share/mofos/templates/postinstall.sh.j2
is used. This jinja2
template injects the public SSH key to be configured on the template.
In addition of configuring the root SSH public key, the following operation are performed:
- Disable the standard SSH service and enable a SSHD over virtual sockets (vsock).
- Empty the
/etc/resolv.conf
file. - Configure the GRUB timeout to 0 second.
- Install an initramfs hook that mounts the overlayfs when partition labeled
overlay
is detected.
Once the installation is complete, the libvirt virtual machine is retrieved and compressed into a local qcow2
file saved in the current directory.
$ mofos template create debian-template
[*] Installing debian-template
[*] Configure the SSH host key of the template
[*] Waiting for the installation to be complete
[*] Installation is complete
[*] Downloading the resulting qcow2 disk
[*] Compressing the disk
[*] Save template's public ssh host key
[+] Template installation finished
[+] Template disk is debian-template-disk.qcow2
In addition to the qcow2
file, this process also creates an entry in the file $HOME/.local/share/mofos/ssh.json
containing the machine’s name and its public SSH key:
{
"disk": {
"debian-template-disk.qcow2": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINrbOdOPENEj2KeHrYLdorQe9Ez1b9Bu5agZmgNDMayy"
}
}
This file is automatically used during the import process.
The next step is to import the created template qcow2
file into Mofos.
$ mofos template import debian-template debian-template-disk.qcow2 http://debian.org/debian/11
[*] Uploading debian-template-disk.qcow2 to mofos pool
[*] Creating the virtual machine debian-template
[*] Configuring the template metadata
[*] Configuring the SSH key
[+] debian-template successfully imported
For now, the osinfo
variant is mandatory. They can be found in the file:
/usr/lib/python3/dist-packages/mofos/settings.py
.
Once imported, the template can be seen in the mofos ls
command:
$ mofos ls
+----+-----------------+---------+-------------+-------+-----+--------------+
| Id | Name | State | Description | Alias | Cid | IPv4 address |
+----+-----------------+---------+-------------+-------+-----+--------------+
| | debian-template | shutoff | | | | |
+----+-----------------+---------+-------------+-------+-----+--------------+
From this point, the template can be started and accessed for modification as needed.
$ mofos start debian-template
$ mofos ls
+----+-----------------+---------+-------------+-------+-----+----------------+
| Id | Name | State | Description | Alias | Cid | IPv4 address |
+----+-----------------+---------+-------------+-------+-----+----------------+
| 3 | debian-template | running | | | 3 | 192.168.90.202 |
+----+-----------------+---------+-------------+-------+-----+----------------+
$ mofos ssh debian-template --user root
root@linux:~#
The following command creates an empty upper layer with the specified label on the disk’s single partition:
$ mofos template create-overlay-disk
By default, this disk is set to 50 GB but initially occupies only around 100 MB. This size can be customized in the configuration file.
Note: It is recommended to always shut down a template before manipulating Mofos virtual machines. Although running a template and its virtual machines simultaneously is supported, it may lead to instability.
$ mofos new test
[*] New virtual machine name is test
[+] Virtual machine test successfully created
[*] Triggering post install actions
[*] Create SSH known_hosts entries for test
[*] Waiting for test to be up
[+] test is ready
$ mofos ssh test -u root
Last login: Mon Jun 2 11:09:51 2025 from UNKNOWN
root@linux:~#
Keep in mind that SSH connections are made through virtual sockets, so you cannot directly SSH into the newly created machine. Instead, you must use the mofos ssh command. Alternatively, you can create an SSH configuration specifying a ProxyCommand
to access the machine’s SSH port:
$ mofos inventory --format ssh
Host debian-template
User user
PasswordAuthentication no
IdentityFile /home/user/.ssh/id_ed25519
ProxyCommand /usr/bin/mofos proxy-cmd %h
CanonicalizeHostname=no
Host test
User user
PasswordAuthentication no
IdentityFile /home/user/.ssh/id_ed25519
ProxyCommand /usr/bin/mofos proxy-cmd %h
CanonicalizeHostname=no
$ mofos inventory --format ssh > ~/.ssh/mofos
$ echo "Include ~/.ssh/mofos" >> ~/.ssh/config
$ ssh root@test
Linux linux 6.1.0-37-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.140-1 (2025-05-22) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon Jun 2 11:09:51 2025 from UNKNOWN
root@linux:~#
During a mofos ssh
session, a ControlMaster
socket is established beforehand to speed up subsequent connections. This is why the MOTD is not displayed.
To simplify the customization of templates and virtual machines, Mofos introduces the concept of hooks and tags. For each tag, a corresponding hook (a Bash script) can be executed to perform automated actions on the target virtual machine or template and configure it accordingly.
Minimal hooks are located in /usr/share/mofos/hooks
. These are simple Bash scripts that receive the following inputs:
TAG=$1
NAME=$2
OS=$3
DISTRIB=$4
HOSTNAME=$5
This mechanism can be leveraged with Ansible to execute playbooks during template installation:
#!/bin/bash
# During template installation, the machine is not yet managed by mofos,
# the inventory would not working.
# A custom inventory is created on the fly using the given tag as main ansible
# group and the distribution as secondary.
TAG=$1
NAME=$2
OS=$3
DISTRIB=$4
HOSTNAME=$5
if [ -z "${TAG}" ] || [ -z "${NAME}" ] || [ -z "${DISTRIB}" ] ; then
exit 1
fi
# Create inventory
ANSIBLE_DIRECTORY="/home/user/Documents/ansible"
RANDOM_SUFFIX=$(printf "%x" $RANDOM)
INVENTORY_FILE="${ANSIBLE_DIRECTORY}/inventory-${NAME}-${RANDOM_SUFFIX}.ini"
trap 'rm -f "${INVENTORY_FILE}"; exit' EXIT
cat > $INVENTORY_FILE <<EOF
[all:vars]
ansible_ssh_common_args="-o ProxyCommand='mofos proxy-cmd %h' -o CanonicalizeHostname=no"
[${TAG}]
${NAME}
[${DISTRIB}]
${NAME}
EOF
export ANSIBLE_CONFIG="/home/user/Documents/ansible/ansible.cfg"
export ANSIBLE_VERBOSITY=1
/usr/bin/ansible-playbook \
-i "${INVENTORY_FILE}" \
-l "${NAME}" \
/home/user/Documents/ansible/playbooks/pentest/install.yml
This script dynamically creates an inventory and runs a playbook against it.
During virtual machine creation, another hook can be used, for example, to randomize the hostname.
By default, Mofos generates an alias based on the classic Windows naming convention (e.g., DESKTOP-2BF9753
). This name, along with other information, is passed to the hook script:
#!/bin/bash
TAG=$1
NAME=$2
OS=$3
DISTRIB=$4
HOSTNAME=$5
if [ -z "${TAG}" ] || [ -z "${NAME}" ] || [ -z "${OS}" ] ; then
exit 1
fi
if [ -z "${HOSTNAME}" ] ; then
HOSTNAME="${NAME}"
fi
mofos run -u root "${NAME}" "echo ${HOSTNAME} > /etc/hostname && hostname ${HOSTNAME}"
Next, the configuration should be edited to enable this hook:
[hooks.test]
new = "/home/user/.config/mofos/hooks/new.sh"
Then, during virtual machine creation, this script will be executed:
$ mofos new test2 --tags test
[*] New virtual machine name is test2
[+] Virtual machine test2 successfully created
[*] Triggering post install actions
[*] Create SSH known_hosts entries for test2
[*] Waiting for test2 to be up
[*] Running new hook: test
[+] test2 is ready
$ mofos ssh test2 -u root
Last login: Mon Jun 2 11:09:51 2025 from UNKNOWN
root@DESKTOP-2BF9753:~#
Similar to the installation phase, Ansible playbooks can also be executed at this stage. In this case, the mofos inventory
command can be used to generate an Ansible inventory, simplifying the process of selecting and accessing virtual machines:
$ mofos inventory
{
"_meta": {
"hostvars": {
"debian-template": {
"ansible_host": "debian-template",
"ansible_ssh_common_args": "-o ProxyCommand='/usr/bin/mofos proxy-cmd %h' -o CanonicalizeHostname=no"
},
"test": {
"ansible_host": "test",
"ansible_ssh_common_args": "-o ProxyCommand='/usr/bin/mofos proxy-cmd %h' -o CanonicalizeHostname=no"
},
"test2": {
"ansible_host": "test2",
"ansible_ssh_common_args": "-o ProxyCommand='/usr/bin/mofos proxy-cmd %h' -o CanonicalizeHostname=no"
}
}
},
"debian": [
"debian-template",
"test",
"test2"
],
"test": [
"test2"
]
Note that groups are created based on the distribution variant as well as tags. These groups can be used to load different variables.
For example, the script below runs an arbitrary playbook:
#!/bin/bash
TAG=$1
NAME=$2
OS=$3
DISTRIB=$4
HOSTNAME=$5
if [ -z "${TAG}" ] || [ -z "${NAME}" ] || [ -z "${OS}" ] ; then
exit 1
fi
if [ -z "$HOSTNAME" ] ; then
HOSTNAME=$NAME
fi
if [ $OS == "windows" ] ; then
TAGS="hostname,desktop"
else
TAGS="hostname,hosts,desktop"
fi
export ANSIBLE_CONFIG="/home/user/Documents/ansible/ansible.cfg"
export ANSIBLE_VERBOSITY=0
/usr/bin/ansible-playbook \
-i /home/user/Documents/ansible/inventory.py \
-l "${NAME}" \
-t "${TAGS}" \
-e "hostname=${HOSTNAME}" \
/home/user/Documents/ansible/playbooks/pentest/update.yml
Similarly, the start hook is executed when a virtual machine starts. It is typically used to launch services required by the virtual machine.
For example, to enable seamless Windows integration within the virtual machine, you can install Xpra
.
First install ansible
:
# apt install ansible
Next, run the user playbook located in the ansible
directory. Before doing so, edit the playbooks/user.yml
file to update the password hash and the public SSH key to be installed in the user’s home directory.
~/mofos/ansible$ ls
ansible.cfg ansible.log inventory.sh playbooks
$ ansible-playbook playbooks/user.yml -l test2
Using /home/user/mofos/ansible/ansible.cfg as config file
[WARNING]: Found both group and host with same name: test
PLAY [Create and configure a user]
[...]
PLAY RECAP
test2 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Afterward, you can SSH into this user account, provided the configuration specifies this user as the default:
$ mofos ssh test2
user@DESKTOP-2BF9753:~$
Next, run the Xpra
playbook. This playbook installs packages from Debian mirrors. Please note that the Mofos network does not configure DNS, proxy, or a default gateway by default. These must be set up before running the playbook.
No modifications to the playbook are required by default.
ansible-playbook playbooks/xpra.yml -l test2
This playbook installs and configures Xpra and starts the xpra
service on the virtual machine.
The remote service can be started manually using:
user@DESKTOP-2BF9753:~$ systemctl --user start xpra
Otherwise, the service will start automatically at the next reboot.
Then, the local client service can also be start manuallly:
$ mofos xpra test2
Back on the virtual machine, the display should be set to :10
(the default), after which a graphical application can be launched and will appear within the host’s desktop environment.
user@DESKTOP-2BF9753:~$ export DISPLAY=:10
user@DESKTOP-2BF9753:~$ xterm
To ensure this mechanism runs smoothly and automatically, the mofos xpra
command can be start from the start hook.
#!/bin/bash
TAG=$1
NAME=$2
OS=$3
DISTRIB=$4
HOSTNAME=$5
if [ -z "${TAG}" ] || [ -z "${NAME}" ] ; then
exit 1
fi
mofos xpra "${NAME}"
To be inform of the start and stop of libvirt/qemu
machines, the libvirt
qemu
hook nay be modified to specify the name of the host user (by default user
):
# sed 's/USER = "user"/USER = "foobar"/' /etc/libvirt/hooks/qemu.d/90-mofos
Then, enable and start the mofos-libvirt-notifier
socket:
systemctl --user enable --now mofos-libvirt-notifier.socket
Mofos can also manage the clipboard between virtual machines and the host. The idea is to configure a specific keybind to trigger an SSH connection to the currently focused VM, either to pull the X11 clipboard or to push content to it.
To push content in the virtual machine X11 clipboard:
mofos clipboard in pentest-0
To pull content from the virtual machine X11 clipboard:
mofos clipboard out pentest-0
For each operation, mofos will establish an SSH connection to the virtual machine and use xclip and on the host wl-copy
or xclip
according to the windows technology (wayland vs X11).
The machine name in the trace above may be omitted, in this case, the script will identify the currently focused virtual machine and target it.
Two options exist in mofos to route a VM:
mofos route
that takes a gateway and configure anip rule
on the host to route the virtual machine through this gateway.mofos pivot
that takes another mofos machine, retrieve its IP address and configure it as default gateway for the current virtual machine.
Both options may take a DNS server to configure it.
The mofos tunnel
command sets up a SSH vpn (ssh -w
) to route the traffic of a
mofos machine through a server. This feature relies on few configurations:
Concretely the mofos tunnel
command does the following actions (no black magic here):
- Create a local tun interface (
sudo /usr/libexec/mofos/mofosnet.py tun add pentest_box
) and assign an IP address to this interface. - Create a tun on a remote server and link it wit the local tun created previously (
/usr/libexec/mofos/mofosnet.py sshvpn start pentest_box
). - Route the traffic of a mofos machine through the gateway of the remote box (
/usr/libexec/mofos/mofosnet.py route mofos_vm_ip gateway_ip
), the default gateway of the mofos virtual machine is also changed.
As for route
and pivot
commands, a DNS may be provided to configure it as
well.
The mofos usb
commmand allows managing usb devices.
Devices are identified by their ID (vendor_id:product_id) which is needed for the attach and detach command:
$ mofos ls usb
+-----------+------------------------------------------------+-------------+
| ID | Device | Attached to |
+-----------+------------------------------------------------+-------------+
| 0bda:8153 | Realtek, RTL8153 Gigabit Ethernet Adapter | |
| 046d:c077 | Logitech, Mouse | |
| 0a5c:5842 | Broadcom Corp, 58200 | |
| 1bcf:28d2 | CN0Y9V728LG003AGBCJZA01, Integrated_Webcam_FHD | |
+-----------+------------------------------------------------+-------------+
$ mofos usb attach pentest-1 0bda:8153
$ mofos usb
+-----------+------------------------------------------------+-------------+
| ID | Device | Attached to |
+-----------+------------------------------------------------+-------------+
| 0bda:8153 | Realtek, RTL8153 Gigabit Ethernet Adapter | pentest-1 |
| 046d:c077 | Logitech, Mouse | |
| 0a5c:5842 | Broadcom Corp, 58200 | |
| 1bcf:28d2 | CN0Y9V728LG003AGBCJZA01, Integrated_Webcam_FHD | |
+-----------+------------------------------------------------+-------------+
$ mofos usb detach pentest-4 0bda:8153
The force
option detach and re-attach a device. It is commonly used to
re-attach a device that has been unplugged without being first detached.
Note: attaching a USB device is only valid for the current life of the virtual machine. When it stops, the device is automatically detached.
Similar to USB devices, mofos allows attaching a PCI device to a running virtual machine, the commands are the same.
An additional limitations concerns some PCI devices that belongs to a group. For example, attaching the ethernet board to a running virtual machine may need to move the entire PCI group inside the virtual machine. As it cannot be done sequentially, it is not supported yet. However, for a unique PCI device such as a Wi-Fi network card, it works fine.
The mofos mount
command creates a share folders and can mount the newly added filesystem to a directory inside the virtual machine. The mofos umount
will unmount the directory and remove the share folders from the virtual machine configuration.
This mechanism relies on the virtiofsd
technology that requires enabling shared memory, this is now done by default when creating a virtual machine. Otherwise, the following command will enable it:
virt-xml -c qemu:///system --edit --memorybacking source.type=memfd,access.mode=shared DOMAIN
Furthermore, the provided AppArmor policies restrict the directories that can be shared by the host. This is done to prevent your user to configure a share on the /etc
directory or the filesystem root and modify using root privileges within the virtual machine. Therefore, it is needed to modify the usr.lib.qemu.virtiofsd
policy to allow sharing arbitrary directories.
Two lines should be adapted:
@{SHARE_DIRS}=/data/libvirt/shares/*/ /home/user/Public/**/
[...]
pivot_root /data/libvirt/shares/*/,
pivot_root /home/user/Public/**/,
The SHARE_DIRS
variable is reused in the policy, however, due to apparmor limitations, it is not possible to reuse it for pivot_root
directives. Therefore, it is required to manually adapt the pivot_root
directives for each shared directories.
To mount a local directory:
mofos mount test ./Public/share -d /home/user/share
In order to not disrupt the virtual machine where the share is to be mounted, if the remote directory is not empty a warning is issued and the script let you manually perform the mount operation.
Finally, the mount operation is not persistent and should be re-issued at each reboot.
To create Windows virtual machines, a template machine must be created manually first. The disk of this template is then used as a backing file to create child machines. By default, Windows virtual machines created with Mofos are not pre-configured. However, it is possible to configure Mofos to perform post-configuration tasks, such as changing the hostname and adding a dedicated entry in the known_hosts
file, by using hooks.
To enable the post creation setup, the following prerequisites are mandatory:
- OpenSSH server should be listening
- An SSH key should be configured to smoothly authenticate as an Administrators user. The
authorized_keys
has to be created inC:\Program Data\ssh\administrators_authorized_keys
and specific ACL.
$admin_group = "Administrators"
$system = "SYSTEM"
$acl = Get-Acl C:\ProgramData\ssh\administrators_authorized_keys
$acl.SetAccessRuleProtection($true, $false)
$administratorsRule = New-Object system.security.accesscontrol.filesystemaccessrule($admin_group,"FullControl","Allow")
$systemRule = New-Object system.security.accesscontrol.filesystemaccessrule($system,"FullControl","Allow")
$acl.SetAccessRule($administratorsRule)
$acl.SetAccessRule($systemRule)
$acl | Set-Acl
- OpenSSH should be configured with a
PowerShell
shell instead ofcmd.exe
.
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" `
-Name DefaultShell `
-Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" `
-PropertyType String `
-Force
Autocompletion should be handled out-of-the-box for bash
and fish
. For zsh
, it may be required to run the following commands:
autoload -Uz compinit
compinit
source /usr/share/zsh/vendor-completions/_mofos
Virtual machines based on the same template disk may obtain the same IP address even though the mac address of their network card changes due to DHCP identifier. This behavior can be changed by editing the template's network configuration:
With systemd-networkd:
[Match]
Name=eth0
[Network]
DHCP=yes
MulticastDNS=no
IPv6AcceptRA=no
[DHCP]
ClientIdentifier=mac
With legacy network interfaces /etc/network/interfaces
:
iface eth0 inet dhcp
client no