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: rpi
March 26th, 2018 at 4:41 pm
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.
March 30th, 2018 at 7:34 pm
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
April 2nd, 2018 at 10:51 am
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
April 3rd, 2018 at 8:00 pm
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 ?
April 4th, 2018 at 10:21 am
@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
April 4th, 2018 at 9:39 pm
@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?
April 5th, 2018 at 10:33 am
@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.
April 5th, 2018 at 11:18 pm
@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
April 6th, 2018 at 2:25 am
Got the entire thing running. My firewall was blocking connections on usb0. Now works well
April 21st, 2018 at 8:53 pm
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.
April 21st, 2018 at 9:31 pm
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).
April 25th, 2018 at 10:25 am
@Jay. Great that you worked that out. Yes, you need to compile the initram on a Pi Zero or original Pi, or cross-compile.
April 28th, 2018 at 9:05 am
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.
May 9th, 2018 at 2:28 am
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.
May 15th, 2018 at 12:48 pm
@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.
June 13th, 2018 at 4:23 am
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.
September 30th, 2018 at 4:38 am
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.
October 13th, 2018 at 9:39 am
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
October 13th, 2018 at 10:12 am
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
October 13th, 2018 at 12:01 pm
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.
October 17th, 2018 at 7:35 pm
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. 😉
December 1st, 2018 at 8:34 pm
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.
December 14th, 2018 at 3:39 am
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
January 28th, 2019 at 10:37 pm
@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
February 16th, 2019 at 4:07 pm
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.
February 16th, 2019 at 6:42 pm
https://github.com/mvp/uhubctl can be used to interrupt power to the USB port, then you can run rpiboot again.
June 27th, 2019 at 9:34 am
[…] 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 […]
September 10th, 2019 at 6:01 pm
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.
September 19th, 2019 at 10:12 am
@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?
September 19th, 2019 at 10:18 am
@Eric. Nice tip.
Also a more rudimentary approach is described here.
https://www.raspberrypi.org/forums/viewtopic.php?t=162539
October 6th, 2019 at 6:59 am
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)
October 15th, 2019 at 12:54 pm
@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
October 15th, 2019 at 1:20 pm
@Ryan Aiello
Read my comments above for the solution to your issue (likely). The short answer is you need to cross-compile.
Jay
October 15th, 2019 at 5:31 pm
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.
February 7th, 2020 at 11:20 am
@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
June 21st, 2020 at 4:47 pm
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
July 5th, 2020 at 12:40 pm
@Marco. I guess there is something wring with the initramfs. Just double check the steps.