I recently replaced a 2019 Intel MacBook Pro with a M3 Macbook Air, so I decided to wipe the MBP and install proxmox on it.

It wasn’t as straightforward as installing on non-Apple hardware, so I’m documenting what I had to do here.

Note that this post only covers getting things working on a MacBook Pro - look at the many online tutorials for what you should do once your node is up and running.

I’ve been wanting to experiment with proxmox in my homelab for a while, and when I replaced my old Intel MacBook Pro with a M3 Macbook Air, I decided it was a good time to start.

When I did this install, the current version of Proxmox was 8.3.0.

Pre-requisites

Make a backup

The install is going to wipe your Mac’s disk, so make sure you’ve backed up any files you care about.

A boot stick

As with a normal proxmox install, I downloaded a installer from https://proxmox.com/en/downloads then burned it to a thumb drive with Etcher, but use whatever tool you’re comfortable with.

Network setup

Proxmox doesn’t do DHCP during install, so you’re going to need to collect your network information. I recommend you pick an address outside you DHCP pool so you don’t have to worry about IP address collisions. While you’re still running macOS, open System Settings, then select Network so you can collect the current working IP address, router, and DNS servers.

Hardware

Once you boot into the Proxmox installer it doesn’t recognize a lot of the MacBook Pro’s hardware, so you’ll need some hardware to get through installation. Once the install’s complete, everything can get done through the webUI or via ssh.

You’re going to need:

  • USB hub
  • USB keyboard and mouse. Proxmox 8.3.0 doesn’t recognize the MacBook Pro’s keyboard or trackpad
  • A USB ethernet dongle. Running a server node over WIFI is a bad idea to begin with, and a stock install of Proxmox 8.3.0 doesn’t recognize the MBP’s WIFI either so you don’t get a choice.

Installing

Disable Boot Security

By default, Macbooks with a T2 chip won’t boot off external devices, or boot unsigned operating systems.

To unlock the security restrictions:

  1. Reboot into recovery mode by holding Command-R while rebooting
  2. Once you’re in recovery mode, open Startup Security Utility - it’s in Utilities -> Startup Security Utility
  3. Set Secure Boot to No Security
  4. Set Allow booting from external or removable media

You’re set to start the proxmox install

Proxmox install

  1. Connect the install drive, keyboard, mouse and ethernet dongles.
  2. Reboot while holding the Option key. You should see a menu of drives come up. If not, you didn’t press the Option key fast enough, reboot and try again.
  3. You’ll see your Mac’s drive, a UEFI option, and a GRUB option. On my 2019 MacBook Pro, I had to pick UEFI.
  4. The Proxmox splash screen will appear. Pick your install option. I picked graphical because when I tried the terminal option the text was so small it was hard to read.
  5. Read and accept the EULA.
  6. Choose the drive you want to install on. Click the Options button if you want to change from the default ext4 filesystem.
  7. Set your country and time zone.
  8. Set password and email address.
  9. Set up the network with the address, router, and DNS information you collected earlier. Choose your FQDN wisely - it’s a pita to change the name once you’ve created VMs or LXC containers.
  10. It’ll present a summary. Make sure everything is correct, especially the network information, then click install. On my MBP, it took less than ten minutes to install proxmox and prompt me to remove the install disk and let it reboot.

You’ll see a login screen, with instructions on what URL to use to manage the instance.

Gotchas

As of 2025-02-01, I ran into the following issues after installing proxmox 8.3.0 on a 2019 MacBook Pro.

The node goes to sleep when the lid is closed

If you’re going to use this as a proxmox cluster node, you’re not going to want it going to sleep just because you closed the laptop lid.

To disable sleeping when the lid is closed, edit /etc/systemd/logind.conf as root.

Change the HandleLidSwitch entries to ignore - they should look like

HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
HandleLidSwitchDocked=ignore

Then

sudo systemctl reload logind

You should now be able to close the lid without the node going to sleep.

Networking not coming up automatically during boot

I installed on both an old Mac Mini and a MacBook Pro. On the Mac Mini, networking (using the built in ethernet) worked fine, but on the MacBook Pro it failed to bring up the network.

Once I logged into the console, I did some poking, and it looks like what’s happening is that systemd-udev-settle fails during boot, probably because my ethernet adapter is USB-C, and the networking systemd unit won’t start. But after boot, systemctl restart networking detects the adapter and brings it up.

I don’t want to have to log into the console every boot, of course, so I wrote a helper script that restarts networking if it’s down.

Download from kick-mbp-networking

#!/usr/bin/env bash
#
# kick-mbp-networking
#
# This script is Apache 2.0 licensed.
#
# Networking on proxmox on my 2019 MacBook Pro stubbornly fails to come up
# during boot, but a systemctl networking restart will fix it.
#
# Stick this into root's crontab as a @reboot item and it will fix the
# damned networking
#
# The entry should look like:
# m h  dom mon dow  command
#@reboot /usr/local/sbin/kick-mbp-networking
#
# Copyright 2025, Joe Block <jpb@unixorn.net>

set -o pipefail
if [[ -n "$DEBUG" ]]; then
  # shellcheck disable=SC2086
  if [[ "$(echo $DEBUG | tr '[:upper:]' '[:lower:]')" == "verbose" ]]; then
    set -x
  fi
fi

function debug() {
  if [[ -n "$DEBUG" ]]; then
    echo "$@"
  fi
}

function echo-stderr() {
  echo "$@" 1>&2  ## Send message to stderr.
}

function fail() {
  printf '%s\n' "$1" >&2  ## Send message to stderr. Exclude >&2 if you don't want it that way.
  exit "${2-1}"  ## Return a code specified by $2 or 1 by default.
}

function has() {
  # Check if a command is in $PATH
  which "$@" > /dev/null 2>&1
}

function get-settings() {
  LOG_F=${LOG_F:-'/root/mbp-network-weirdness.log'}
}

function check-dependencies() {
  # Confirm the stuff we need is in $PATH
  debug "Checking dependencies..."
  # shellcheck disable=SC2041
  for p in 'ip' 'systemctl'
  do
    if ! has $p; then
      fail "Can't find $p in your $PATH"
    else
      debug "- Found $p"
    fi
  done
}

function path-exists() {
  local file="${1}"
  [[ -s "${file}" ]] || fail "$1 is not valid"
  [[ -d "${file}" ]] && return
  [[ -f "${file}" ]] && return
  fail "$1 is not a directory or file"
}

function restart-networking-if-down() {
  debug "$LOG_F"
  # Check if the vmbr interface is present
  if [[ $(ip link show | grep -c vmbr) != 0 ]]; then
    debug "ip link show = $(ip link show)" | tee -a "$LOG_F"
    debug "Networking is up" | tee -a "$LOG_F"
  else
    debug "Networking was down after boot, restarting at $(date)" | tee -a "$LOG_F"
    echo "Restarting networking after failed to start during boot at $(date)" | tee -a "$LOG_F"
    time systemctl restart networking | tee -a "$LOG_F"
  fi
}

check-dependencies
get-settings
restart-networking-if-down

Put the script in /usr/local/sbin/kick-mbp-networking, then add it as a cron reboot job. As root, run crontab -e, then add a line to run the script. The crontab entry should look like

# m h  dom mon dow  command
@reboot /usr/local/sbin/kick-mbp-networking

Test it by rebooting. You should now be able to access proxmox’s web ui without having to enable networking manually in a console session.

Finally

You should now have a working proxmox node you can safely use, either as a standalone machine or as part of a cluster.