To enable SSH Raspberry Pi on modern Bookworm or Trixie OS without a monitor, you must place an empty file named ssh (no extension) and a userconf.txt file containing a hashed password into the boot/firmware partition before first boot. This bypasses the default security lockdown introduced in recent OS releases, allowing immediate remote headless access for embedded deployments.

The 2026 Reality: The legacy raspi-config GUI method is useless when your Pi 5 is buried in a control panel or your Zero 2 W is soldered into a custom PCB. Headless provisioning via the boot partition is the industry standard for fleet deployment.

1. The Headless Embedded Workflow: Parts & Pinout

Before writing a single line of code, ensure your hardware baseline is stable. The Raspberry Pi 5 is highly sensitive to power delivery; a brownout will silently disable the USB-C controller and Ethernet PHY, making SSH impossible even if configured perfectly.

Spec-Sheet: Target Hardware & Debug Tools
ComponentExact Variant / SpecWhy It Matters for SSH
Compute BoardRaspberry Pi 5 (8GB) or Pi Zero 2 WTarget boards for this guide; Pi 5 requires 27W PD for full peripheral uptime.
Power Supply27W USB-C PD (5V/5A)Prevents brownout-induced network drops during SSH handshake.
Storage32GB A2-Rated MicroSD or NVMe SSDA2 rating ensures the OS generates SSH host keys fast enough on first boot.
Debug FallbackCP2102 or PL2303 USB-to-TTL SerialRequired when network SSH fails; provides direct console access via UART.

UART Serial Pin Mapping (The Ultimate Fallback)

When network SSH fails, UART is your lifeline. Wire your CP2102 adapter to the Pi's primary UART0 pins. Note: On Pi 5, UART0 is mapped to GPIO 14/15 by default, but verify your config.txt if using custom overlays.

UART0 Pin Mapping for Serial Console
Pi GPIO PinPhysical Pin #FunctionCP2102 Adapter Wire
GND6Ground ReferenceGND
GPIO 14 (TXD)8Transmit DataRXD (Receive)
GPIO 15 (RXD)10Receive DataTXD (Transmit)

2. Provisioning: Steps to Enable SSH Headless

This procedure targets the Raspberry Pi 5 (8GB) and Pi Zero 2 W running Raspberry Pi OS Bookworm or newer. We use the boot/firmware partition, which is FAT32 formatted and readable by Windows, macOS, and Linux immediately after flashing.

  1. Flash the OS: Use Raspberry Pi Imager to write the 64-bit Bookworm Lite image to your storage media.
  2. Mount the Boot Partition: Eject and re-insert the SD card. Open the drive named boot or bootfs (now technically boot/firmware on the Pi itself, but appears as boot on your host PC).
  3. Create the SSH Flag: Create an empty file named exactly ssh.
    Warning: Windows Notepad will silently append .txt. The file must be ssh with zero extensions. Use a code editor like VS Code or enable 'File name extensions' in Windows Explorer to verify.
  4. Create the User Configuration: Create a file named userconf.txt. The default pi user no longer exists. You must define a custom username and an encrypted password.
  5. Generate the Hash: Open a terminal on your host machine (or use an online OpenSSL tool) and run: openssl passwd -6 Enter your desired password. Copy the resulting hash string.
  6. Format userconf.txt: Open userconf.txt and add a single line: username:encrypted_password_hash (e.g., fluxuser:$6$xyz...).
  7. Boot and Wait: Insert the SD card into the Pi and apply power. Wait exactly 90 seconds. The Pi must generate unique SSH host keys on first boot; attempting to connect before this finishes will result in a refused connection.

3. Automated Hardware Verification over SSH

Once SSH is active, you need to verify that the OS has correctly mapped the GPIO hardware. The legacy RPi.GPIO library is deprecated and broken on Pi 5 / Bookworm. Modern embedded Python relies on libgpiod via the rpi-lgpio wrapper.

Run sudo apt install python3-rpi-lgpio on your Pi, then execute this script to flash a hardware heartbeat LED on GPIO 17. This confirms SSH access, Python environment health, and hardware pinmuxing simultaneously.


import lgpio
import time
import sys

# Pin definition for hardware heartbeat verification
LED_PIN = 17
CHIP = 0  # Default GPIO chip for Pi 4/5

def setup_gpio():
    """Claims GPIO 17 as an output. Fails gracefully if pin is busy."""
    try:
        h = lgpio.gpiochip_open(CHIP)
        lgpio.gpio_claim_output(h, LED_PIN)
        print(f"Successfully claimed GPIO {LED_PIN} on chip {CHIP}")
        return h
    except lgpio.error as e:
        print(f"[FATAL] GPIO Claim Failed: {e}")
        print("Check if another process (e.g., pigpiod) is hogging the pin.")
        sys.exit(1)

def heartbeat(handle):
    """Blinks LED 5 times to visually confirm remote SSH execution."""
    try:
        for i in range(5):
            lgpio.gpio_write(handle, LED_PIN, 1)
            time.sleep(0.5)
            lgpio.gpio_write(handle, LED_PIN, 0)
            time.sleep(0.5)
        print("Heartbeat sequence complete. Hardware verified.")
    except Exception as e:
        print(f"[ERROR] Execution interrupted: {e}")
    finally:
        # Always release the chip to prevent pin lockouts
        lgpio.gpiochip_close(handle)

if __name__ == "__main__":
    print("SSH Connection Verified. Starting Hardware Heartbeat.")
    chip_handle = setup_gpio()
    heartbeat(chip_handle)

4. Debugging Connection Failures: Exact Errors & Fixes

When headless setups fail, they fail silently. Here are the exact error strings you will see, ranked by probability, and how to fix them.

Error 1: ssh: connect to host raspberrypi.local port 22: Connection refused

The First Three Things to Check:

  1. Hidden File Extensions: Your ssh file is actually named ssh.txt. The OS ignored it. Mount the SD card on your PC, enable hidden extensions, and rename it.
  2. Host Key Generation Delay: You tried to connect at 45 seconds. On a Pi Zero 2 W, generating RSA/Ed25519 host keys can take up to 120 seconds on a slow SD card. Wait 3 minutes and try again.
  3. mDNS / Avahi Failure: Your router blocks multicast DNS, so raspberrypi.local won't resolve. Log into your router's DHCP table, find the Pi's IP address (e.g., 192.168.1.45), and SSH directly to the IP.

Error 2: Permission denied (publickey,password)

  1. Malformed Password Hash: You pasted the raw password into userconf.txt instead of the OpenSSL hash, or you missed the username: prefix. The OS rejected the file and locked SSH.
  2. Root Login Attempt: You typed ssh root@raspberrypi.local. Root SSH is disabled by default in Bookworm. Use the custom username you defined in userconf.txt.
  3. Keyboard Layout Mismatch: If you generated the password hash on a UK keyboard but typed it on a US keyboard during SSH, special characters (like # or @) will mismatch. Stick to alphanumeric passwords for initial provisioning.

5. Frequently Asked Questions

How to enable SSH Raspberry Pi headless without a monitor?

Place an empty file named ssh and a userconf.txt file (containing username:hashed_password) in the root directory of the FAT32 boot partition on your SD card before inserting it into the Pi. Upon first boot, the OS moves these files to the secure partition and starts the sshd daemon automatically.

Why is my Raspberry Pi SSH connection refused on first boot?

The most common cause is interrupting the boot sequence before SSH host keys are generated. If the Pi loses power during the 60-120 second key generation window, the SSH service will fail to start on subsequent boots to prevent security vulnerabilities. Reflash the OS and ensure stable 27W power delivery during the first boot.

How to enable SSH Raspberry Pi via UART serial console?

If network SSH is completely dead, connect a USB-to-TTL adapter to GPIO 14 (TXD), GPIO 15 (RXD), and GND. Open a serial terminal (like PuTTY or screen /dev/ttyUSB0 115200) at 115200 baud. Once logged in via serial, run sudo raspi-config, navigate to Interface Options > SSH, and enable it manually, then run sudo systemctl restart ssh.

How to extend or simplify the build for fleet deployment?

To Simplify: Use the Raspberry Pi Imager GUI on your host PC. Click the 'Gear' icon (OS Customization) to inject your SSH credentials, Wi-Fi SSID, and hostname directly into the image before flashing. This eliminates manual file creation.

To Extend: For production embedded systems, disable password authentication entirely. Generate an Ed25519 keypair on your host (ssh-keygen -t ed25519), and use Pi Imager to inject your .pub key into the Pi's authorized_keys. Then, edit /etc/ssh/sshd_config via your automation script to set PasswordAuthentication no, securing the device against brute-force attacks on the factory floor.