Headless Raspberry Pi and macOS Screen Sharing

A few things have changed in the nearly five years since I took notes on Connecting to a headless Raspberry Pi w. VNC. Now the Mac is running Mojave. I'm using the macOS "Screen Sharing" app instead of Jolly's Fast VNC. And I just installed the current version of Raspbian on a new RPi. How does one connect to a headless RPi in this environment?

Enable SSH

After installing Raspbian on a microSD card, mount the card on (in my case) macOS. CD to the root directory and follow these instructions starting from section 3, "Enable SSH on a headless Raspberry Pi (add file to SD card on another machine)". In short:

$ touch ssh

Then unmount the boot SD card, install it in the RPi, and boot. Assuming a wired ethernet connection and some way (e.g., your router's "Device Table") to discover the RPi's IP address, that's it.

Install x11vnc

According to StackOverflow, TightVNCServer does not work too well with macOS "Screen Sharing". But x11vnc does. To recap the StackOverflow instructions:

$ x11vnc -forever -usepw -display :0 -ultrafilexfer & # Start in background
$ sudo netstat -nlp | grep vnc # Verify VNC is running and listening

Then launch "Screen Sharing" on the Mac and connect to the Pi's IP address.

First-time Setup of Rasbian

Just as a note in passing, it's pretty cool that Raspian on an RPi 3 B+ automatically walks you through securing the pi account password and connecting to your home wifi.

Start x11vnc At Boot

Create the AutoStart File

Again following the instructions from StackOverflow,

$ mkdir ~/.config/autostart
$ vi ~/.config/autostart/x11vnc.desktop

Ensure the x11vnc.desktop file contains the following.

[Desktop Entry]
Encoding=UTF-8
Type=Application
Name=X11VNC
Comment=
Exec=x11vnc -forever -usepw -display :0 -ultrafilexfer -geometry 1024x768
StartupNotify=false
Terminal=false
Hidden=false

Ensure the file permissions are correct:

$ chmod a+r ~/.config/autostart/x11vnc.desktop

Ensure 1080p Display Size

Again following instructions from the StackOverflow thread, edit /boot/config.txt and ensure hdmi_mode=16 for 1080p display resolution:

hdmi_force_hotplug=1
hdmi_group=1
hdmi_mode=16

Install and Configure Netatalk and Avahi

Make the RPi visible to the macOS Finder via Bonjour (or whatever the kids are calling it these days).

$ sudo apt-get install -y netatalk avahi-daemon
$ sudo update-rc.d avahi-daemon defaults
 # (Ignore any warnings about setting locale?)

Ensure /etc/avahi/services/afpd.service has the following content:

<?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>

Ensure /etc/avahi/services/rfb.service has the following content:

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

Restart the service or, what the heck, reboot the Pi.

Verify that the Raspberry Pi appears in the "Network" list of a macOS Finder Window. If it doesn't, uh... I guess you're on your own :)

Running Scripts at Startup

[Added 20181221]

If you want to run a custom script or command at system startup, and you want it to run as a regular user, cron may be your best bet.

For example, suppose you want to run a Python script in a particular virtual environment. First create a shell script that configures the virtual environment, then runs the Python script.

$ vi /path/to/custom_command.sh
# Insert the following into custom_command.sh:
cd $(dirname "$0")

. ${HOME}/.profile # Pick up the definition of workon
workon py3cv4

python /path/to/my/script.py >log.txt 2>&1

(Note: Sourcing your .profile is probably not the right way to pick up the definition of virtualenvwrapper's workon, but it works.)

Then add the script to your crontab, specifying that it should run once at boot:

$ crontab -e
# Enter the following:
@reboot /path/to/custom_command.sh &