How To Make A Linux Distro

How To Make A Linux Distro

Reading time1 min
#Linux#OpenSource#Technology#LinuxDistro#Buildroot#CustomKernel

Building Your Own Linux Distro: From Requirements to Custom Image

Most prebuilt Linux distributions sacrifice control for convenience and legacy compatibility. If you’re targeting nonstandard hardware, optimizing for boot time, or enforcing strict security guarantees, public images just aren’t enough.


Pin Down Requirements and Hardware Constraints

Skip this and you’ll waste days rebuilding. Precise requirements drive every architectural decision:

  • Target platform: e.g., Raspberry Pi 4 Model B (BCM2711, ARM Cortex-A72), virtual machines (KVM), industrial x86 boards.
  • Primary use case: headless IoT node, ultra-minimal GUI desktop, cryptography appliance.
  • Memory/storage envelope: sub-128MB RAM? eMMC only?
  • Security demands: Read-only root, encrypted rootfs, custom SELinux/AppArmor policies.

It’s easy to get sucked into feature creep. For IoT sensors needing quick net connectivity and update support, a 25 MB statically linked rootfs is realistic (think BusyBox + Dropbear + mdev + custom daemons, no PAM).

Table: Sample Hardware/Feature Matrix

TargetCPU ArchRAMBoot TypeNetworkDisplaySpecial Needs
Raspberry Pi 4ARMv8 Cortex2GBU-Boot+EFIGbE/WiFiHDMIGPIO, SPI
QEMU VMx86_641GBSeaBIOSvirtiononeVirtFS, QXL graphics
Custom BoardARMv7256MdirectUSB LTEnoneWatchdog, CAN

Build System Selection: From Scratch or Framework?

Scratch builds (see Linux From Scratch 11.3) teach fundamentals but rarely scale; fine for research, not production. Modern embedded and cut-down distros prefer frameworks:

  • Buildroot 2023.08: Focused on small, fast, single-purpose systems. Limited package options.
  • Yocto (Kirkstone 4.0): Huge, with package feeds. Strong for commercial/long-term support.
  • Debian Netinst/Arch Bootstrap: Standard distros, then prune mercilessly. Start here if your goal isn’t ultra-lean images.

For walkthrough reproducibility, this guide uses Buildroot. It cross-compiles cleanly, supports multiple targets, and is tissue-thin compared to mainstream roots.


Prepare Buildroot: Version Control Everything

Never hand-edit core configs outside of Git or you’ll regret it.

git clone https://github.com/buildroot/buildroot.git
cd buildroot
git checkout 2023.08.1
cp -r ../my-config-overlay/ .
# Document all patches to board/ or configs/

make menuconfig triggers the ncurses UI. If building for Raspberry Pi 4:

  • Target architecture: ARM (aarch64)
  • Toolchain: “External toolchain” if you need glibc over musl, otherwise internal is fine.
  • Enable minimal SSH (Dropbear), manager shell as BusyBox, and include necessary drivers via “Kernel modules”.
  • Skip X11 unless required; go for Wayland or framebuffer for GUIs.

Tip: The default kernel versions may lag; check the latest stable LTS releases and plug into Buildroot as a custom tarball.


Kernel: Actual Tuning, Not Checkbox Clicking

No bloat: disable unneeded filesystems, wireless stacks, latency-impacting mitigations unless needed.

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.30.tar.xz
tar -xf linux-6.6.30.tar.xz
cd linux-6.6.30
make ARCH=arm64 menuconfig
# Example: Enable CONFIG_PREEMPT_RT for low-latency if real-time apps

Gotcha: Buildroot can override your .config during builds if not using a “custom kernel” option. Always test by running:

make linux-savedefconfig

and keep minimal defconfigs under version control.

Build with:

make -j$(nproc) ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-

Export Image, dtb, and modules/ to expected locations for Buildroot integration (output/images/).


User-Space: Strip to Essentials

Resist adding every tool you “might need.” Start with:

  • BusyBox 1.36.1: File, networking, shell, process tools in one binary.
  • init system: BusyBox init suffices for most—no systemd = smaller images, less risk. Watch out for services that hard-require systemd (e.g., resolved, logind).
  • Networking: Dropbear or OpenSSH (if you need scp/rsync), udhcpc for DHCP.

Configurable in Buildroot menus under “Target packages.”

Known issue: Some X11/Wayland DEs silently require PAM or dbus unless explicitly disabled (look for hidden deps—“Why is my simple LXDE image 400 MB?”).


Custom Init and Boot Scripts

Minimal images—the less shell logic in /etc/init.d/, the less to debug at 3 a.m. Logging to serial/UART is non-negotiable for debugging early boot.

Example of minimal /etc/inittab for BusyBox:

::sysinit:/etc/init.d/rcS
ttyAMA0::respawn:/bin/sh
::ctrlaltdel:/sbin/reboot

Tip: Always test cold boots with and without peripherals (SD out, network unplugged). Udev or mdev can behave non-intuitively.


Image Creation and Deployment

Let Buildroot build the output image, but sanity-check the output:

make
ls output/images/

Typical outputs:

  • sdcard.img for device flashing.
  • rootfs.cpio.gz for netboot/NFS.
  • Optionally, .iso via:
    make isoimage
    

Deploy using dd:

sudo dd if=output/images/sdcard.img of=/dev/sdX bs=2M status=progress

Or, for emulation:

qemu-system-aarch64 -M raspi4 -kernel output/images/Image -dtb output/images/*.dtb -append "root=/dev/mmcblk0p2 console=ttyAMA0,115200" -sd output/images/sdcard.img

Trade-off: Buildroot’s default images lack a package manager. To get apt/pacman, you must pivot to a different base (or maintain your own feed, which is rarely worth it for small footprint targets).


Practical Walkthrough: 50MB ARMv8 Minimal Distro

  1. Clone Buildroot 2023.08.1.
  2. make menuconfig:
    • ARM64, external Linaro toolchain
    • Enable BusyBox, Dropbear, mdev, no X11
    • Custom kernel: Linux 6.6.30
    • No package manager, static /etc/fstab and networking
  3. Build – ensure host has python3, make, gcc-aarch64-linux-gnu.
  4. Write image to SD and cold boot on RPi4.
  5. On first boot, check serial output for:
    EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode
    
    and Dropbear up on port 22.

Countless times, bad WiFi firmware or improper DT overlays kill the first boot; keep UART open.


Tricks, Tips, and Gotchas

  • Use BR2_ROOTFS_OVERLAY for injecting configs, keys, or custom services—safer than patching the Buildroot skeleton.
  • For U-Boot, always cross-verify boot.scr scripts, especially if the board has quirks—wrong loadaddr is a common failure point.
  • Version-lock everything—upstream removes old kernel/toolchain versions without notice.
  • Validate with QEMU and real hardware: discrepancies abound (GPIO, networking, display).

Closing Thought

Distro building is inherently iterative—perfect is the enemy of good. Once a minimal image boots and fits requirements, only then start adding polish. Every extra feature reintroduces risk and complexity. Strip it back, automate repeat builds, and document everything—future-you will thank you.

No universal playbook exists; expect to hit sharp edges. That’s the value: understanding and owning every byte that boots on your hardware.