To SSH to a Raspberry Pi 5 for headless hardware control, enable the SSH daemon via raspi-config or by placing an empty file named ssh in the boot partition, connect the board to your network, and execute ssh username@<IP_ADDRESS> from your host machine. For reliable embedded automation, do not rely on an active SSH session to keep your hardware running; instead, use SSH to deploy your Python script and register it as a systemd service.

The Verdict: Choosing Your Headless Access Method

When stripping the monitor and keyboard off your workbench, you need a reliable way into the OS. Here is the decision matrix for remote access on the Pi 5, terminating in the optimal setup for embedded hardware projects.

Access Method Best For Failure Mode Verdict
Direct UART Serial Console Boot-level debugging, kernel panics, WiFi misconfiguration Requires USB-to-TTL adapter; no network stack visibility Use only for rescue operations
VNC over WiFi GUI configuration, browser-based testing High bandwidth; drops out if WiFi sleeps or router reboots Avoid for headless hardware nodes
SSH over WiFi Mobile robots, remote sensors where cables are impossible Susceptible to 2.4GHz interference and IP drift Acceptable if static IP is reserved
SSH over Ethernet Stationary relay controllers, home automation hubs Requires physical cable run to switch/router DEFAULT PICK: SSH via Ethernet + systemd

Parts List & Hardware Spec Sheet

This guide targets the Raspberry Pi 5 (8GB variant) running Raspberry Pi OS (Bookworm 64-bit). The Pi 5 requires a 27W USB-C PD power supply to prevent brownouts when driving peripherals via the GPIO header.

Component Exact Variant / Model Approx. Cost Notes
Microcontroller Raspberry Pi 5 (8GB RAM) $80.00 Requires active cooling for sustained loads
Power Supply Official 27W USB-C PD PSU $12.00 Prevents peripheral USB/GPIO current limiting
Actuator Songle SRD-05VDC-SL-C (1-Ch Relay) $4.50 Opto-isolated, active-LOW trigger
Wiring 22 AWG Dupont Jumper Wires (F-F) $6.00 Use silicone-jacketed for high-temp environments
Storage SanDisk Extreme 32GB microSD (A2) $11.00 A2 rating critical for OS responsiveness

GPIO Pin Mapping Table

The Pi 5 uses the RP1 southbridge chip for GPIO, which changes the underlying hardware addressing but maintains backward-compatible BCM numbering in software. Wire the 5V relay module exactly as follows:

Relay Module Pin Pi 5 Physical Pin BCM GPIO Number Function
VCC Pin 2 N/A (5V Power) Powers the relay coil and optocoupler
GND Pin 6 N/A (Ground) Common ground reference
IN Pin 11 GPIO 17 Control signal (Active LOW)
Safety Callout: The relay module switches mains voltage (120V/240V AC). Ensure the relay's screw terminals are fully seated, no stray wire strands are exposed, and the module is mounted in a non-conductive enclosure. Never touch the load-side terminals while the system is energized.

Step-by-Step: Enabling SSH and Deploying the Service

Follow this sequence to get headless access and ensure your hardware script survives a reboot or a dropped SSH session.

  1. Enable SSH Headlessly: Before booting the Pi, insert the flashed microSD card into your PC. Open the bootfs partition and create an empty file named exactly ssh (no file extension). This tells the OS to enable the SSH daemon on first boot.
  2. Configure WiFi (If not using Ethernet): In the same bootfs partition, create custom.toml (for Bookworm) or wpa_supplicant.conf (for older OS versions) with your network credentials. For Ethernet, simply plug in the CAT6 cable.
  3. Boot and Locate IP: Power the Pi 5. Check your router's DHCP client list for a device named raspberrypi, or use a network scanner like nmap or Fing to find its IP address.
  4. Establish the SSH Session: From your host terminal, run ssh pi@192.168.1.XX (replace 'pi' with your actual username if you changed the default during imaging). Accept the ECDSA fingerprint.
  5. Install Dependencies: The Pi 5 requires the lgpio backend for Python GPIO control. Run: sudo apt update && sudo apt install python3-gpiozero python3-lgpio -y.
  6. Create the Systemd Service: Do not run hardware scripts directly in the SSH terminal. Create a service file: sudo nano /etc/systemd/system/relay.service. Paste the systemd configuration (see code block below), then run sudo systemctl enable relay.service and sudo systemctl start relay.service.

The Code: SSH-Triggered Python GPIO Script

This Python script targets the Pi 5 using the modern gpiozero library backed by lgpio. It includes explicit pin definitions, state management, and error handling to prevent the GPIO pins from locking up if the script crashes.

#!/usr/bin/env python3
import time
import sys
import logging
from gpiozero import OutputDevice
from signal import pause

# --- Pin Definitions (BCM Numbering) ---
RELAY_PIN = 17

# Configure basic logging for systemd journal
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

def main():
    relay = None
    try:
        # Initialize relay. Most 5V relay modules are Active LOW.
        # active_high=False means relay.on() pulls the pin to GND.
        relay = OutputDevice(RELAY_PIN, active_high=False, initial_value=False)
        logging.info(f"Relay controller initialized on BCM GPIO {RELAY_PIN}.")
        
        # Main control loop
        while True:
            relay.on()
            logging.info("Relay ENGAGED (Circuit Closed)")
            time.sleep(10)
            
            relay.off()
            logging.info("Relay DISENGAGED (Circuit Open)")
            time.sleep(10)
            
    except KeyboardInterrupt:
        logging.info("Shutdown requested via keyboard interrupt.")
    except Exception as e:
        logging.critical(f"Fatal hardware or logic error: {e}", exc_info=True)
        sys.exit(1)
    finally:
        # Explicitly release the GPIO pin back to the OS
        if relay is not None:
            relay.close()
            logging.info("GPIO resources released cleanly.")

if __name__ == '__main__':
    main()

Systemd Service File (/etc/systemd/system/relay.service):

[Unit]
Description=Pi 5 GPIO Relay Controller
After=network.target

[Service]
ExecStart=/usr/bin/python3 /home/pi/relay_control.py
Restart=always
RestartSec=5
User=root

[Install]
WantedBy=multi-user.target

Debugging: Exact Error Strings and Ranked Causes

When your SSH connection fails, the terminal output tells you exactly where the breakdown occurred. Here are the three most common errors and how to fix them.

The First 3 Things to Check When SSH Fails:
1. Ping the IP: Run ping 192.168.1.XX. If it times out, the Pi is off, disconnected, or on a different subnet.
2. Check Port 22: Run nc -vz 192.168.1.XX 22. If it says 'Connection refused', the Pi is online but the SSH daemon is dead or blocked.
3. Verify Credentials: Ensure you are using the username created during the Raspberry Pi Imager process, not the deprecated default 'pi' user.

Error 1: "Connection refused"

Exact String: ssh: connect to host 192.168.1.50 port 22: Connection refused

  • Cause A (Most Likely): The ssh file was not created in the boot partition, or it had a hidden .txt extension (e.g., ssh.txt). Fix: Re-flash or mount the SD card on a PC and create the extension-less file.
  • Cause B: The SSH daemon crashed or is masked. Fix: Connect a monitor/keyboard, log in locally, and run sudo systemctl unmask ssh && sudo systemctl enable --now ssh.
  • Cause C: UFW (Uncomplicated Firewall) is active and blocking port 22. Fix: Run sudo ufw allow ssh.

Error 2: "Network is unreachable" or "Timed out"

Exact String: ssh: connect to host 192.168.1.50 port 22: Network is unreachable

  • Cause A (Most Likely): You are targeting the wrong IP address. The Pi's DHCP lease expired or changed. Fix: Check your router's admin panel for the current IP, or set a static DHCP reservation for the Pi's MAC address.
  • Cause B: WiFi credentials in custom.toml are incorrect, or the Pi is out of range of the 5GHz band. Fix: Force the Pi to connect to a 2.4GHz SSID, or switch to wired Ethernet.

Error 3: "REMOTE HOST IDENTIFICATION HAS CHANGED"

Exact String: WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!

  • Cause A (Most Likely): You re-flashed the SD card or swapped in a new Pi, but kept the same static IP. Your host machine remembers the old cryptographic fingerprint. Fix: Run ssh-keygen -R 192.168.1.50 on your host machine to clear the old key, then reconnect.

Extending or Simplifying the Build

Once you have reliable SSH access and a functioning relay, you can scale the project to match your specific application requirements.

To Simplify (The Minimalist Approach):
If you only need to trigger a relay once a day and want to eliminate Python entirely, strip the build down to a bash cron job. SSH into the Pi and type crontab -e. Add a line like 0 8 * * * /usr/bin/raspi-gpio set 17 op dh to pull the pin high at 8 AM. This removes the Python dependency and reduces RAM usage to near zero, ideal for a Pi Zero 2 W.

To Extend (The Industrial Approach):
If you are scaling to 8+ relays or adding I2C sensors (like a BME280 temperature sensor), the Pi 5's 3.3V logic and limited 5V pin current become bottlenecks. 1. Upgrade to an official Raspberry Pi M.2 HAT+ and an NVMe drive to eliminate SD card corruption from frequent logging. 2. Replace the raw relay module with an I2C GPIO expander like the MCP23017, which isolates the Pi's sensitive RP1 chip from inductive kickback generated by relay coils. 3. Expose the relay state over MQTT using the paho-mqtt Python library, allowing Home Assistant to control the hardware without needing to SSH in to run manual scripts.

For detailed specifications on the Pi 5's power delivery and GPIO tolerances, refer to the official Raspberry Pi 5 hardware documentation. For deeper reading on securing your SSH daemon against external threats, consult the Raspberry Pi remote access security guidelines.