/raspberry-pi-turnkey

How to make a Raspberry Pi image that can be deployed anywhere and assigned to a WiFi network without SSH :ok_hand:

Primary LanguagePythonMIT LicenseMIT

Raspberry Pi Turnkey

Have you ever wanted to setup a Raspberry Pi without having to SSH or attach a keyboard to add your WiFi credentials? This is particularly useful when you are making a Raspberry Pi that needs to be deployed somewhere where supplying the credentials via SSH or attaching a keyboard isn't an option. Or it could be useful if you take your Pi to a friend's house and they don't have ethernet cables or extra keyboards+monitors to put your friend's WiFi credentials onto the Pi. With this image base you don't ever need to modify a wpa_supplicant with SSH/terminal/PiBakery again!

You can follow the instructions below to create a turnkey image, or you can just download my latest one at raspberry-pi-turnkey.schollz.com/2018-06-25-turnkey-1.3.zip (v1.3.0, 982MB) and follow the typical flashing instructions.

Support

Usage

Once you boot the Pi with this image, wait about 10 minutes for the Pi to reformat the drive and start up the web server. Then you will see a WiFi AP named "ConnectToConnect" (password same). Connect to it and your browser should automatically redirect you to a sign-in page. If not, navigate to 192.168.4.1 where you'll see a login form.

When the WiFi credentials are entered onto the login form, the Pi will modify its internal wpa_supplicant to conform to them so that it will be connected to the net. The Pi will then reboot itself using those WiFi credentials. If the credentials are not correct, then the Pi will reboot back into the AP mode to allow you to re-enter them again.

Once connected, you can recieve a message with the LAN IP for your Pi at https://snaptext.live (the specific URL will be given to you when you enter in the credentials to the form).

Note: The Raspberry Pi is not a fast computer. When you see the AP and connect to it, it may take up to a minute for the page at 192.168.4.1 to appear. Also, if you enter the wrong WiFi credentials, it will have to reboot twice to reset the Pi to allow you to enter the credentials again. So try to enter them right the first time!

How does it work?

When the Pi starts up it runs a Python script, startup.py. This script first checks if the Pi is online (by looking for an SSID in iwconfig wlan0). If the Pi is online, the script sets the status as "connected" (saved to disk in status.json).

If the Pi is not online, it will check the status. The initial status is "disconnected". When "disconnected" the Pi will uncomment the configuration files for hostapd and dnsmasq. The access point configuration is nearly identical to as outlined in this tutorial. Then the Pi sets the status as "hostapd" and reboots itself.

When the status is "hostapd" then the script will bind to port 80 and serve a web form at 192.168.4.1. Once you connect to the AP this web form will be available and it will recieve input. Once the server recieves input, it sets the credentials in wpa_supplicant.conf and comments out the configuration file for hostapd and dnsmasq so that the AP doesn't interfere, and then reboots. When it reboots it will see if it gets online and set the status as "connected" or "disconnected". Then it repeats the steps above (i.e. doing nothing if connected, or restarting the AP if disconnected).

Instructions to create image

The following are the step-by-step instructions for how I create the turnkey image. If you don't want to download the image I created above (I don't blame you), then follow these to make one exactly the same.

These instructions assume you are using Ubuntu. You can use Windows/OS X for most of these steps, except step #4 which requires resizing.

1. Flash Raspbian Stretch Lite

Starting from version Raspbian Stretch Lite version 2017-11-29.

$ sudo dd bs=4M if=2017-11-29-raspbian-stretch-lite.img of=/dev/mmcblk0 conv=fsync status=progress

Change /dev/mmcblk0 to whatever your SD card is (find it using fdisk -l).

After flashing, for the first time use, just plug in ethernet and you can SSH into the Pi. To activate SSH on boot just do

$ touch /media/YOURUSER/boot/ssh

2. Install libraries onto the Raspberry Pi

SSH into your Pi using Ethernet, as you will have to disable the WiFi connection when you install hostapd.

Basic libraries

$ sudo apt-get update
$ sudo apt-get dist-upgrade -y
$ sudo apt-get install -y dnsmasq hostapd vim python3-flask python3-requests git

Install node (optional)

$ wget https://nodejs.org/dist/v8.9.4/node-v8.9.4-linux-armv6l.tar.xz
$ sudo mkdir /usr/lib/nodejs
$ sudo tar -xJvf node-v8.9.4-linux-armv6l.tar.xz -C /usr/lib/nodejs 
$ rm -rf node-v8.9.4-linux-armv6l.tar.xz
$ sudo mv /usr/lib/nodejs/node-v8.9.4-linux-armv6l /usr/lib/nodejs/node-v8.9.4
$ echo 'export NODEJS_HOME=/usr/lib/nodejs/node-v8.9.4' >> ~/.profile
$ echo 'export PATH=$NODEJS_HOME/bin:$PATH' >> ~/.profile
$ source ~/.profile

Install Go (optional)

$ wget https://dl.google.com/go/go1.10.linux-armv6l.tar.gz
$ sudo tar -C /usr/local -xzf go*gz
$ rm go*gz
$ echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' >>  ~/.profile
$ echo 'export GOPATH=$HOME/go' >>  ~/.profile
$ source ~/.profile

Install turnkey

$ git clone https://github.com/schollz/raspberry-pi-turnkey.git

Install Hostapd

$ sudo systemctl stop dnsmasq && sudo systemctl stop hostapd

$ echo 'interface wlan0
static ip_address=192.168.4.1/24' | sudo tee --append /etc/dhcpcd.conf

$ sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig  
$ sudo systemctl daemon-reload
$ sudo systemctl restart dhcpcd

$ echo 'interface=wlan0
dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,24h' | sudo tee --append /etc/dnsmasq.conf

$ echo 'interface=wlan0
driver=nl80211
ssid=ConnectToConnect
hw_mode=g
channel=7
wmm_enabled=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=ConnectToConnect
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP' | sudo tee --append /etc/hostapd/hostapd.conf

$ echo 'DAEMON_CONF="/etc/hostapd/hostapd.conf"' | sudo tee --append /etc/default/hostapd

$ sudo systemctl start hostapd && sudo systemctl start dnsmasq

Add pi to sudoers

Add pi to the sudoers, so that you can run sudo commands without having to be root (so that all the paths to your programs are unchanged).

$ sudo visudo

Then add this line:

pi      ALL=(ALL:ALL) ALL

(Sidenote: I save an image intermediate.img at this point so its easy to go back)

Startup server on boot

Open up the rc.local

$ sudo nano /etc/rc.local

And add the following line before exit 0:

su pi -c '/usr/bin/sudo /usr/bin/python3 /home/pi/raspberry-pi-turnkey/startup.py &'

Shutdown the pi

Shutdown the Raspberry Pi and do not start it up until after you write the image. Otherwise the unique ID that is generated will be the same for all the images.

$ sudo shutdown now

3. Resize Raspberry Pi SD image

If you don't want to resize the image, you can just write the entire image file to your computer and use that from here on. If you do want to resize (especially useful if you are installing on a 16GB card and want to flash onto a smaller card), follow these instructions.

Put the newly made image into Ubuntu and do

$ xhost +local:
$ sudo gparted-pkexec

Right click on the SD card image and do "Unmount". Then right click on the image and do "Resize/Move" and change the size to 2400.

Then you can copy the image to your computer using the following command

$ sudo dd if=/dev/mmcblk0 of=/some/place/turnkey.img bs=1M count=2400 status=progress

Again /dev/mmcblk0 is your SD card which you can determine using fdisk -l. The location of the image, /some/place/, should be set by you.

4. Test the turnkey image

The new image will be in /some/place/2018-turnkey.img which you can use to flash other SD cards. To test it out, get a new SD card and do:

$ sudo dd bs=4M if=/some/place/turnkey.img of=/dev/mmcblk0 conv=fsync status=progress

Roadmap

  • Add messaging system to send the LAN IP address once online (uses https://github.com/schollz/snaptext)
  • Add startup hooks (just edit startup.sh)
  • connect immediately to wifi and disable hostapd without rebooting

If you'd like to contribute, please do send a PR!

Thanks

Thanks to @ilirb for checking if passphrase is correct before rebooting!

License

MIT