Skip to content

Instantly share code, notes, and snippets.

@codello
Last active March 6, 2024 19:28
Show Gist options
  • Save codello/f70973b1106978722eb2016b8b37b801 to your computer and use it in GitHub Desktop.
Save codello/f70973b1106978722eb2016b8b37b801 to your computer and use it in GitHub Desktop.
How to install CentOS 8 on a Mac.

Installing CentOS on Apple Hardware

Installing recent CentOS versions on Macs is not as straight forward as I wish it to be. I repeatedly had issues even getting the installation media to boot. In this snippet I gather my findings and present a way to successfully install CentOS on a Mac.

Tested using CentOS Stream 8 on a Late 2014 Mac Mini.

1. Preparing the Installation Media

When using the usual methods of creating a bootable USB drive (e.g. by using balenaEtcher) I was greeted by a black screen. In order to successfully get to the CentOS installer I did the following things:

  1. Format the USB drive
  2. Copy the ISO onto the USB drive
  3. Replace the EFI boot file
  4. Edit grub.cfg
  5. Copy repair-grub.sh and mount-lvm.sh to the USB drive

1.1 Formating the USB drive

This step is mainly necessary in order to be able to modify files on the USB drive in macOS. By default the system wasn't able to read the filesystem of the CentOS ISO or the drive created by Etcher. If you are using a Linux machine you can probably skip steps 1.1 and 1.2 and instead copy the contents of the ISO to the USB drive using dd.

On a Mac however I erased the USB drive using Disk Utility:

  • Choose a name for the volume. This name will be important later. This name will be referred to as <USB>.
  • Format the volume with a FAT filesystem
  • Use the GUID partition table (apparently some macs are especially picky about this setting).

1.2 - 1.4 Mac-specific tweaks

Edit the create-ush.sh script with your <USB> name and the location of the CentOS ISO file. Then run the script. The script will perform the following actions in a docker container:

  • Mount the ISO
  • Copy its contents to the installation media
  • Create a EFI boot image that does not result in a black screen but actually gets you into grub.
  • Fix the grub.cfg file to use your <USB> name. By default it expects a certain name for the volume, depending on the ISO you used.

1.5. Copy repair-grub.sh and mount-lvm.sh

Copy the contents of repair-grub.sh and mount-lvm.sh onto the installation media. We will use them in step 3. Alternatively you type the commands in the script manually in step 3.

Remember to adjust the values in mount-lvm.sh to your environment.

2. Installing CentOS

Installing CentOS is relatively straight forward. However we have to do some custom partitioning. Here are the relevant steps, slightly adjusted:

  • Select your disk
  • At the bottom, click the "Full disk summary and boot loader" text
    • Click on the disk in the list
    • Click "Do not install boot loader"
    • Close
  • Select "Custom" (I didn't try automatic, but it probably would not create the EFI partition)
  • Done in the top left to get to the partitioning screen
  • Delete existing partitions if needed
  • Click +
    • Create /foo mountpoint, 600M, Standard partition, then edit the partition to be on /boot/efi and change the file system to 'EFI System Partition'.
  • Click + repeatedly to create the rest of the partitions as usual (/boot, /swap, /home, etc.).
  • Done

In my case the package installation from install media was not possible. Instead I used a package repository URL as the installation source, more specifically http://mirror.centos.org/centos/8/BaseOS/x86_64/os/.

When starting the installation there will be an error about a missing mactel-boot package. Ignore the error and continue the installation.

3. Making the Installation Bootable

When the installation finishes the system is not quite usable yet. We need to fix two things:

  • Reinstall grub (to avoid the booting-to-black-screen problem)
  • Create a grub.cfg.

To do this, boot from the installation media again and enter the rescue mode.

  • Choose 1 to mount the system on /mnt/sysimage. If you chose to use a LVM root partition there may be an error that no linux filesystem could be found. Run bash /mnt/install/repo/mount-lvm.sh to fix this issue. This is the mount-lvm.sh script copied in step 1.5. Alternatively you can type the commands from the script manually.
  • Run bash /mnt/install/repo/repair-grub.sh. This is the repair-grub.sh script from step 1.5. Alternatively you can type the commands from the script manually.
  • Exit the rescue mode and reboot the machine. It should reboot once after SELinux relabelling and then boot into CentOS.
#!/usr/bin/env sh
ISO_PATH="/path/to/centos.iso" # Must be an absolute path.
USB_NAME="<USB>"
USB_PATH="/Volumes/$USB_NAME" # Must be an absolute path
# Mounting the ISO requires a privileged container.
docker run --rm -it --privileged \
-v "$ISO_PATH":/centos.iso \
-v "$USB_PATH":/usb \
centos bash -c "
echo -e '\033[0;32mInstalling Dependencies...\033[0m'
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
yum install -y grub2 grub2-efi-x64-modules rsync genisoimage
# Mount the ISO at /mnt to access its contents.
mount -o ro /centos.iso /mnt
ISO_NAME=\$(isoinfo -d -i /centos.iso | grep -i 'Volume id:' | cut -d' ' -f3-)
# Store the name of the ISO for later
ISO_NAME=\$(isoinfo -d -i /centos.iso | grep -i 'Volume id:' | cut -d' ' -f3-)
# Copy the contents of the ISO to the USB drive
echo -e '\033[0;32mCopying ISO contents...\033[0m'
rsync -ra --info=progress2 /mnt/. /usb/
# Generate a EFI boot image that can be used on Macs. It may be possible to
# shorten this but it works.
# This is adapted from https://unix.stackexchange.com/a/273334
echo -e '\033[0;32mCreating EFI boot image...\033[0m'
grub2-mkimage -O x86_64-efi -o /usb/EFI/BOOT/BOOTX64.EFI -p /efi/grub \
disk part_msdos part_gpt linux loopback normal configfile test search \
search_fs_uuid search_fs_file true iso9660 test search_label efi_uga \
efi_gop gfxterm gfxmenu gfxterm_menu fat ext2 ntfs cat echo ls memdisk tar
# Replace the default boot drive name with the actual boot drive name.
echo -e '\033[0;32mFixing grub.cfg...\033[0m'
sed -i \"s/\$ISO_NAME/$USB_NAME/g\" /usb/EFI/BOOT/grub.cfg
umount /mnt
"
#!/usr/bin/env sh
LVM_GROUP=<changeme> # The name of the LVM group
LVM_NAME=root # The name of the LVM volume
EFI_DEVICE=/dev/sda1 # Change if necessary
BOOT_DEVICE=/dev/sda2 # Change if necessary
# Find and activate the LVM volume
vgscan
vgchange -ay
# Mount the volume as well as some auxiliary directories to be able to use
# grub inside a chroot.
mount /dev/$LVM_GROUP/$LVM_NAME /mnt/sysimage
mount $BOOT_DEVICE /mnt/sysimage/boot
mount $EFI_DEVICE /mnt/sysimage/boot/efi
mount --bind /dev /mnt/sysimage/dev
mount --bind /sys /mnt/sysimage/sys
mount --bind /proc /mnt/sysimage/proc
mount --bind /run /mnt/sysimage/run
#!/usr/bin/env sh
# Install the grub2-efi-x64-modules in the rescue system. This is used to be
# able to create a new boot image with grub. By installing the package into the
# rescue system we do not modify our installation with additional packages.
# The installed package will be gone after a reboot.
# Since the rescue system usually does not have internet access we create a
# local repo file that points to the BaseOS repo on the installation media.
mkdir -p /etc/yum.repos.d/
cat <<-EOF | tee /etc/yum.repos.d/local.repo >/dev/null
[local]
name=CentOS Local BaseOS
baseurl=file:///mnt/install/repo/BaseOS/
enabled=1
gpgcheck=0
EOF
# We now install the grub modules. Grub itself is already installed.
yum install -y grub2-efi-x64-modules
# This command re-installs grub. This is the grub installation that will
# usually be used for booting CentOS.
grub2-install --target=x86_64-efi \
--boot-directory=/mnt/sysimage/boot \
--efi-directory=/mnt/sysimage/boot/efi \
--bootloader-id=GRUB
# This command re-installs grub at /EFI/BOOT/BOOTX64.EFI. This is usually not
# used during boot but provides a safe fallback as the file generated by the
# CentOS installer is not usable on macOS (results in a blank screen).
grub2-install --target=x86_64-efi \
--boot-directory=/mnt/sysimage/boot \
--efi-directory=/mnt/sysimage/boot/efi \
--bootloader-id=GRUB \
--removable
# This command generates the grub boot menu. If this file does not exist grub
# will immediately drop into the emergency console.
chroot /mnt/sysimage grub2-mkconfig -o /boot/grub2/grub.cfg
@zwalex
Copy link

zwalex commented Oct 1, 2022

Thanks @codello!
Yes, I managed to install Fedora and Debian 11 on that old Mac Mini, although with some tweaking because of the Broadcom wireless adapter. I might give CentOS another try with your suggestions.

@abirchall
Copy link

abirchall commented Aug 5, 2023

I had to add the following fixes for /usb/EFI/BOOT/grub.cfg in create-usb.sh:

sed -i 's/linuxefi/linux/g' /usb/EFI/BOOT/grub.cfg
sed -i 's/initrdefi/initrd/g' /usb/EFI/BOOT/grub.cfg

I'm currently stuck on fixing grub post centos install due to the following error when running grub2-install:

grub2-install: error: this utility cannot be used for EFI platforms because it does not support UEFI Secure Boot.

I've attempted to apply the steps here but to no avail.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment