If you are still trying to configure your Raspberry Pi network by editing /etc/wpa_supplicant/wpa_supplicant.conf or /etc/dhcpcd.conf, stop. As of Raspberry Pi OS Bookworm and the current 2026 Trixie releases, the OS has fully migrated to NetworkManager. The direct answer for modern headless Raspberry Pi network config is to use the nmcli command-line tool for Wi-Fi and Ethernet management, paired with a hardware-level GPIO indicator to confirm link state without needing a monitor.

This guide targets the Raspberry Pi 5 (4GB variant) running 64-bit Raspberry Pi OS. We will build a headless network node, map GPIO pins for physical status LEDs, write a robust Python monitoring script, and debug the exact NetworkManager errors that stall headless deployments.

The 2026 Raspberry Pi Network Config Decision Tree

Before flashing an SD card or NVMe drive, choose your network topology. Use this decision matrix to lock in your configuration strategy.

Deployment Scenario Primary Interface IP Assignment Concrete Pick / Default Action
High-bandwidth local server (NAS, Pi-hole) Gigabit Ethernet (eth0) Static IPv4 Pick: Ethernet + nmcli static IP (/24 subnet)
Remote IoT sensor / mobile robot Wi-Fi 5 (wlan0) DHCP Pick: 5GHz Wi-Fi + DHCP with MAC reservation on router
Industrial / ceiling-mounted node PoE+ (802.3at) Static IPv4 Pick: Waveshare PoE HAT + Ethernet static IP
Default Recommendation: For 90% of home-lab and maker projects, terminate your decision here: Raspberry Pi 5 4GB on Gigabit Ethernet with a static IP assigned via NetworkManager. Wi-Fi on the Pi 5 is adequate for telemetry, but the PCIe-lane Gigabit Ethernet controller is vastly superior for sustained throughput and latency.

Hardware & Parts List: Pi 5 Headless Network Node

This build assumes a headless deployment where physical feedback is required to diagnose boot and network issues without plugging in an HDMI display.

Component Exact Variant / Model Estimated Price (2026)
Compute Board Raspberry Pi 5 (4GB RAM) $60.00
Storage Samsung 980 256GB NVMe M.2 (2230 or 2242) $32.00
Enclosure Argon ONE V3 M.2 NVMe Case (Active/Passive cooling) $35.00
Power Supply Official Raspberry Pi 27W USB-C PD Power Supply $12.00
Indicator LEDs 3mm Diffused LEDs (Red, Green, Blue) + 330Ω resistors $2.00

Pin Mapping: GPIO Network Status LEDs

To give our headless Pi physical network awareness, we will wire three LEDs to the GPIO header. This allows you to glance at the board and instantly know if the physical link is up and if an IP address has been assigned.

LED Color Function BCM GPIO Pin Physical Pin (40-pin Header) Wiring Note
Red No Link / Error GPIO 17 Pin 11 Anode to Pin 11, Cathode to 330Ω resistor, then to GND (Pin 9)
Green Physical Link Up GPIO 27 Pin 13 Anode to Pin 13, Cathode to 330Ω resistor, then to GND (Pin 14)
Blue IP Address Assigned GPIO 22 Pin 15 Anode to Pin 15, Cathode to 330Ω resistor, then to GND (Pin 20)

Step-by-Step: NetworkManager CLI Configuration

With the hardware assembled and the Pi booted headless (accessed via a temporary monitor or USB-C serial console), use nmcli to configure the network. We will set a static IP on Ethernet (eth0).

  1. Check current NetworkManager status:
    nmcli general status
    Verify it returns 'connected' or 'disconnected', not 'unmanaged'.
  2. Create a new static Ethernet connection profile:
    sudo nmcli con add type ethernet ifname eth0 con-name eth0-static autoconnect yes
  3. Assign the static IP, Gateway, and DNS:
    sudo nmcli con mod eth0-static ipv4.addresses 192.168.1.50/24
    sudo nmcli con mod eth0-static ipv4.gateway 192.168.1.1
    sudo nmcli con mod eth0-static ipv4.dns "1.1.1.1 8.8.8.8"
    sudo nmcli con mod eth0-static ipv4.method manual
  4. Activate the profile:
    sudo nmcli con up eth0-static
  5. Verify the assignment:
    ip -4 addr show eth0

Python Network Monitor Script (With Error Handling)

This script targets the Raspberry Pi 5 (4GB) running 64-bit OS. It uses the gpiozero library to drive our status LEDs and subprocess to query NetworkManager. It includes robust error handling for interface dropouts.

import time
import socket
import subprocess
from gpiozero import LED

# BCM Pin Definitions
PIN_RED = 17
PIN_GREEN = 27
PIN_BLUE = 22

# Initialize LEDs
led_red = LED(PIN_RED)
led_green = LED(PIN_GREEN)
led_blue = LED(PIN_BLUE)

INTERFACE = 'eth0'

def check_physical_link():
    """Checks if the physical Ethernet cable is plugged in via ip link."""
    try:
        result = subprocess.run(
            ['ip', 'link', 'show', INTERFACE],
            capture_output=True, text=True, timeout=2
        )
        return 'state UP' in result.stdout or 'LOWER_UP' in result.stdout
    except Exception as e:
        print(f'Link check error: {e}')
        return False

def check_ip_assigned():
    """Checks if a valid IPv4 address (not 169.254.x.x) is assigned."""
    try:
        result = subprocess.run(
            ['ip', '-4', 'addr', 'show', INTERFACE],
            capture_output=True, text=True, timeout=2
        )
        for line in result.stdout.split('\n'):
            if 'inet ' in line and '169.254.' not in line:
                return True
        return False
    except Exception as e:
        print(f'IP check error: {e}')
        return False

def set_led_state(link_up, ip_assigned):
    """Drives the GPIO LEDs based on network state."""
    if not link_up:
        led_red.on()
        led_green.off()
        led_blue.off()
    elif link_up and not ip_assigned:
        led_red.off()
        led_green.on()
        led_blue.blink(on_time=0.5, off_time=0.5, background=False)
    else:
        led_red.off()
        led_green.on()
        led_blue.on()

if __name__ == '__main__':
    print('Starting Pi 5 Network Monitor...')
    try:
        while True:
            link = check_physical_link()
            ip_ok = check_ip_assigned()
            set_led_state(link, ip_ok)
            time.sleep(2)
    except KeyboardInterrupt:
        print('Monitor stopped by user.')
    finally:
        led_red.off()
        led_green.off()
        led_blue.off()

Debugging: Exact Errors & The First Three Checks

When headless network configs fail, you are usually flying blind. Here are the exact error strings NetworkManager throws, what they mean, and how to fix them.

Error 1: The Wi-Fi Secret Failure

Exact Error String: Error: Connection activation failed: (7) Secrets were required, but not provided.

Ranked Causes:

  1. Missing interactive prompt: You ran nmcli dev wifi connect SSID password 'xyz' but the password contained unescaped shell characters (like ! or $). Fix: Use single quotes around the password, or use the --ask flag to let nmcli prompt you securely.
  2. WPA3 vs WPA2 mismatch: The router enforces WPA3-SAE, but the Pi's NetworkManager profile defaulted to WPA2. Fix: Edit the connection with nmcli con mod SSID wifi-sec.key-mgmt sae.

Error 2: The DNS Blackhole

Exact Error String: ping: google.com: Temporary failure in name resolution

Ranked Causes:

  1. Static IP missing DNS: You set a static IP via nmcli but forgot to define ipv4.dns. Fix: Run sudo nmcli con mod eth0-static ipv4.dns "1.1.1.1" and restart the connection.
  2. systemd-resolved conflict: A leftover /etc/resolv.conf symlink is broken. Fix: Ensure NetworkManager is managing DNS by checking sudo nmcli general status (DNS field should not be empty).

The "First Three Checks" When It Fails

If your Pi drops off the network and the Red LED turns on, run these three diagnostics in order via serial console or local keyboard:

  1. Check NetworkManager State: nmcli general status (Look for 'connected' vs 'disconnected').
  2. Check Interface IP: ip a show eth0 (Look for a valid subnet IP, not just a link-local 169.254.x.x address).
  3. Check the Logs: journalctl -u NetworkManager -n 50 --no-pager (This will reveal DHCP timeouts or authentication rejections).

Extending or Simplifying the Build

Depending on your deployment scale, you should either strip this build down to its bare essentials or scale it up for fleet management.

To Simplify (Single Node):
Skip the CLI entirely for initial provisioning. Use the Raspberry Pi Imager on your desktop. In the OS Customisation settings (the gear icon), input your Wi-Fi SSID, password, and check the box to set a static IP or hostname. The Imager writes a custom.toml file to the boot partition, which the Pi parses on first boot to configure NetworkManager automatically before you even plug it in.

To Extend (Fleet Monitoring):
If you are deploying five or more Pi 5 nodes, GPIO LEDs are insufficient. Extend this build by installing prometheus-node-exporter via sudo apt install prometheus-node-exporter. This exposes network interface metrics (bytes sent/received, error rates, drop counts) on port 9100. You can then scrape these metrics into a central Grafana dashboard, allowing you to monitor the exact moment a Wi-Fi interface drops packets across your entire fleet without writing custom Python polling scripts.