UEFI HTTP Network Boot not working due to missing /dev/ram0

After weeks of stupid grinding I got it working!

Let me try to explain how to get it working:

( 192.168.2.221 is the IP address of my server running the Nginx HTTP server)

  1. Create a folder structure like:
my_network_boot
my_network_boot/configs/butane
my_network_boot/files/grub2
my_network_boot/files/hosts/grub2
my_network_boot/files/images
my_network_boot/nginx/conf.d
  1. Create some files:
    my_network_boot/nginx/conf.d/default.conf:
server {
    listen 80;
    listen [::]:80;
	sendfile on;
	tcp_nopush on;
	tcp_nodelay on;
	keepalive_timeout 65;
	types_hash_max_size 2048;
	client_max_body_size 0;
	include /etc/nginx/mime.types;
	default_type application/octet-stream;
	error_log  /var/log/nginx/error.log notice;
	access_log  /var/log/nginx/access.log  main;
	gzip on;
	gzip_disable "msie6";
	include /config/nginx/site-confs/*;
}

my_network_boot/nginx/html as a soft link to the files directory:

ln -s files nginx/html

my_network_boot/compose.yaml:

---
services:
nginx:
    container_name: netboot_nginx
    image: nginx:1.27.4-alpine3.21
    network_mode: host
    ports:
      - 80:80
    volumes:
      - type: bind
        source: "${PWD}/nginx/conf.d"
        target: "/etc/nginx/conf.d"
        read_only: true
      - type: bind
        source: "${PWD}/nginx/html"
        target: "/etc/nginx/html"
        read_only: true
    restart: unless-stopped

my_network_boot/get_files.sh:

#!/usr/bin/env bash

#Define source directory of the Scrtipt
SOURCE_DIR=$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")

# openSUSE Leap Micro 6.1
# https://cdn.opensuse.org/download/distribution/leap-micro/6.1/appliances/
# https://documentation.suse.com/sle-micro/6.1/html/Micro-deployment-pxe/index.html
echo "\n########## openSUSE-Leap-Micro 6.1"
mkdir -p ${SOURCE_DIR}/files/images/openSUSE-Leap-Micro/6.1
wget -O ${SOURCE_DIR}/files/images/openSUSE-Leap-Micro/6.1/openSUSE-Leap-Micro.x86_64-Default-SelfInstall.install.tar -nc https://cdn.opensuse.org/download/distribution/leap-micro/6.1/appliances/openSUSE-Leap-Micro.x86_64-Default-SelfInstall.install.tar
tar xvf ${SOURCE_DIR}/files/images/openSUSE-Leap-Micro/6.1/openSUSE-Leap-Micro.x86_64-Default-SelfInstall.install.tar -C ${SOURCE_DIR}/files/images/openSUSE-Leap-Micro/6.1 --overwrite

my_network_boot/configs/butane/your_hostname.bu.yaml:

variant: fcos
version: 1.4.0
passwd:
  users:
    - name: root
      ssh_authorized_keys:
        - "ssh-rsa AAAAB3NzaC.......b3Z5TXQ== your_comment"
      password_hash: $6$sxfGOnw5tPck1LoS$N.YsNpCFM1MnbmAUGqmmZt/wy.42ugI7K1ZcGBfp4XdufTXxst1.I0u297hCWf.CKWxNwQ9joSgdh7KU96VKH1
    - name: yourUsername
      ssh_authorized_keys:
        - "ssh-rsa AAAAB3NzaC.......b3Z5TXQ== your_comment"
      password_hash: $6$sxfGOn........U96VKH
      home_dir: /home/yourUsername
      groups:
        - wheel
      shell: /bin/bash
storage:
  disks:
    - device: "/dev/disk/by-id/wwn-0x50014ee21264eceb"
      wipe_table: true
      partitions:
        - number: 1
          size_mib: 0
          label: opt
  filesystems:
    - path: /home
      device: "/dev/disk/by-id/wwn-0x5002538d40db1ab0-part3"
      format: btrfs
      wipe_filesystem: false
      with_mount_unit: true
      mount_options:
        - "subvol=/@/home"
  files:
    - path: /etc/NetworkManager/system-connections/enp1s0.nmconnection
      mode: 0600
      contents:
        inline: |
          [connection]
          id=enp1s0
          uuid=b5344841-0f14-4406-b699-c9d70cc198f9
          type=ethernet
          autoconnect-priority=-100
          autoconnect-retries=1
          interface-name=enp1s0
          multi-connect=1

          [ethernet]

          [ipv4]
          address1=192.168.0.5/23
          dns=192.168.0.1;
          gateway=192.168.0.1
          may-fail=false
          method=manual

          [ipv6]
          method=disabled

          [proxy]
systemd:
  units:
    - name: sshd.service
      enabled: true
    - name: cockpit.socket
      enabled: true

my_network_boot/files/hosts/grub2/a8:a1:59:1d:ca:c0 with a file name with the MAC address of the to be network booted device:
(Change the example IP address 192.168.2.221 in the file)
(Change your_hostname.ign)

# opensuse leap micro 6.1

set default="opensuse-leap-micro-6-1"
set timeout=30

if [ x"${feature_menuentry_id}" = xy ]; then
  menuentry_id_option="--id"
else
  menuentry_id_option=""
fi

menuentry "Boot from Hard Disk" --class os --unrestricted $menuentry_id_option 'boot-from-hard-disk' {
    exit
}
menuentry "Install openSUSE Leap Micro" --class os --unrestricted $menuentry_id_option 'opensuse-leap-micro-6-1' {
    echo Loading kernel...
    linux ($root)/images/openSUSE-Leap-Micro/6.1/pxeboot.openSUSE-Leap-Micro.x86_64-6.1.kernel rd.kiwi.oem.installdevice=/dev/disk/by-id/wwn-0x5002538d40db1ab0 rd.kiwi.install.pass.bootparam rd.kiwi.install.pxe rd.kiwi.install.image=http://192.168.2.221/images/openSUSE-Leap-Micro/6.1/openSUSE-Leap-Micro.x86_64-6.1.xz ignition.config.url=http://192.168.2.221/hosts/your_hostname.ign
    echo Loading initrd...
    initrd ($root)/images/openSUSE-Leap-Micro/6.1/pxeboot.openSUSE-Leap-Micro.x86_64-6.1.initrd
}

my_network_boot/files/grub2/grub.cfg

if [ -s /hosts/grub2/${net_default_mac} ]; then
   source /hosts/grub2/${net_default_mac}
fi
  1. Create the Grub2 netboot directories with grub2-mknetdir:
    grub2-mknetdir(1) — grub2-common
cd files
sudo grub2-mknetdir --net-directory=./ --subdir=grub2
cd ..
  1. Fix the owner:
sudo chown yourUsername:yourUserngroup -R files
  1. Create the Grub2 images with grub2-mkimage
    grub2-mkimage(1) — grub2-common
    (Change the example IP address 192.168.2.221 in the command)
cd files
sudo grub2-mkimage -O x86_64-efi --output grub2/x86_64-efi/core.efi --prefix '(http,192.168.2.221)/grub2' btrfs tftp normal ls echo minicmd halt net reboot http linux bsd zfs video efi_gop efi_uga efifwsetup efinet efitextmode
cd ..
  1. Start the container using Docker or Podman:
podman compose up -d --build

Logs can be checked with:

podman logs -f netboot_nginx
  1. Confige your already existing DHCP server, in this case it’s a config for ISC DHCP on an OPNsense,
    /usr/local/etc/dhcpd.opnsense.d/http-network-boot.conf:
    (Change the example IP address 192.168.2.221 in the file)
class "httpclients" {
    option vendor-class-identifier "HTTPClient";
    match if substring (option vendor-class-identifier, 0, 10) = "HTTPClient";
    filename "http://192.168.2.221/grub2/x86_64-efi/core.efi";
}
  1. Generate the ignition config out of the butane config:
    (use podman or docker)
podman run --interactive --rm quay.io/coreos/butane:release --pretty --strict < configs/butane/your_hostname.bu.yaml > files/hosts/your_hostname.ign
  1. Now you can boot your device via UEFI HTTP IPv4
  2. Pray! :grinning:
4 Likes