How to run or boot Raspbian on a Raspberry Pi Zero without an SD-card.

{}
March 22nd, 2018

In an earlier post I explained how you can run and connect to a Raspberry Pi Zero with just an USB cable. Still the RPI Zero was using a micro SD card.

Luckily the great minds of the Raspberry Pi Foundation developed new boot modes: ethernet boot and USB Mass Storage Device (MSD) boot for the Raspberry Pi 3.

Now they came up with USBBoot, a tiny program that pushes the bootcode over the USB to the Raspberry Pi Zero (Raspberry Pi model A, Compute Module, Compute module 3 and Raspberry Pi Zero and Raspberry Pi Zero W), so it can boot without a micro SD-card.

Boot a RPI Zero from your laptop without SD card

In this post we will boot the Zero with the latest Raspbian Stretch (lite) from an common Ubuntu laptop, running 16.04LTS. It is surprisingly comfortable once you’ve set it up. And remember we’re running the Zero without any SD card, which costs are higher then a Raspberry Pi Zero. You do not need an SD card at all.

Yes, we use a standard USB cable to power,  connect, provide internet-access, an OS and storage for the Pi Zero.

So we gonna run the poor Raspberry Pi headless (=no monitor), armless (=no keyboard or mouse) and brainless (=no memorycard). And you know what? Back to the basics make the little gem shine!!

Be free, open and honest

We assume you’re running a free Linux OS Debian.

Why? Free the world and free yourself, make computers open, honest and transparent: no backdoors, no secrets, no patents. Share code, not your privacy! Github über Facebook. 🙂

Or find an old PC and install Linux. Lubuntu is running fine on a 1GB Pentium 4 or similar. Or make a VM. Whatever. But remember. If you’re using open standards and open source, you’re open to the world.

USBBoot utility

First start by downloading the USBBoot utility. Follow the instructions to compile the program.

$ git clone --depth=1 https://github.com/raspberrypi/usbboot
$ cd usbboot
$ sudo apt-get install libusb-1.0-0-dev
$ make

Prepare your laptop: Raspbian Stretch image

Then download the latest Raspbian Stretch image to your download directory Downloads.

cd Downloads
wget https://downloads.raspberrypi.org/raspbian_lite_latest

Now we gonna unzip this image:

unzip 2018-03-13-raspbian-stretch-lite.zip

Then you could burn the image to an USB flash drive, but we gonna do something clever, we gonna setup a loop device.

cd ~
 sudo losetup -P /dev/loop0 Downloads/2018-03-13-raspbian-stretch-lite.img

Then we need two mountpoints for the boot and rootfs directories. Let’s create them.

sudo mkdir -p /pi/{boot,root}

We’re creating them in the root  folder, you could also mount them in your home-directory if you like, but remember they are not writable, and are owned by root. So hence the choice for the /pi.

Mount the loop devices.

sudo mount /dev/loop0p1 /pi/boot
sudo mount /dev/loop0p2 /pi/root

Then we need the Raspberry Pi Zero to connect to the USB cable, and netboot Stretch. For that we need NFS mount.We have to set that up on the laptop and on the Pi.

Install nfs-server on the laptop.

sudo apt install nfs-kernel-server

Make the /pi/root folder a NFS mount point,  add this in the NFS config file `/etc/exports`

echo "/pi/root 10.42.0.14(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports

Save and restart the NFS server.

sudo systemctl start nfs-server.service
 sudo exportfs -a

That’s done on the laptop. Now move to the Pi Zero image for the last parts.

Prepare the Pi Zero image

Edit config.txt in the boot directory (/pi/boot) to enable USB OTG mode and add some instructions to add initramfs. This will load extra kernel modules, so the Pi Zero can use the USB cable as an ethernet connection.

Add these 4 lines in config.txt  :

# enable OTG
 dtoverlay=dwc2
 # set initramfs
 initramfs initrd.img followkernel

Then add make your  cmdline.txt look like this:

otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/nfs nfsroot=10.42.0.1:/pi/root rw ip=10.42.0.14:10.42.0.1::255.255.255.0:pi:usb0:static elevator=deadline modules-load=dwc2,g_ether fsck.repair=yes rootwait g_ether.host_addr=5e:a1:4f:5d:cf:d2

Let’s explain this.  We need NFS mount (root=/dev/nfs), we set the network address (nfsroot=10.42.0.1:/pi/root rw) rw is read/write. We need the modules dwc2 ethernet gadget and g_ether and we set a a fixed ethernet MAC address to ease, and we set the network addresses.

ip=10.42.0.14:10.42.0.1::255.255.255.0:pi:usb0:static
 ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf> 

Remember Ubuntu/Linux will set USB networks on the 10.42.0.1 address range, and we give the pi the fixed address 10.42.0.14. Please read my other posts about setting up an USB connnecting with the pi Zero, if you need more information.

Now we need to make a initramfs to supply some needed kernel modules. This is the best done on another Pi 1 or Pi Zero. We need to add the g_ether module and it dependencies in initramfs.

Make initramfs

Like said, that is best done on the same Pi model running the same OS, so if you own just 1 Pi Zero, you temporarily need an  SD card. Not sure if you can crosscompile this step.

First install the needed tools (if missing).

sudo apt install initramfs-tools

Add these modules to the modules file:

sudo vi /etc/initramfs-tools/modules
g_ether
 libcomposite
 u_ether
 udc-core
 usb_f_rndis
 usb_f_ecm

Save and create the initramfs .

sudo update-initramfs -c -k `uname -r`

It will be saved (initrd.img-4.9.80+ or newer) in the boot directory. Copy that file to the boot directory on your laptop: /pi/boot/, and name it initrd.img. As long it is the same name as in the config.txt file, it’s OK.

Now we are nearly done.

Modify /pi/root/etc/fstab in the Pi root directory, and comment out (or delete) the last two lines. The Pi shouldn’t try to mount SD-card images anymore.

Update: Then we need SSH to start automatically. (Thanks to Charlie for pointing this out. I forgot to document this step at first). An empty ssh file in boot will not do the trick this time, so we need to make it start it by adding this symlink in pi/root:

cd /pi/root/
sudo ln -s /lib/systemd/system/ssh.service etc/systemd/system/multi-user.target.wants/ssh.service

Connect your Pi

Connect your Pi. Run the utility rpiboot:

 usbboot/rpiboot -d /pi/boot/ 

Make sure you set the connection on shared. And your Pi Zero will boot, a  bit slowly.

ssh pi@10.42.0.14 

Does your Pi connect to the internet?

sudo apt update && sudo apt upgrade -y

Yes, and actually quite fast!

The Raspberry Pi Zero is really a 5 dollar computer in the end. No SD card, no keyboard, no monitor, no mouse needed. Just a Zero and an (old  Phone) USB micro cable.

All your changes will persist. The image in your directory will update. When you decide you need a SD card in the end, just flash the image to a SD card.

Tags:

37 Responses to “How to run or boot Raspbian on a Raspberry Pi Zero without an SD-card.”

  1. Jake Says:

    Great, had some trouble to get it working, actually I connected a monitor on the Zero to debug the NFS settings, because it didn’t boot in the beginning.

    Now it’s working fine.

  2. Charlie Says:

    Cool
    Couple of comments:

    1. SSH is not enabled on a fresh image. Putting an ssh file in boot did not seem to work (unless I’m too impatient?). Had to add the following to rc.local, then remove once ssh started
    systemctl enable ssh
    systemctl start ssh

    2. Making a shared connection may need a bit more explaining. I had to resort to using fixed IPv4 address on laptop, and then had to use iptables to allow shared internet access, e.g.
    echo 1 > /proc/sys/net/ipv4/ip_forward
    /sbin/iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
    /sbin/iptables -A FORWARD -i enp0s20u1 -o wlan0 -j ACCEPT
    /sbin/iptables -A FORWARD -i wlan0 -o enp0s20u1 -j ACCEPT

    but other than that, all worked great, thanks for the write-up

    C

  3. Hex Says:

    I am getting a kernel panic stating
    “`
    ipconfig: no devices to configure
    ipconfig: usb0: SIOCGIFINDEX: No such device
    Kernel panic — not syncing
    “`

    @Jake what problem did you have? Might be related

    I am using Fedora 27 x64

  4. Hex Says:

    How to setup the Desktop side of network configuration. I followed the instructions but there is no usb0 detected on the Linux host. Am I missing something ?

  5. webonomic Says:

    @Charlie. Now you mention it, yes, I changed some setting for SSH, which I forgot to document in this post. I will later. About the shared connection, I wrote two earlier post about it. Should have linked. Thanks for the feedback.

    @Hex
    https://dev.webonomic.nl/connecting-to-a-raspberry-pi-zero-with-just-an-usb-cable-ii

  6. Hex Says:

    @webonomic Can you share a working sd card image for this. I configured the static ip on both host and client image based on the previous guide and still i am unable to get it past kernel pannic.

    Is it necessary to compile initrd with the same kernel version or that is not strictly required to match?

  7. webonomic Says:

    @Hex, I would definitely recommend to compile initrd with the same kernel version.

    I stumbled also on kernel panic errors, while finding all out. In what stage do you get the panic error?

    – Is it loading initrd? (terminal laptop)
    – Do you see the NFS messages? (pi, connect monitor)
    – Does it start NFS?

    My guess: the initrd. BTW crosscompile should be possible, I’ve that done for the pi, but haven’t tried it for initrd yet.

  8. Hex Says:

    @webonomics I compiled the initramfs again and got it working. The network is connected to PC but it gets stuck at no route to host.

    https://i.imgur.com/OoqlJio.jpg

  9. Hex Says:

    Got the entire thing running. My firewall was blocking connections on usb0. Now works well

  10. Jay Says:

    Hi,

    Hex, do you have any idea how you “got it working”? I appear to be having the same initial error as you.

    The last line on the display that looks successful is:
    Begin: Running /scripts/nfs-premount … done

    Then I get 9 repeats of:
    ipconfig: usb0: SIOCGIFINDEX: No such device
    ipconfig: no devices to configure

    Then I get:
    Kernel panic – not syncing: Attempted to kill init! exitcode=0x00000200

    My zero is a v1.3, and my “computer” is a Pi3. The version of stretch on both is 2018-04-18.

    I’ve recompiled the initramfs a couple of times with no luck.

  11. Jay Says:

    Hi again,

    I think I figured it out. ‘uname -r’ gives me the value 4.14.34-v7+ on my development machine. When doing the update-initramfs it needs for the the -k argument the string ‘4.14.34+’. My understanding is that the -v7 is for pi2/3 architectures, without is pi0/1 (and so needed here).

  12. webonomic Says:

    @Jay. Great that you worked that out. Yes, you need to compile the initram on a Pi Zero or original Pi, or cross-compile.

  13. Hex Says:

    Hey Jay,

    Sorry for the delay, The pre-mount error occurs if the kernel mismatches with the kernel version of the initramfs or if the network is not connecting the pi to the Linux system.

    One thing to note is follow the instruction to the letter and ensure firewall settings are set to ignore for usb0 on host computer. Let me know how it goes. I will check for your reply for some time.

  14. Jay Says:

    Once I figured out the cross-compile thing I was able to get there pretty much just by following the instructions. Thanks for the detailed and helpful descriptions. I’m thinking about trying to get the same functionality going using tiny core linux on the zero as a much lighter OS alternative that runs completely in ram.

  15. webonomic Says:

    @Jay. Another approach, I followed, stripping away unneeded packages from a default mounted Raspbian Lite image, by simply uninstalling them from the pi Zero. (apt remove **).

    Remember, the mounted image is just a file on the harddisk, so it’s easy to copy, back-up and modify.`But tiny core will be much smaller.

  16. Jay Says:

    Hi, so I was able to build a piCore image that can boot over usb with usb ethernet gadget installed. To do that you’ll need to add the g_ether gadget to picore (see link http://forum.tinycorelinux.net/index.php?topic=20195.0 on how to do that), then you’ll need to start and configure it (modprobe dwc2 and g_ether and ifconfig the ethernet settings) at boot using bootlocal.sh, and lastly you’ll need to remaster the image (http://wiki.tinycorelinux.net/wiki:remastering) so that all the extensions/changes are in a single .gz file that can be loaded by usbboot (I didn’t need or want to get NFS going for the second file system). I did the first few steps on a SD card and then did the remastering before trying it out with usbboot. The boot time for the base piCore 9.0 system (on pi zero) over USB when customized this way was about 10 seconds.

  17. Jay Says:

    Hi,
    Until recently I’ve been testing this with a Pi Zero 1.3, and things have been working just fine. I’ve just tried it out on a Pi Zero W, and for whatever reason, the ethernet gadget isn’t seen by the connected system. Does anyone have experience with specifically one or the other board working? I’ve tried two 1.3’s and two W’s, and both 1.3’s work, but both W’s don’t. Strange.

  18. Dave Says:

    Also getting 9 repeats of:
    ipconfig: usb0: SIOCGIFINDEX: No such device
    ipconfig: no devices to configure

    Occurs after
    Begin: Running /scripts/nfs-premount … done.

    Have started from scratch with fresh image, and set up again, still getting same result. Host system is Ubuntu 18.04

  19. Dave Says:

    Okay, so I updated /pi/boot/cmdline.txt and changed usb0 to enp0s29u1u5 (which is the address I got previously when booting from SD card). The error message changed to:
    ipconfig: enp0s29u1u5: SIOCGIFINDEX: No such device

    So guess I’m on the right track, but unsure how to get the correct device. ifconfig isn’t showing anything other than my PCI ethernet

  20. Dave Says:

    So I didn’t have luck with other attempts. I ended up making a dd copy of the SD card, and then added the usual to config.txt and cmdline.txt.

    Copied across the initrd.img I had already done, and set the static IP in /pi/root/etc/dhcpcd.conf

    This time, it boots as per normal (!!??) and NFS loads. Now I have a new error:

    IP-Config: usb0 complete:
    address: 10.42.0.14 broadcast: 10.42.0.255 netmask: 255.255.255.0
    gateway: 0.0.0.0 dns0: 0.0.0.0 dns1: 0.0.0.0
    host: pi
    rootserver: 10.42.0.1 rootpath:
    filename :

    and then 10 copies of
    NOHZ: local_softirq_pending 04
    until:
    connect: connection times out
    NFS over TCP not available from 10.42.0.1
    Begin: Retrying nfs mount …

    Trying to narrow this one down now.

  21. webonomic Says:

    Hi Dave, you’re getting near. Yeah, this post was done on 16.04, will try it on a recent Ubuntu 18.04 soon and, @Jay, I will use a Pi Zero W. 😉

  22. ME Says:

    To create the symlink for SSH it is a bit trickier than described, you actually need:
    sudo mount / /pi/root/mnt -o bind
    sudo chroot /pi/root /mnt/bin/busybox ln -s /lib/systemd/system/ssh.service /etc/systemd/system/multi-user.target.wants/ssh.service

    Hope it helps.

  23. Eric Mockler Says:

    This is a great tutorial.
    The only thin I would add (if you are using a pi3B+ for the master) is to:
    Install bridge-utils
    create br0 and add eth0 as well as usb0
    My ifconfig looks like this after booting the zero. Only the bridge has an ip, and the zero gets 104, and access to my network. This is more like the way qemu gives a vm access.

    br0: flags=4163 mtu 1500
    inet 192.168.1.103 netmask 255.255.255.0 broadcast 192.168.1.255
    inet6 fe80::ba27:ebff:fe6b:7ca2 prefixlen 64 scopeid 0x20
    ether 0a:3b:5a:4b:c0:92 txqueuelen 1000 (Ethernet)
    RX packets 22222 bytes 2284653 (2.1 MiB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 11316 bytes 45224915 (43.1 MiB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    eth0: flags=4163 mtu 1500
    ether b8:27:eb:6b:7c:a2 txqueuelen 1000 (Ethernet)
    RX packets 895 bytes 126100 (123.1 KiB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 256 bytes 50240 (49.0 KiB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    lo: flags=73 mtu 65536
    inet 127.0.0.1 netmask 255.0.0.0
    inet6 ::1 prefixlen 128 scopeid 0x10
    loop txqueuelen 1000 (Local Loopback)
    RX packets 202 bytes 23790 (23.2 KiB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 202 bytes 23790 (23.2 KiB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    usb0: flags=4163 mtu 1500
    inet6 fe80::83b:5aff:fe4b:c092 prefixlen 64 scopeid 0x20
    ether 0a:3b:5a:4b:c0:92 txqueuelen 1000 (Ethernet)
    RX packets 21375 bytes 2177269 (2.0 MiB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 39119 bytes 47088687 (44.9 MiB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

  24. webonomic Says:

    @ME, you make a good remark the symlink for ssh.

    I can’t remember using chroot, but honestly, I also can’t remember how I did it exactly ;(

    Well probably I did this:
    cd /pi/root/etc/systemd/system/multi-user.target.wants/
    sudo ln -s /lib/systemd/system/ssh.service ssh.service

  25. Eric Mockler Says:

    How would I reboot the Pi zero from the host without physically unplugging it? I can unplug and re-run the usbboot, but I’d like to do this without restarting the host Pi or unplugging the Pi0.

  26. Eric Mockler Says:

    https://github.com/mvp/uhubctl can be used to interrupt power to the USB port, then you can run rpiboot again.

  27. 4 ways to connect your Raspberry Pi 4 to the internet - dev.webonomic.nl Says:

    […] if it will be possible to boot the Raspberry Pi 4 entirely over USB, without a SD card, like the RPI Zero. Not at the moment […]

  28. Ryan Aiello Says:

    Okay, I am trying to setup my rpi zero v1.3 (not wireless) to boot from a rpi 3 B (host computer), I compiled the initrd.img on my rpi zero W v1.1 and the raspberry pi zero v1.3 (not wireless) boots up fine until it hits the Begin: Running /scripts/nfs-premount … done then i get ipconfig: usb0: SIOCGIFINDEX: No such device
    nine times. please help.

  29. webonomic Says:

    @Ryan. I guess you have connected a screen to your Pi Zero.

    Sounds like you the USB ethernet is not set up correctly. Double check your settings in config.txt or cmdline.txt.

    You are running the same kernel on both Pi Zero’s?

  30. webonomic Says:

    @Eric. Nice tip.

    Also a more rudimentary approach is described here.
    https://www.raspberrypi.org/forums/viewtopic.php?t=162539

  31. kakurasan Says:

    Hi, I have a Pi Zero WH, followed this tutorial, but was not able to boot Raspbian because “g_ether” didn’t work. I tried using built-in WiFi instead (needed to install BusyBox and add some files into “/etc/initramfs-tools/”) and it’s now working without microSD card.
    The files I used are based on https://gist.github.com/telenieko/d17544fc7e4b347beffa87252393384c (See “Forks”). Note that two different “wpa_supplicant.conf” files are needed and “/etc/initramfs-tools/wpa_supplicant.conf” must have “ctrl_interface=/tmp/wpa_supplicant” line.

    The only problem is that the connected machine (Pi 3B+ or Ubuntu PC) still doesn’t detect “USB Ethernet gadget”.
    “dmesg” says my Zero WH is “Raspberry Pi Zero W Rev 1.1”, it also outputs “dwc2 20980000.usb: Mode Mismatch Interrupt: currently in Host mode”.

    I’m using “USB 2.0 OTG MicroUSB Male To USB Female” cable with “USB 2.0 Male To Male” cable.

    Tested kernel/OS versions:
    * 4.19.75+ (Buster, 2019-09-26)
    * 4.19.66+ (Buster, 2019-07-10, Updated kernel version)
    * 4.9.80+ (Stretch, 2018-03-13)

  32. Jay Says:

    @kakurasan, do you get different behaviour if you use a non-OTG cable? My understanding is that an OTG cable connects a 5th OTG ID pin to ground to force the usb port (on the zero) to be a usb host. If it is not grounded it should behave as a usb peripheral (which is what you want).

    Jay

  33. Jay Says:

    @Ryan Aiello

    Read my comments above for the solution to your issue (likely). The short answer is you need to cross-compile.

    Jay

  34. kakurasan Says:

    USB Ethernet gadget is now working. My Ubuntu PC detects “ID 0525:a4a2 Netchip Technology, Inc. Linux-USB Ethernet/RNDIS Gadget”.
    * Replaced my cables with (non-OTG) “USB To MicroUSB” cable
    * Added “,dr_mode=peripheral” after “dtoverlay=dwc2” in config.txt
    * Downgraded to Raspbian Jessie Lite 2017-06-21

    @Jay Right. I chose wrong cables (I didn’t intend to use USB devices from Zero WH). Now the “in Host mode” messages are not shown and “lsusb” on Zero WH shows nothing, but the gadget is still not detected with Stretch or Buster.

  35. webonomic Says:

    @Jay, @kakurasan.

    Just tried it in Buster (2019-09-26-raspbian-buster-lite.img), and it is working great.

    Main thing, you can run into something like usb0 not found, /run/usb0.conf not found or some kernel panic error.

    It’s really important that you create the initramfs on a Buster version with the same kernel running (Pi Zero of Pi 1). So what I did, I actually used an SD card with the Buster image to create the initramfs to eventually run the Pi afterwards without SD card booting over USB.

    See:
    https://dev.webonomic.nl/connecting-to-a-raspberry-pi-zero-with-just-an-usb-cable-i

  36. Marco Says:

    Hi,
    My first time with rpi zero wh. Flashed image and connected to tv via hdmi cable no signal…
    could the rpi bugged? so i followed your fine tutorial to check if it works with no sd.
    but when i run
    sudo ./rpiboot -d /pi/boot/ on my laptop linux mint Operating System: Linux Mint 19 Kernel: Linux 4.15.0-101-generic.
    I have these response:
    Waiting for BCM2835/6/7/2711…
    Sending bootcode.bin
    Successful read 4 bytes
    Waiting for BCM2835/6/7/2711…
    Second stage boot server
    File read: config.txt
    File read: start.elf
    File read: fixup.dat
    File read: config.txt
    File read: config.txt
    File read: initrd.img
    Unknown message
    The last line is coming after some minutes… where’s my mistake?
    Thank’s
    Marco

  37. webonomic Says:

    @Marco. I guess there is something wring with the initramfs. Just double check the steps.

Leave a Reply