Introduction: The Ultimate Headless RPi Zero Setup for Beginners

About: I'm a computer programmer who loves building electronics, art projects, writing music, and shooting photography.

In this Instructable, we'll take a look at my base setup for all Raspberry Pi Zero projects. We'll do it all from a Windows machine, no extra keyboard or monitor required! When we're done, it'll be on the internet, sharing files over the network, work as a USB thumb drive and more. There is a YouTube video (COMING SOON!) that accompanies this write up as well, in case you're a more visual person.

love Raspberry Pi Zeros and I think they're super useful, but it takes a lot of work to get them ready to be integrated into projects. My goal here is to walk you through all of that setup as easily as possible, and then I'll show you how to back up your new custom Raspbian OS SD Card so you can re-image new memory cards in 15 minutes and never have to walk through this process again.

Unfortunately, this write up is made specifically for Windows users. It'd certainly be useful to everyone else, but I don't do this process on Linux or Mac OS, so I can't help with the exact process on those machines. I'm sure you could still follow along, though. There isn't THAT MUCH that is specific to Windows here and all of it could be done on any other operating system with a little help from Google.

This is primarily meant to be used on a Raspberry Pi Zero, although it would all work on a Zero W just fine. That being said, none of the USB OTG functionality will work on any of the other Models (A, B, etc.) as the only models that support it are the Zero and Zero W.

Step 1: Downloads and Installs

First thing we need to do is download and install a bunch of software.

We'll need Balena Etcher for writing disk images to SD cards which can be downloaded from HERE.

Speaking of disk images, let's grab Raspbian Lite from HERE. At the time of writing, I'm using Rasbian Buster Lite.

I like to grab the SD Memory Card Formatter app from HERE. This is used to format SD cards before I image them. This is kind of a formality, it's probably not necessary in most cases, but I've read that it can save you some grief with brand new SD cards so why not.

Then download Putty from HERE. You're definitely going to want Putty if you're messing with Raspberry Pis, especially if they're 'headless'.

This one might sound surprising, but next we'll be grabbing Bonjour Print Services by Apple from HERE. This lets us refer to our Raspberry Pi (and other devices) by name so we don't have to figure out what its IP Address is in order to connect to it. You may already have this installed on your machine, it's worth checking first.

Finally, grab Win32 Disk Imager from HERE. We'll use this at the end to make a disk image of our finished SD card. Then, we can copy it back onto SD cards with Balena Etcher any time we mess something up or start a new project.

Alright, now install everything, this should be straight forward. When you're done, restart Windows and pop your micro SD card into the your computer and continue.

Step 2: SD Card Setup

Now let's use all the new software to setup the SD card. But before we do that, please note that it's a good idea to start with an 8 or 16 gig card for this. We're going to be backing our system up for re-use later and if you start with a huge card, you can't write it to a smaller card. You can, however, write a smaller card to a larger one and then expand the Linux file system to fill it. So starting small will make this more useful later.

So first, run the SD Memory Card Formatter app, choose your SD card, select "quick format" and type in a volume label. Click "Format" and give it a moment to prepare the card. If your memory card has multiple partitions on it, selecting any of them will work just fine; it'll format the whole card regardless.

Then, uncompress the Raspbian Lite disk image with whatever you prefer (I use Winrar).

Run Balena Etcher and select the Raspbian Lite .img file you just uncompressed. Select your SD card and give it time to write the image to your card and verify it.

Once that's done, you'll probably need to remove and re-insert the SD card to get Windows to pickup the new partitions. When you see a drive labeled "boot" appear in "This PC", open it. If you get a warning about the other partition being unreadable, just ignore it; it's a Linux partition which Windows can't natively read.

Run any application you're comfortable with to create text files. Notepad is fine for this, Microsoft VS Code is even better.

First, add an empty file to the "boot" drive named "ssh" with no file extension: leave it completely empty. This will ensure Raspbian starts the SSH server on boot, which we'll connect to later with Putty. You may have to show file extensions in File Explorer to be sure that your file is named exactly "ssh" and not something like "ssh.txt". Here is an example of how to show file extensions in Windows 10.

Next, let's edit "config.txt". We're going to jump to the bottom of the file and add:

dtoverlay=dwc2 

This will enable the USB OTG functionality we need for running an Ethernet and Mass Storage Device over USB.

Then, open "cmdline.txt". We need to be very careful in here: every command goes on the first line and needs a space between it and other commands around it. I also add a space at the end of the first line to be safe, and make sure there is an empty second line in the file. Scroll to the very end of that first line and add:

modules-load=dwc2,g_ether

Alright, the SD card setup is complete! Pop that micro SD card into your Raspberry Pi and plug the Raspberry Pi into your computer via USB. Make sure you plug your USB cable into the center most USB port; the outside port is only connected to power.

Step 3: RPI SETUP PART 1

Once Raspbian boots, it will enable the USB OTG functionality on the full USB port. Then, it'll start a service that appears to be a USB Ethernet adapter to Windows and, finally, it'll start a SSH server that we can connect to over Ethernet from inside of Windows. This is the key to not needing a keyboard or monitor.

In Windows, open the "Device Manager" by clicking the start menu and typing "Device Manager". Once that's up, you'll be able to see all of the devices discovered by Windows. If you watch your device manager, you'll see a new network adapter show up called "USB Ethernet/RNDIS Gadget" which is how you know you're ready to connect. Assuming you installed Bonjour earlier, you can connect to the Raspberry Pi by name; if not, you'll need something like NMAP to scan your network for it.

Open up Putty which will be set to SSH by default. In the host box, type "raspberrypi.local" and hit enter. If everything has been done correctly, you will probably get a security alert popup warning you about the SSH key from the Raspberry Pi. That's fine, just click yes to continue and you'll get a login prompt from the Raspberry Pi.

If you're unable to connect, wait until the light on the Raspberry Pi stops blinking (it'll just be solid green) and unplug it. Check that you're using the center most USB port, ensure you've restarted Windows since installing Apple Bonjour and plug the USB back in. Sometimes, things don't work on the first time.

The default user account login for a Raspberry Pi is:

pi

And the password will be:

raspberry

Once you've logged into your Pi, the first thing we need to do is rebuild our USB devices to support Ethernet and Mass Storage instead of just the Ethernet that we have now. Do that by typing:

sudo nano /etc/modules

This will open a file in the Nano text editor with administrator privileges. Once opened, scroll to the bottom of the file and type or paste:

dwc2

(Note: if you copied this, you can paste it into Putty by right clicking on the terminal.) Then, hold the Control key and hit X to exit. It'll ask if you're sure you want to save, choose yes. Then, it'll ask you to confirm the file name, just hit enter.

Before we go any further, let's talk about the USB Mass Storage (thumb drive) functionality we're setting up. It's very useful for easily copying files or scripts over for use on the Pi, or for your scripts on the Pi to write files like logs that can be easily picked up from Windows. There are a few caveats to this, though. You can't write to the partition from the Raspberry Pi and Windows at the same time, so you have to decide upfront which side you want to be able to write to it. Also, if you make it writable on Windows, you will get a warning about the drive needing to be repaired sometimes. This is a minor annoyance and it never actually needs repair unless you unplug the Raspberry Pi while it's writing files, so it's really not a big deal.

With all that said, let's create the container file for our USB Mass Storage partition data. I'm setting it to 2 gigabytes or 2048 megabytes here. You can reserve more or less space if you'd like. Enter:

sudo dd bs=1M if=/dev/zero of=/piusb.bin count=2048

Next, we'll format that container to be a fat32 MSDOS compatible partition. Enter:

sudo mkdosfs /piusb.bin -F 32 -I

Now, make a directory to use as your mount point for this partition with:

sudo mkdir /mnt/usb_share

And we'll have to add an entry to fstab for the new partition with:

sudo nano /etc/fstab

Copy this to the end of the fstab file:

/piusb.bin /mnt/usb_share vfat users,umask=000 0 2

Once that's done, let's mount all new partitions and make sure we don't get any errors. If you do, please retrace your steps here and ensure you haven't missed anything.

sudo mount -a

OK, almost done setting up USB devices. Now, let's go into "rc.local" and add some lines to re-activate our USB devices and remount this partition after every boot with:

sudo nano /etc/rc.local

Copy the following BEFORE the line that says "exit 0" so that it remains the last line of the file:

/bin/sleep 5
/sbin/modprobe g_multi file=/piusb.bin stall=0 removable=1
sudo mount -o ro /piusb.bin /mnt/usb_share

NOTE: The above lines will make it so Windows can write to the thumb drive and Linux can only read from it. If you want this to be the other way around, use this instead:

/bin/sleep 5
/sbin/modprobe g_multi file=/piusb.bin stall=0 removable=1 ro=1
sudo mount -o /piusb.bin /mnt/usb_share

There are a few things to notice about what we've pasted in here. I have a sleep of 5 seconds; you can reduce that down to more like 1 second if you like. Later, if your startup gets bloated with other services and drivers, you may want to increase this. I just leave it at 5 to be safe.

The second line is starting up a Multi-Function Composite USB Gadget. In a moment, we're going to remove our previously setup "g_ether" Gadget as this one includes Ethernet, Serial and Mass Storage all in one. The third line remounts the fat32 partition on the Raspberry Pi. Remember, you can always come back later and change which side is read only for different projects or if you change your mind.

Now that we've done that, let's go back into "cmdline.txt" and remove "g_ether" from the end with:

sudo nano /boot/cmdline.txt

Scroll to the end of the first line and remove "g_ether", then save.

Alright, take a moment to pat yourself on the back; you've come a long way. Now, let's reboot the Raspberry Pi and get it ready to use again in Windows.

sudo reboot

Step 4: RPI Setup Part 2

There are a lot of quirks to using the Multi-Function Composite USB gadget functionality on the Raspberry Pi. I haven't found a way to get around most of these things, but they're no big deal once you get used to them.

The first: when the Raspberry Pi is booting, while plugged in as a USB OTG device, you will get a warning in Windows that it's an unknown device; just ignore that. We added the "g_multi" module start to "rc.local" to fix this issue but it takes a few seconds for that to kick in. After a bit, the USB devices will remount and your USB thumb drive will popup.

The second quirk: Sometimes, when the thumb drive appears, Windows will complain that there's something wrong with it and it needs to be scanned for errors. The reason for this is complicated, but unless you've unplugged the Raspberry Pi while writing to the SD card, there's nothing wrong with it; it's just a quirk with the way Linux mounts it. You can repair it if you like, or just ignore it.

OK, so now you have a thumb drive hosted by the Raspberry Pi. If you made it writable by Windows then now is a good time to create a text file on it named "test.txt" with some text in it, Later, we'll read it back from Linux.

This third quirk you will only have to fix once per machine you're using it on, so although it is going to look annoying, you will probably only have to do it once.

Bring up the "Device Manager" like before and under "other devices" you should see a device with a warning on it named "RNDIS". I'm not sure why "g_ether" worked just fine, but this doesn't; it's an easy fix, though. Right click on it and choose "Update driver". Then "Browse my computer" and "Let me pick". Select "Show all devices" and give it some time to load all the choices. Once loaded: scroll down the "Manufacturers" list and select "Microsoft" (not "Microsoft Corporation", just "Microsoft"). On the "Model" list: scroll down to "Remote NDIS compatible device" and select it, then click "Next" in the bottom right. You will get a warning, just click "Yes" and close the dialogue when that's done installing.

If all goes well, you will now have a "Remote NDIS compatible device" under "Network Adapters". We're now able to talk to the Raspberry Pi again.

Next, let's make sure it is able to reach the internet through our Windows machine's internet connection. To do that, click the "Start" button and type "Network Status" and select it. Once that pops up: scroll down a bit and choose "Change Adapter Settings". You should see your Raspberry Pi NDIS device in here with a name like "Ethernet 5" and also the network adapter you use to connect Windows to the internet with; this is most likely going to to be named something like "Wifi". Right click on the one that connects you to the internet and choose "Properties". Then, click the "Sharing" tab on the window that pops up. Now check the box that says "Allow other network users to connect through this computer's internet connection" and select the network adapter name of the Raspberry Pi NDIS device we just looked at (something like "Ethernet 5".)

Once this is done, we can check the Raspberry Pi for internet connectivity by re-connecting with Putty like before. The first thing I check when looking for internet connectivity on the Pi is pinging 8.8.8.8 which is a Google domain name server. You can do this by typing:

ping 8.8.8.8

You will most likely not have connectivity, in which case just reboot your Pi with:

sudo reboot

When it reboots, it'll bring the Ethernet adapter back up and Windows should start tunneling internet connectivity to it automatically from now on. You should know it's booted by waiting for the USB drive to pop back up. Now, let's connect with Putty again and re-test for internet connectivity:

ping 8.8.8.8

This time, it should work just fine, so now let's see if we can ping www.google.com:

ping http://www.google.com

Ok, perfect. So our Raspberry Pi is officially connected to the internet! Nice work!

If you're having issues at this point, you may also have to remove the device from "Device Manager" (right click on it and choose "Uninstall Device" and restart Windows). Then start this step again. Before going that far, I would re-read everything and make sure you didn't miss anything.

Step 5: RPI Setup Part 3

Now that we have the Pi online, we can start installing things and setting the rest up. Before installing anything, though, we should update our APT packages with:

sudo apt-get update

Next, let's do a little house cleaning before going any further by running:

sudo raspi-config

Once that's up, choose "Change User Password". Then let's customize the host name for this Raspberry Pi to be something other than default. Select "Network Options" and then "Hostname". I named mine "devpi" but you can go with whatever suites you; just keep in mind we're going to image this SD card later so you probably don't want to make it overly specific to a project just yet as you will hopefully re-use this setup later. Once done, go back and choose "Finish", which will probably restart your Raspberry Pi.

Once the thumb drive comes back up again, let's re-connect with Putty. Keep in mind that your Raspberry Pi is now named something different, so you can't use "raspberrypi.local" anymore to connect. Now, you'll need to use the hostname you just entered. You will also get a new SSH key warning because the host name is different, which is fine. Your login will still be "pi" but your password will now be different as well.

Now, let's install Samba file sharing so you can edit files in Linux from inside Windows. First, we'll install "avahi-daemon":

sudo apt-get install avahi-daemon

Then:

sudo update-rc.d avahi-daemon defaults

This next step appears to be allowing Apple Talk over port 548. To be honest, I'm not sure why this is necessary, but I couldn't get Samba file sharing to work without it, so here we are. We're going to create a new service file with:

sudo nano /etc/avahi/services/afpd.service

And paste some XML into it:

<?xml version="1.0" standalone='no'?><!--*-nxml-*-->
  <!DOCTYPE service-group SYSTEM "avahi-service.dtd">
  <service-group>
      <name replace-wildcards="yes">%h</name>
      <service>
          <type>_afpovertcp._tcp</type>
          <port>548</port>
      </service>
  </service-group>
</xml>

Then hit control x to save. Now restart "avahi-daemon" and we should have zeroconf service discovery setup.

sudo /etc/init.d/avahi-daemon restart

Finally, let's install the Samba file sharing service. When you get the blue screen asking to enable WINS support, I always say no.

sudo apt-get install samba samba-common-bin

Let's change the default Samba file sharing password:

sudo smbpasswd -a pi

Once that's done, we'll need to modify the default Samba configuration with:

sudo nano /etc/samba/smb.conf

There's a lot you can configure in here, but I just drop to the bottom of the file and paste my default sharing settings:

workgroup = WORKGROUP
wins support = yes
	
[source]
   comment = HOME
   path = /home/pi/
   browseable = Yes
   writeable = Yes
   only guest = no
   create mask = 0777
   directory mask = 0777
   public = yes
   read only = no
   force user = root
   force group = root

This will share "/home/pi" with full read / write access. Feel free to customize this now, but I use this for editing scripts from Windows, so I like to leave it wide open. Press Control + X to save and reboot the Raspberry Pi to kick all that into gear:

sudo reboot

Step 6: RPI Setup Part 4

As usual, once the USB thumb drive pops back up in Windows, we're ready to continue. This time, let's try to access the Linux file system over our new Samba share. In Windows, you can do this by opening File Explorer or any file browser and going to the path "\\YOUR_HOST_NAME" (replace with your actual hostname.) It's going to ask you for credentials, which are your typical default Pi user "pi" and whatever your new password is. Make sure you tell it to remember your credentials so you don't have to keep entering this info.

If everything worked properly, you will see some shared folders. Both of these point to the same "home/pi" directory. Open one of them and create another text file named "test.txt" like we did on the USB thumb drive earlier.

Now that we have both test files in place, let's read them from the Raspberry Pi. Re-connect to SSH and type the following to see what's in your user home directory:

ls 

You'll see the test text file we just created. You can confirm that by listing its contents with the cat command:

cat text.txt

If we list the contents of "/mnt/usb_share", we can see the text file we made on the USB drive in Windows as well:

ls /mnt/usb_share

And if we cat that, we can see its contents:

cat /mnt/usb_share/test.txt

Wonderful! You're done setting up the Raspberry Pi!

Step 7: Backup Disk Image

Alright, you're all done setting up a base for new projects! Nice work! This has been a journey, but before we get too wild with this setup, we need to back it up so we can easily restore back to this point or copy this setup for new projects in the future. To do that, let's shutdown the Raspberry Pi and put the SD card back into the Windows machine:

sudo shutdown -h now

Once the SD card comes up in Windows, run Win32 Disk Imager. In that, we'll enter a path and filename for our backup disk image. Make sure you give it a file extension of ".img".

Then, make sure you have the right drive selected. This should be the boot drive from your SD card.

Then, click "Read only allocated partitions" to speed this process up. Finally, click "Read" and let it do its thing.

When that's done, we can see that it's created a disk image file that's almost the size of the entire SD card! We can make this MUCH smaller by compressing it as most of that file content is empty. I'm using Winrar, but you can use whatever you prefer, just make sure you choose a high level of compression. Now you can see the image archive is MUCH smaller.

So that's it, you now have a Raspberry Pi connected to the internet and your Windows machine over USB. No need for any other hardware. You can connect to it over SSH, write code on it from your favorite editor in Windows, save files directly to the Linux file system or pass them via the USB thumb drive in Windows. This is a real convenience being able to pass it files from other computers that you won't be able to fix the networking on. You can also write scripts that will watch for new files and run them as soon as they appear on the thumb drive!

I'm glad you made it through this whole tutorial! I hope everything worked properly the first try and this saved you a ton of time. If you have any issues, I'll do my best to help in the comments, and if you have any changes you'd make to my setup, I'd love to hear your thoughts and suggestions.

Step 8: Bonus Tips

Restoring to larger disks

If you're restoring this image to a new SD card that is larger then the disk image, you'll want to expand the Linux file system to fill the new card. This can be done by running "raspi-config":

sudo raspi-config

Then choose "Advanced Options". Then, "Expand Filesystem". Once this completes, your Linux system will be using the entire SD card, even if you started with a much smaller disk image.

Seeing new written files on the thumb drive from Windows in Linux

You will have to un-mount and re-mount this fat32 drive in Linux to get any new files to show up. This is very trivial to do and can be done with:

sudo umount /mnt/usb_share

Then:

sudo mount -o ro /piusb.bin /mnt/usb_share

And now you should see your new files in Linux:

ls /mnt/usb_share

Watching for new python scripts on the thumb drive and running them automatically

A shell script can be made to watch for new files automatically and do something with them as they appear. It feels like a heavy operation to run continuously so I try not to run it TOO fast, but the Raspberry Pi doesn't seem to mind too much.

First, create the shell script:

nano refreshPythonScript.sh

Paste in the following script and edit to taste:

#!/bin/sh

remoteFile="/mnt/usb_share/Main.py"
tempFile="/home/pi/tempMain.py"
localFile="/home/pi/Main.py"

# delect local file and replace it with an empty file
rm $localFile
touch $localFile

while true
do
    # unmount and remount usb_share to refresh the files on it
    sudo umount /mnt/usb_share
    sudo mount -o ro /piusb.bin /mnt/usb_share

    # copy the Main.py off the usb share for comparing
    sudo \cp -r $remoteFile $tempFile

    if cmp -s "$tempFile" "$localFile"; then
        echo "they match"
    else
        echo "they're different"
        # kill the python script if it's already running
        sudo killall python3
        # copy temp file over the local file
        sudo \cp -r $tempFile $localFile
        # run local file
        sudo python3 $localFile
    fi

    # wait a bit before checking again
    sleep 10
done

Save with Control + X and change the permissions on the script so it can be executed:

chmod +x refreshPythonScript.sh

And now you can run it anytime by typing:

./refreshPythonScript.sh

This can of course be done automatically when the Raspberry Pi starts, which turns it into an interesting little Python device!