Raspberry Pi: Headless installation

From Fixme.ch
Jump to: navigation, search

While it is not uncommon to have a headless Raspberry Pi (RPi) server, the installation process is usually done by connecting a monitor and a keyboard to the RPi to do the initial installation and configuration, e.g. using NOOBS or by directly transferring the official Raspbian image on the SD card.

If you don't have an additional monitor and keyboard for your RPi, e.g. you only have a laptop at hands, by installing directly Raspbian and after you have hooked up your RPi to the network you can SSH into it to finalize the installation. But this assumes that you know the IP address of your RPi in order to SSH into it. If you don't, e.g. the IP address is assigned by a DHCP server that you do not control, you can still have some ways to get it, but this can be challenging to novice users.

This article proposes a simple solution to allow the user to SSH into its RPi without having to go above and beyond to get its IP address once hooked to the network. It is assumed that you can modify the content of the SD card once the Raspbian image has been transfered to it, so it won't work natively on Windows.

Among others, the following solutions seem interesting to easily SSH into the RPi:

  • Configure the RPi to advertise its hostname with Zeroconf. The hostname can be modified from its default to prevent ambiguities.
  • Configure the RPi to advertise itself on a DynDNS service.
  • Configure the RPi to send an email to a predetermined address once its network interface is up.

However, none of them are actionable out of the box, and they require some packages to be installed on the RPi in order to work. You can however push your Pi's IP to your computer/phone on boot, or note down your Pi's MAC and then scan with nmap/Fing to find it, or even scan the subnet without your Pi connected, and then again with your Pi connected (then look at the difference between the two scans to see where your Pi is).

Existing solutions

NOOBS has some facilities to make unattended installations and Pi-Kitchen can be used to customize it further (e.g. by installing package, configuring and launching services after the first boot).

Raspbian-ua-netinstall can be used to create self-downloading unattended installations, and seems very flexible.

All those solutions are however too complex for a simple installation, and do not allow to easily understand what is happening under the hood. The aim of this article is to only install a standard Raspbian distribution and configure it such that it can be SSH'd into without hassle to complete the installation.

The raspi-config tool (available out of the box) is usually used to do part of this initial configuration, but it must be used interactively so it is not fit for our purpose. Another similar tool, raspi-autoconfig is a non-interactive pendant of the former, and might be useful for our purpose.

Prerequisites

  • An SD card that meets the capacity requirements for Raspbian
  • A running computer with an SD card reader (for this guide, it is assumed that it runs a linux distribution)

And as the target for the installed OS, although not absolutely required to follow this guide:

  • A powered RPi
  • Network access with a DHCP-provided IP address

Installation

All the following steps are done from your running computer, not from your RPi.

Download the latest Raspbian image and follow the official installation procedure.

TL;DR: dd bs=4M if=/path/to/raspbian-image of=/dev/sdX; sync

That's it! Also, an SSH server should be up and running on your RPi once powered-up with the default Raspbian installation.

Although optional, it could be nice to already prevent anyone except you to access the RPi through SSH. In order to do this, even before putting the SD card into the RPi, you can already configure sshd to authorize only access using SSH keys.

Assuming you already have an SSH key pair on your running computer, you just have to authorize your key ($SD is the root directory of your SD card):

mkdir $SD/home/pi/.ssh
cat ~/.ssh/id_rsa.pub >> $SD/home/pi/.ssh/authorized_keys

(note that the default raspbian user is pi)

Then configure sshd to prevent password login by editing $SD/etc/ssh/sshd_config with the following options:

ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no

Now, something must be done to address the IP address discovery problem.

Bootstrapping packages

Installing additional packages beyond the basic Raspbian installation is not straightforward when you want to do it on your running computer: you cannot just chroot into the SD card and execute apt-get to pull additional packages, because your running computer probably runs on an x86/x86-64 architecture and your RPi uses ARM (and chroot works only when the architectures are the same).

To solve this problem, we will let Raspbian bootstrap the additional packages directly from the RPi once the network is available. It should also be possible to download the packages' and their dependencies' archives and install them manually from your running computer or let apt install them from the file system instead of downloading them, but this won't be covered here.

By placing a script in $SD/etc/networks/if-up.d/, it will be executed every time a network interface becomes available, and this will be used to wait for Internet access before downloading additional packages. The following script contains boilerplate code to ensure that Internet access is actually available (e.g. this is not the case with the loopback interface) and prevent the script from being executed several times (e.g. if there are several interfaces with Internet connectivity, such as Ethernet and WiFi) and finally ensure that the script is executed only once, typically the first time the RPi is booted.

#!/bin/sh

# Ensures that the script is run only when "useful" network interfaces become
# available, e.g. the loopback interface provides no Internet connectivity.
case "$IFACE" in
    lo)
        exit 0
        ;;
    *)
        ;;
esac

# Ensures that the script is run only once, e.g. when several network
# interfaces are available
FLAGFILE=/var/run/raspi-bootstrap.flag
if [ -e $FLAGFILE ]; then
    exit 0
else
    touch $FLAGFILE
fi

###############################################################################
### Your code goes here, everything before and after is boilerplate ###########
###############################################################################

# The file containing this script is removed from the file system, so it won't
# be executed again
rm "$0"

Using Zeroconf

Assuming that you have a Zeroconf client (e.g. Avahi, Bonjour) on the machine you will use to SSH into your RPi, it would be nice to be able to use it to automatically resolve the IP address of your RPi. If both your computer and the RPi are on the same LAN (Zeroconf does not work across LANs), it would allow to use the hostname of your RPi instead of its IP address.

The problem is that there is no Zeroconf client in the default Raspbian installation, so it will have to be bootstrapped using the script above. Simply replace the "your code goes here" line by the following:

apt-get -q update
apt-get -qy install avahi-daemon
insserv avahi-daemon

You should be able to replace insserv avahi-daemon by update-rc.d avahi-daemon defaults, which is actually the recommended way to manage boot scripts.

You can optionally change the hostname of your RPi in order to prevent ambiguities, as it defaults to raspberrypi on all fresh Raspbian installations. To achieve this, change the hostname in $SD/etc/hostname and in $SD/etc/hosts at the 127.0.1.1 line (which is exactly what raspi-config does when you ask it to change the hostname).

Once done, you can finally place the SD card into your RPi, connect it to your LAN and power it up. After a few minutes (it can take some time, go get a coffee) you should be able to ssh into your RPi using ssh pi@<hostname> (or pi@<hostname>.local depending on the configuration of your machine, if none works check the installation and configuration procedure of the Avahi client for your distribution).

Finally you can execute sudo raspi-config in your SSH shell to configure your RPi as usual.

Using DynDNS

When you are not on the same LAN as your RPi, you can use a DynDNS service to resolve the IP address of your RPi.

Basically, you have to install a DynDNS client on your RPi using the same technique as above and configure it according to the requirement of the DynDNS service you use.

As an example, using OVH's DynDNS service you can install ddclient on your RPi by replacing the "your code here" line of the script above with:

apt-get -q update
apt-get -qy install ddclient

and configuring the client by editing $SD/etc/ddclient.conf with:

protocol=dyndns2
use=if, if=eth0
server=www.ovh.com
login=raspberrypi
password='p455w0rd'

# Updates interval (in seconds)
daemon=300

# Logging & temp files
syslog=yes
pid=/var/run/ddclient.pid
cache=/tmp/ddclient.cache

# Domain name
raspberrypi.fixme.ch

Note: if you have not guessed it already, you have to adapt the values for login, password and the domain name to match your case, and the values above are fictional.

Sending a mail

The poor man's version of IP address discovery: make the RPi send an email that containing its IP address to a predefined email address. Yours.

Raspbian does not have an SMTP server installed by default, so again you can use the script above to install sendmail. You might have to configure the SMTP server before sendmail can be used in your script (which you can do by directly editing configuration files on the SD card before placing it in the RPi; I won't explain how to do it here because I'm too lazy).

For this solution to be a bit more comfortable, you might want to adapt the script such that it sends the email at regular intervals, and disable it manually once you have SSH'ed into your RPi.