Recently, I got my hands on a brand new Raspberry Pi and was asked to make it usable. I didn’t have an HDMI monitor or keyboard, so I decided to configure it as a headless station. I don’t have an Ethernet cable at home but I have a Wi-Fi router. So, the task was to prepare the Raspberry Pi with MacBook Pro (with card reader), Micro USB cable and 4GB SD card.

I picked Raspbian as an OS. There are images available for download on the official site. I used Raspbian Jessie Lite, because the full version wouldn’t fit on my 4GB SD card. My card was formatted already, but I decided to start from scratch. First, we have to find the name of the block device assigned to our SD card. The name of the device will look like this: /dev/disk2. On macOS the diskutil command will help us to manage block devices.

# list disks and look up the SD card name
diskutil list

After we discovered the name of the card we can start working with it. First, we have to unmount the SD card mount point (in macOS it is automatically mounted when the card is inserted in the card reader) otherwise the next steps might fail.

# replace diskX with your SD card disk name
diskutil unmountDisk /dev/diskX

After the disc is unmounted we can start modifying its contents. If your disc is already formatted, you might want to start from scratch, though this is not required. To accomplish this we’ll need to use dd command. We are going to use this command, to fill the first 512 bytes with zeros. First 512 bytes is by convention a size of a single sector on the hard drive, which is reserved for the Master Boot Record (MBR). MBR holds a table, called partition table, which contains information about each partition. By removing MBR, the device appears to OS as a fresh and empty device ready to be filled with data. When working with device files in macOS, you might want to prefix your device file name with “r” like this /dev/rdisk2. “r” prefix tells OS to use a corresponding raw device file which means that the OS will try to apply changes to data immediately bypassing any caches or buffers.

sudo dd if=/dev/zero of=/dev/rdiskX bs=512 count=1 conv=notrunc

Enabling Wi-Fi

You might want to enable a Wi-Fi network on your Raspberry Pi. This will allow Raspberry to connect to your Wi-Fi spot upon boot. This in turn will allow us to work with Raspberry over the network, by connecting to it via SSH. An alternative way would be to connect the device directly to a router with Ethernet cable, but I didn’t have one, so I went with the Wi-Fi approach. Initially, the Wi-Fi functionality in Raspbian image is disabled, so we have to enable it first. To do that we have to modify the Wi-Fi settings file inside the image. We’ll need to mount this image as a device file, but we won’t be able to do that on macOS, because the image filesystem is ext4 (a filesystem used by Linux) and this filesystem is not supported on macOS (well, there might be drivers but from the brief look they are not free). A possible workaround is to mount the image inside a Linux virtual machine and apply the changes. I used Vagrant to spin up the Ubuntu box quickly. Create a Vagrantfile with the following contents:

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/trusty64"
  config.vm.synced_folder ".", "/home/vagrant/pi"
end

Spin up the box:

vagrant up

This Vagrantfile creates an Ubuntu box and shares current directory with the box. This shared directory allows us to use its contents inside the VM. First, we have to copy the image to this folder, then we login to the box via SSH.

# copy image to current folder
cp /path/to/raspbian.img ./

# ssh into the box
vagrant ssh

Once we are inside the box, we can find the contents of the shared folder in the /home/vagrant/pi folder. The last thing we have to do before mounting the image is to find the address of the Linux partition (Raspbian image consists of two partitions: boot partition and linux partition). We can use fdisk command to accomplish that:

sudo fdisk -l raspbian.img 

This will print a table like this:

Disk raspbian.img: 1390 MB, 1390411776 bytes
255 heads, 63 sectors/track, 169 cylinders, total 2715648 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x244b8248

       Device Boot      Start         End      Blocks   Id  System
raspbian.img1            8192      137215       64512    c  W95 FAT32 (LBA)
raspbian.img2          137216     2715647     1289216   83  Linux

We’re interested in the value of the 2nd row and the Start column, which is an offset sector value of the Linux partition: 137216. In order to get a byte offset we have to multiply this value by a sector size (512 in our case): 137216 * 512 = 70254592. Next, we’ll use this number to mount the image:

sudo mount -o rw,loop,offset=70254592 /path/to/raspbian.img /path/to/mount

This command mounts a Raspbian image on the /path/to/mount path (you should replace this path with your own one). We tell the OS to mount this image on a loop device /dev/loop0 (which is not a real block device, like a hard drive, but an emulated one) and to mount this image as a read-write filesystem (because we want to make changes to the image). Once the image is mounted we can go ahead and modify the Wi-Fi configuration files.

# navigate to our mount point
cd /path/to/mount

# edit config file
sudo vim /etc/wpa_supplicant/wpa_supplicant.conf

Add the following lines to the end of the file replacing the placeholders with your own values:

network={
    ssid="wifi-spot-name"
    psk="wifi-spot-password"
}

Save the file and unmount the filesystem:

sudo umount /path/to/mount

Installing and configuring the OS

Once the image is prepared, we can transfer it to the SD card:

sudo dd bs=1m if=/path/to/raspbian.img of=/dev/rdiskX

After the transfer is finished, you might want to enable SSH on the machine. You can do it by creating an empty file called ssh on a boot partition. On my Mac, the boot partition is available via Finder, so I just created the file via GUI in the SD card folder.

Then, you should eject the card to avoid any data corruption:

diskutil eject /dev/diskX

Finally, insert the card into Raspberry Pi, power it and wait for a minute till it connects to the network. You can find a list of currently connected clients in the network by running the following command:

ifconfig | grep broadcast | arp -a

If everything was successful, you should see a new IP in your network clients list. Use this IP address to connect to SSH, pass pi as a username and raspberry as a password:

# replace with IP address discovered in arp -a command
ssh pi@192.168.0.102

If everything went well, you should be inside the Raspberry Pi box. You might want to configure the device even further by running:

sudo raspi-config

Finally, you might also want to harden the security of your Raspberry, I’ve written an article on that topic.