Bottom Line: Configure your VMs to start and run automatically on pfSense with vm-bhyve.

If you’re trying to get a Linux VM running under bhyve on pfSense, I strongly recommend that you start with my first post on the topic. Once you have things running interactively, it’s time to try to get the VM to start and run automatically.

vm-bhyve is designed to help make the process a little easier, and it’s available in the default pfSense repo, which is highly convenient.

First off, it’s important to realize that pfSense apparently does not use the standard FreeBSD rc init system; I would have saved a lot of time had I realized this earlier, as it means that the default FreeBSD instructions on this topic, which advise adding a number of settings to /etc/rc.conf, won’t work.

Further, at boot time, you can automatically run scripts in /usr/local/etc/rc.d/, but they must end in .sh and be executable.

With these two facts in mind, the rest wasn’t too difficult. As a reminder, I’m using bash as my shell, and all commands below are being run as root (I’m using $ instead of # in codeblocks below for better markdown syntax highlighting.)

You’ll probably want to keep vm-bhyve’s GitHub page open to references its documentation.

  1. Install vm-bhyve with pkg install vm-bhyve
  2. Using the web interface, configure pfSense to load the necessary kernel modules on boot by adding the following to /boot/loader.conf (following the official FreeBSD instructions, though I didn’t need nmdm_load):
  3. Configure pfSense to bring up your TAP interface on boot:
    • System -> Advanced -> System Tunables (/system_advanced_sysctl.php)
    • + New
    • Tunable:
    • Value: 1
    • Description: Open TAP on boot for vm-bhyve
  4. This is probably a good time to reboot, which should load / activate the above settings and make sure they are working
  5. Symlink vm-bhyve’s rc script to something pfSense will run:
    $ ln -s /usr/local/etc/rc.d/vm /usr/local/etc/rc.d/
  6. Edit /etc/rc.conf.local and add vm-bhyve’s config. The contents of mine are the following lines, yours may vary:
  7. You may need to remove the remnants of the zfs virtual drive created in the prior post:
    $ zfs destroy pfSense/vm/nixos0
  8. Create and populate vm-bhyve’s directory structure: $ vm init
  9. Copy the UEFI file we downloaded in the last post to a place that vm-bhyve will look for it:
    $ cp BHYVE_UEFI.fd /pfSense/vm/.config/
  10. Next you need to configure the VM
    1. Start by looking through a few of the samples:
    2. Next, I downloaded and then edited the default config:
       $ curl ''  > /pfSense/vm/.templates/nixos.conf
       $ vim /pfSense/vm/.templates/nixos.conf

    My config ultimately ended up looking like this:

  11. I had trouble with the vm-bhyve console until I configured it to run in tmux; if you’re not a tmux user maybe skip this: $ vm set console="tmux"
  12. Create a “manually” managed switch (since we’ve configured it in pfSense in the prior post, and pfSense will manage it)
    $ vm switch create -t manual -b bridge0 public
  13. Create a VM named nixos0 based on your customized nixos template:
    $ vm create -t nixos nixos0
  14. Tell vm-bhyve to download the installer ISO:
    $ vm iso
  15. Install in the foreground using your currently active terminal session. Note that immediately after running this command I had to hold down the down arrow key and keep tapping it for 15 seconds or so, during which the entire SSH session seemed be frozen. Afterwards, it comes up with the option to go into Accessibility and redirect its output to the serial console, just like in the last post.
    $ vm install -f nixos0 nixos-minimal-22.11.2979.47c00341629-x86_64-linux.iso
  16. At this point, you should be able to get a shell, sudo su to elevate, systemctl start sshd, passwd to set a root password, ip addr to get your IP address, and you’re off to the races! (Don’t forget to add boot.kernelParams = [ "console=ttyS0" ]; if using NixOS, and you’ll need SSH access configured so you can access the machine once it’s booting in the background)
  17. Once you’ve completed your installation, see if your VM comes up (make sure to give it a minute):
    $ vm poweroff nixos0
    $ vm start -f nixos0
  18. If that works, try SSH access. If that also works, try rebooting pfSense – your VM should automatically start in the background a few seconds after bootup is complete, at which point you should be able to connect via SSH (check your pfSense logs for the IP address, for which you might want to add a DHCP reservation at this point).
  19. If you’ve made it to this point, everything seems to be working. Congratulations! All that’s left is to make a snapshot of your working VM, which I suppose you should be able to zfs send to another machine, or to which you can roll back if something goes wrong in the future:
$ vm stop nixos0
$ vm snapshot nixos0@booting
$ vm info nixos0
vm info nixos0
Virtual Machine: nixos0
  state: stopped
  datastore: default
  loader: uefi-custom
  uuid: 0b49b710-e2ce-11ed-b922-00e0672a504a
  uefi: default
  cpu: 1
  memory: 1024M

    number: 0
    emulation: virtio-net
    virtual-switch: public
    fixed-mac-address: 58:9c:fc:03:dc:eb
    fixed-device: -

    number: 0
    device-type: sparse-zvol
    emulation: virtio-blk
    options: -
    system-path: /dev/zvol/pfSense/vm/nixos0/nixos0
    bytes-size: 17179869184 (16.000G)
    bytes-used: 1650454528 (1.537G)

    pfSense/vm/nixos0@booting	0	Mon Apr 24 15:25 2023
    pfSense/vm/nixos0/nixos0@booting	0	Mon Apr 24 15:25 2023

I hope you’ve found this useful – I still have a lot to learn, so if you see any major missteps or recommendations for improvement please let me know in the comments.