profit_image – stock.adobe.com
VNC (Virtual Network Computing) is an easy-to-use method for having complete access to a graphical user interface (GUI) on any machine you can connect to. It’s flexible in terms of bandwidth, latency, and security. When you use VNC, it doesn’t matter if the machine is on your local network or another continent.
You can connect to your Pi from Windows, macOS, and Linux with equal ease and security. This is a one-size-fits-all setup for shared, remote computing. However, don’t run a big server when a micro server will suffice. Raspberry Pi computers are super-green, and you can help resist climate change!
No previous networking knowledge is required, but you should have a Pi ready. Anything from Raspberry Pi 2 B+ and up is fine; version 1 is just too slow for responsive VNC sessions.
Please refer to this for basic setup, and this for how to configure your Raspberry Pi to use a static IP.
A static IP is required only if you wish to connect to your home or lab while you’re out, and will ensure that the Pi doesn’t get another IP from DHCP, which would mess up the port forwarding.
The Raspberry Pi Linux images available here all provide you with an option for a RealVNC server. You should select the “Raspbian Buster with desktop” variant, and flash it to a microSD card, either with “dd” or your Pi, via a USB to microSD adapter:
1 2 3 |
sudo unzip -px raspbian_latest | dd bs=1M of=/dev/sdX |
where “X” is the relevant disk, e.g. /dev/sda if you’re using a Raspberry Pi with a USB to microSD adapter to flash. Be careful with this, as you don’t want to target the wrong disk. Use “lsblk” on your Pi/Linux system to discover which disk you want to write to.
For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
pi@raspberry$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 1 30.2G 0 disk /media/pi/SANDISK_32GB mmcblk0 179:0 0 29.8G 0 disk ├─mmcblk0p1 179:1 0 256M 0 part /boot └─mmcblk0p2 179:2 0 29.6G 0 part / pi@raspberry$ sudo umount /media/pi/SANDISK_32GB pi@raspberry$ sudo unzip -px raspbian_latest | dd bs=1M of=/dev/sda &;&; \ sync &;&; \ echo If Raspbian has automounted your disk (again), see it with 'ls_blk' &;&; \ echo and then unmount it ... again. |
An easier option is to use Etcher, which even handles unzipping the downloaded file for you. Follow this link for instructions.
Once you’ve flashed your microSD card, you’re ready to boot your Pi. First, decide if you wish to run with a display, or headless.
One example of a headless application is if your Pi is inside a _ROBOT_, and you really would like to use a GUI editor to adjust your code while the system is live. If there’s no display attached, use “sudo raspi-config”
-> ‘3 Boot Options’
-> ‘B1 Desktop / CLI’
-> ‘B1 Console’ to disable the Xserver. You’ll save RAM and CPU resources doing this.
Connecting to a Raspberry Pi on your LAN
If you want to use your Pi with a display, connect an HDMI cable and USB keyboard and mouse.
Then, enter the command “sudo raspi-config” into your Pi’s terminal, and:
And …
And …
Hit “OK” and if asked to reboot, then exit raspi-config.
Now, enable the RealVNC server, again punch in the command “sudo raspi-config” in your Pi’s terminal:
And …
And …
Press “Yes” and exit raspi-config again. You’ll be prompted to reboot if system changes require it. Say yes to a reboot if prompted.
Once you’ve rebooted, you can connect with the username “pi” and your password. We’ll cover client software installation in a moment.
If you wish to run headless, add these lines to your “/etc/rc.local” file, above the line that says “exit 0.” If not, skip past this section.
1 2 3 4 5 6 7 |
# HEADLESS if /usr/bin/pgrep -U pi vncserver >/dev/null ; then /bin/sh -c '/usr/bin/sudo -u pi /usr/bin/vncserver -kill :1 >/dev/null 2>&;1 || :' fi /bin/sh -c '/usr/bin/sudo -u pi /usr/bin/vncserver -depth 24 -geometry 1280x1024 :0 >/dev/null 2>&;1' |
Now, you can log in to your Pi with a VNC client. The best I’ve found is the one already bundled or installed by Raspbian: RealVNC Viewer.
It supplies clients (precompiled as binary packages) for macOS, Windows, and Linux, and many other systems, including Android and iPhone iOS. You can download your client here. There are no quirks on macOS or Windows; just double-click the downloaded software. On Ubuntu or a similar Debian-based distribution, download “DEB x64” for a modern machine, and use the terminal:
1 |
sudo dpkg -i VNC-Viewer-6.19.325-Linux-x64.deb |
For other Linux systems, use RPM or standalone BIN, or generic script as appropriate. After the installation, simply type “vncviewer” and hit RETURN. You’ll be presented with a sophisticated GUI interface. At the top, you enter the address of your Pi, which you can discover by entering “hostname -I” into your Pi’s terminal. Another option is the free Fing app for iPhone iOS or Android.
The address is in the form IP:PORTl; for example, on this network, it’s 10.0.9.116:5900 for the “:0” instance on my Pi. A “:1” instance would use the port 5901 instead, so I’d enter 10.0.9.116:5901.
After you’ve entered the address, press ENTER, and wait a second. You’ll be prompted to authenticate and can set VNC Viewer to remember the login details. That’s it; you’ll be dropped directly into your Pi’s desktop environment.
Connecting to your Pi over the internet is a bit more convoluted. You’ll need to set up port forwarding on your router, and you’ll also need to set your Pi to use a static IP address. Use the link in the Installation and Setup section to set a static IP; or, if your router provides this option, select the Pi in the list of network clients, and set a DHCP reservation. It’ll make sure the Pi always has the same IP address.
Next, port forward the external port 20202/tcp to your Pi’s port 22/tcp. No need to expose the VNC server; we’ll make sure your connection to your Pi is as secure as possible. RealVNC only offers 256-bit AES for enterprise users, but we don’t need to buy in just yet. SSH is awesome.
Copy the commands below into a terminal on your Pi:
1 2 3 4 5 6 7 8 9 10 11 12 |
sudo service ssh start sudo systemctl enable ssh sudo apt-get update sudo apt-get -y install ufw sudo ufw enable sudo ufw default deny sudo ufw logging low sudo ufw allow log 5900/tcp sudo ufw allow log 5901/tcp sudo ufw allow log 22/tcp |
Be sure to change your default password with “sudo raspi-config” or “passwd pi.” It really must NOT be “raspberry” if you’re opening SSH up to the world.
To be clear, ensure that you port forward FROM 20202 _TCP_ to your Pi’s _STATIC_ IP address, port 22 _TCP_.
Now you’re set and can connect to your Pi from work, or anywhere else you happen to be. How? What is the external address of the network your Pi is on?
Dynamic DNS makes that irrelevant by letting you use a “normal” name to connect. “Example.com” is an example of a “normal” name, and you don’t need to remember an IP address to connect to it. The IP address “93.184.216.34” might be trouble, since you’ve already got plenty of things to remember.
However, you could remember something such as “risingsun.csproject.org” easily. Let’s install a dynamic DNS client on your Pi, which will ensure that name always points to your Pi’s external network address.
Paste these commands into your Pi’s terminal:
1 2 3 4 |
apt-get update apt-get -y install inadyn |
You’ll need to choose a Dynamic DNS provider. If you want one that’s free, use FreeDNS. Sign up, and edit “/etc/inadyn.conf:” with the command sudo nano /etc/inadyn.conf
. The relevant parameters are listed here for your convenience:
1 2 3 4 5 6 7 8 9 10 |
period = 300 # The FreeDNS username must be in lower case and # the password (max 16 chars) is case sensitive provider freedns.afraid.org { username = lower-case-username password = case-sensitive-pwd hostname = some.example.com } |
Once you’ve got all that info right, paste these commands into your Pi’s terminal:
1 2 3 4 5 6 |
# Start it now sudo service inadyn start # Persist across reboots sudo systemctl enable inadyn |
To connect to your Pi, now do the following on your workstation or laptop (this applies to macOS and Linux; SSH tunneling on Windows is outside the scope of this article):
1 2 3 4 |
ssh -l pi -p 20202 -L 5900:localhost:5900 \ risingsun.csproject.org |
This creates an SSH tunnel for your VNC traffic. The SSH overhead isn’t a real CPU problem for models such as the Raspberry 2 B+ and later, so don’t worry.
To connect through the tunnel, enter the address “127.0.0.1:5900” into VNC Viewer, and connect via your local SSH tunnel to the VNC service on your Pi.
Enter your credentials if necessary, and you’re back in your Pi’s desktop environment. Never again will you need to worry if using shared Wi-Fi in a coffee shop or an airport.
You can of course also just SSH to your Pi, and start the VNC service ad-hoc, with the command:
1 2 3 |
nohup vncserver :0 |
This will persist until you kill it, with for example “pkill -9 -U pi vncserver.”
You can do a few things to boost VNC performance. One way is to reduce graphics to 16 bits or less, for a moderately comfortable user experience.
Latency is the real killer, and if you connect your Pi to your local network using Ethernet, this will help a lot.
If your connection isn’t fast enough (or if other users are using it at maximum capacity), you can discover this by installing speedtest-cli. Paste this into your terminal:
1 2 3 4 5 |
sudo apt update sudo apt-get -y install speedtest-cli speedtest-cli --bytes --simple |
This outputs the following on my Pi:
1 2 3 4 5 |
Ping: 2.723 ms Download: 9.96 Mbyte/s Upload: 0.50 Mbyte/s |
The upload speed of 0.5Mbyte/s equals about 4Mbit/s, and is just enough for VNC at 24 bits, with a resolution of 1280×1024, barely.
On the GUI side of things, you should get rid of the default interface. It works fine for the old 512MB RAM Raspberry Pi’s, but not so much if you want a normal, intuitive interface.
The vanilla Raspberry Pi desktop consists largely of packages from the meta-packages “raspberrypi-ui-mods” and “lxde-common.” As a bonus, it tends to throw LXPolkit errors to VNC users.
If you have a 16-32GB microSD card and a Raspberry Pi 2 B+ (or later), I highly recommend installing the MATE desktop environment.
MATE will improve your overall user experience greatly!
Paste these commands into your Pi’s terminal:
1 2 3 4 5 6 |
sudo apt-get update sudo apt-get -y remove raspberrypi-uid-mods lxde\* sudo apt-get -y install mate-desktop-environment \ mate-themes mate-utils mate-tweak mate-terminal |
If you installed MATE, you should now paste these lines into your ~/.vnc/xstartup file:
1 2 3 4 5 6 7 8 |
#! /bin/sh if [ -r ${HOME}/.Xresources ] ; then xrdb ${HOME}/.Xresources fi xsetroot -solid grey -cursor_name left_ptr &; mate-session |
Then, reboot. This is particularly cool if you’ve got the new Raspberry Pi 4 B, with up to 4GB of RAM. You’ll never need to swap to your microSD card. Even on my Raspberry Pi 2 B+, MATE rarely causes me to swap. It’s just that good.
Add a Reactive Cooling System to your Pi
Cut a big round hole over the CPU
With Raspberry Pi 2 B+ and later models, heat becomes a problem. You can see your system temperature at any time with the command “vcgencmd measure_temp,” and if it reaches a certain threshold, 80C/176F, your Pi will clock itself down to avoid “undefined behavior” caused by overheating.
Thus, your 1.2GHz CPU may run at 600MHz for a while, and not go back to full speed until the heat has dissipated. The tiny heatsinks you’ve probably seen don’t really help if you’ve put the Pi in a case with limited airflow, and certainly not if you use four cores with 100 percent load on each. There’s a built-in config.txt parameter called gpio-fan for driving a fan (see “/boot/overlays/README”), but we don’t want to set that up every time we’ve reflashed our microSD card.
Instead, a dielectric temperature switch can be used. By attaching it to the CPU heatsink with electrically isolating, thermally conductive tape, it’ll close the circuit from the 5V rail to a 5V fan. I used a normally open type, which will close the circuit at 113 degrees Fahrenheit. Once it closes, the fan drives the heat away from the CPU. 0.75W makes for a decent mini-fan and is quite safe if we use a catch diode (ROHM BAT86 schottky) to prevent any spikes from reaching our 5V rail.
You’ll need these parts:
1x KSD9700 temperature switch, normal-open, 45C/113F | https://www.aliexpress.com/item/10pcs-2500W-Temperature-control-switch-KSD9700-45-Degrees-Celsius-Normally-open-N-O-10A-250V-Thermal/32790498666.html |
1x BAT86 schottky diode | https://www.newark.com/nexperia/bat86/rectifier-diode-single-50-v-200/dp/96K6771 |
1x 5V fan | https://www.banggood.com/5v-303010mm-3010-Cooling-Fan-with-2-Pin-Dupont-Wire-for-3D-Printer-Part-p-1421461.html?rmmds=buy&;cur_wbarehouse=CN |
Thin stranded wire | https://www.daburn.com/2671UltraFlexibleSub-MiniatureWire-U/LSTYLE15681692.aspx |
1x 40V/2200uF capacitor, electrolytic | https://www.newark.com/illinois-capacitor/228tta050m/aluminum-electrolytic-capacitor/dp/30K6693 |
Thermal adhesive tape | https://www.adafruit.com/product/1468 |
2x Raspberry Pi heatsinks | https://www.adafruit.com/product/3082 |
Make It!
Practically speaking, simply run a wire from a 5V GPIO pin (or void your warranty by soldering a line from the large “D5” diode near the microUSB port, see the red markings on the picture below) to one wire on the dielectric switch, and from its other wire to the fan’s positive terminal.
Connect a BAT86 schottky catch diode in forward bias from the fan’s negative terminal to its positive terminal, and then complete your circuit by connecting the fan’s negative terminal to GND. You can be creative with what constitutes ground; there’s GND _everywhere_. The Pi is quite sophisticated and can handle a tiny ground loop.
Or, be correct about this, and just connect it to a GPIO GND pin. The only tricky bit is to ensure the thermal adhesive tape is indeed very thermally conductive; use isopropyl alcohol to wipe the heatsink and switch beforehand. Once it is in place, make sure it stays in place with a big blob of hot glue.
Hot glue keeps it all in place
The KSD9700 is buried under hot glue and Kapton tape, to the right of the CPU in the image above. In operation, the 45C/113F switch will close when “vcgencmd measure_temp” returns 53C/127.4F, and continue to drive the fan until “vcgencmd measure_temp” returns 38C/100.4F, always. Even under 100 percent load of all four CPU cores, only the duration changes. This is because the switch itself must sink enough heat to reach 133F, and the CPU sensor reading is a bit ahead of that.
This type of switch will last for a decade and is a robust solution, independent of the “gpio-fan” parameter in config.txt. It’s also easy to make. Get your hot glue gun ready!
BOM
4x ROHM SLR343BC4TT32 3mm blue LEDs | https://www.avnet.com/shop/us/products/rohm/slr343bc4tt32-3074457345627700657?CMP=EMA_ECIA_inventoryfeed_VSE?aka_re=1 |
1x 2N7000 N-channel MOSFET | https://www.oddwires.com/2n7000-2n7000ta-small-signal-mosfet-10-pack/ |
4x 330 ohm resistors | https://www.sparkfun.com/products/14490 |
Thin stranded wire | https://www.daburn.com/2671UltraFlexibleSub-MiniatureWire-U/LSTYLE15681692.aspx |
1x 4.7kOhm resistor | https://www.adafruit.com/product/2783 |
Make It!
A small Pi implant board, ready to become a true blue HEARTBEAT. The omnidirectionality of the LEDs will be enhanced with hot glue and some sheets of film from a decompiled laptop LCD.
Closed up and good to boot! The anodized aluminum mesh prevents damage to the fan, at the cost of ~40 percent less airflow.
Now, why is there a big 2200uF capacitor on this Pi? Yes, it’s connected directly to the 5V/GND GPIO pins.
The capacitor is there for the same reason these are present in subwoofers. Even if you have everything in order, using the official Raspberry Pi 5.25V SMPS power supply, and low-resistance wires, you can have problems if you suddenly surge in your current consumption. E.g. if your current needs to go from 1A to 2A quickly.
For me, this happens most commonly if I write to a USB harddisk, and do a lot of CPU work and network work at the same time. I get the dreaded under-voltage warning. It happens if you have ~4.65V or less on the 5V pin, and is extremely annoying.
So, what if an SMPS power supply cannot rise to the occasional spike and deliver? You add a reservoir capacitor. The bigger the better, but the rule of thumb is 1000uF per A running to the system that needs a wee boost, hence 2200uF. The Raspberry Pi 4 B is rated for 3A, so you’ll want something like a 3300uF capacitor for this. You can go higher if you like. A supercap would surely improve things. It’s a plus they can also be used to spot-weld.
You can use this simple Python 3 script with your heartbeat circuit.
[ begin heartbeat.py ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#! /usr/bin/env python3 import RPi.GPIO as GPIO from time import sleep GPIO.setmode( GPIO.BCM ) # # Count 12 from the 3V3,5V pins at the top of the # GPIO header _led = 18 # BCM18/BOARD12/PWM0 pin GPIO.setup( _led , GPIO.OUT ) pwm = GPIO.PWM( _led, 100 ) pwm.start( 0 ) p=print _step = 3 def get_load(): _f = open( '/proc/loadavg', 'r' ) _buf = _f.read( 30 ) _f.close() return float ( _buf.split()[0] ) def get_delay(): _load = get_load() _delay_base = 0.2 if _load >= 0 and _load < 0.33: _delay = _delay_base elif _load < 0.66 and _load >= 0.33: _delay = _delay_base / 2 elif _load < 1 and _load >= 0.66: _delay = _delay_base / 3 elif _load < 1.33 and _load >=1: _delay = _delay_base / 4 elif _load < 1.66 and _load >= 1.33: _delay = _delay_base / 5 elif _load < 2 and _load >= 1.66: _delay = _delay_base / 6 elif _load < 2.33 and _load >= 2: _delay = _delay_base / 7 elif _load < 2.66 and _load >= 2.33: _delay = _delay_base / 8 elif _load < 3 and _load >= 2.66: _delay = _delay_base / 9 elif _load < 3.33 and _load >= 3: _delay = _delay_base / 10 elif _load < 3.66 and _load >= 3.33: _delay = _delay_base / 11 elif _load < 4 and _load >= 3.66: _delay = _delay_base / 12 else: _delay = _delay_base / 20 # GO FAST # ET CETERA return _delay if __name__ == '__main__': try: while True: for _it in range( 20, 100, _step ): pwm.ChangeDutyCycle( _it ) sleep( get_delay() ) sleep( 0.25 ) for _it in range( 100, 20, -(_step) ): pwm.ChangeDutyCycle( _it ) sleep( get_delay() ) sleep( 0.25 ) except KeyboardInterrupt: print( "[!] Caught ^C, breaking ..." ) # Stop the PWM now that we're leaving pwm.stop() # Clean up pin states, bring them all low GPIO.cleanup() exit() |
[ end heartbeat.py ]
Place the script ‘heartbeat.py’ in ‘/home/pi’ and ensure it’s started when your Pi boots up,
with the lines:
1 2 3 4 |
/bin/sh -c '/usr/bin/sudo -u pi /usr/bin/python3 \ /home/pi/heartbeat.py >/dev/null 2>&;1' &; |
Again, be sure to place this above the line that says “exit 0.”
Now, you’ll see a steady blue light pulsing when your Pi is unloaded, a faster pulse at moderate loads, and rapid pulsing every time your Pi gets loaded.
However, there’s an even more important reason to invest time in such a simple thing as this.
Here’s an action shot at moderate load:
A soothing blue pulse ensures the Pi operator that everything is indeed going according to plan.
The question “HAS MY PI CRASHED?” never goes out of style, especially if you’re running a headless system. If it has, the heartbeat will freeze and cease to pulse, or just go dark.
To stress your Pi, paste the following into your terminal:
1 2 3 4 5 6 7 8 9 |
dd if=/dev/zero bs=1M of=/dev/zero &; dd if=/dev/zero bs=1M of=/dev/zero &; dd if=/dev/zero bs=1M of=/dev/zero &; dd if=/dev/zero bs=1M of=/dev/zero &; # Let it load, let it load, let it load ... sleep 120 kill $( jobs -p ) |
Do enjoy this clip of my puny Raspberry Pi 2 B+ at heavy load (all cores at 100 percent utilization):
Cooling isn’t easy, but it’s necessary! We reactively displace heat from our Raspberry.