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 there 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 for the last parts.

Prepare the Pi Zero

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

First install the needed tools.

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 where 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:

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.

16 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.

Leave a Reply