If you are trying to set a static IP address Raspberry Pi boards use by default, you have likely hit a wall following outdated tutorials. Here is the direct answer: Raspberry Pi OS Bookworm (Debian 12) removed dhcpcd. Editing /etc/dhcpcd.conf will do absolutely nothing on modern Pi OS. You must now use NetworkManager via the nmcli command-line tool.

Furthermore, if you are using a Raspberry Pi 5 on kernel 6.6 or newer, your Ethernet interface is no longer eth0—it has been renamed to end0. This guide walks you through the exact modern procedure, provides a Python verification script, and debugs the specific errors you will encounter when interface names or DNS settings misbehave.

Parts List & Board Variants

This guide and the accompanying code target the current mainstream Raspberry Pi hardware running the 64-bit version of Raspberry Pi OS Bookworm. The networking stack behaves identically across these variants, but the physical interface names differ.

Component Specific Variant / Model Network Interface Name (Bookworm) Notes
Microcontroller/SBC Raspberry Pi 5 (8GB) end0 (Ethernet), wlan0 (WiFi) Kernel 6.6+ renamed eth0 to end0 on Pi 5.
Microcontroller/SBC Raspberry Pi 4 Model B (4GB) eth0 (Ethernet), wlan0 (WiFi) Standard predictable naming applies.
OS / Software Raspberry Pi OS Bookworm (64-bit) N/A Uses NetworkManager; dhcpcd is masked.
Power Supply 27W USB-C PD (Pi 5) / 15W (Pi 4) N/A Brownouts cause network stack drops.
Warning: Never assign a static IP that falls inside your router's DHCP pool. If your router hands out addresses from 192.168.1.100 to 192.168.1.200, set your Pi's static IP to something outside that range, like 192.168.1.50, to prevent IP collisions.

The Modern Way: Configuring NetworkManager via nmcli

To set a static IP address on Raspberry Pi OS Bookworm, we use nmcli (NetworkManager Command Line Interface). This is the enterprise-standard tool now native to Debian 12. For a deeper dive into the tool's flags, refer to the official NetworkManager nmcli documentation.

Step-by-Step Configuration

  1. Identify your active connection name. Run nmcli connection show. You are looking for the connection tied to your interface. On a fresh Pi 5 Ethernet setup, it is usually named Wired connection 1 or eth0/end0.
  2. Modify the IPv4 method. Change the connection from DHCP to manual (static). Replace 'Wired connection 1' with your actual connection name from step 1.
    sudo nmcli connection modify 'Wired connection 1' ipv4.method manual
  3. Assign the static IP and subnet mask. We use CIDR notation (e.g., /24 for a 255.255.255.0 subnet).
    sudo nmcli connection modify 'Wired connection 1' ipv4.addresses 192.168.1.50/24
  4. Set the default gateway. This is usually your router's IP.
    sudo nmcli connection modify 'Wired connection 1' ipv4.gateway 192.168.1.1
  5. Set the DNS servers. If you skip this, you will have local network access but no internet domain resolution. We will use Cloudflare and Google DNS.
    sudo nmcli connection modify 'Wired connection 1' ipv4.dns "1.1.1.1 8.8.8.8"
  6. Apply the changes. Restart the connection to load the new profile.
    sudo nmcli connection up 'Wired connection 1'
Pro-Tip: If you prefer a visual terminal interface over memorizing nmcli flags, simply type sudo nmtui in the terminal. It launches a text-based GUI where you can arrow-key your way through the exact same static IP settings.

Python Verification Script (with Error Handling)

When deploying headless Pi nodes (like environmental sensors or MQTT brokers), you need a automated way to verify the network stack came up correctly after a reboot. The following Python 3 script checks the interface IP, verifies gateway reachability, and handles the specific edge cases of the Pi 5 end0 interface rename.

Interface & Pin Mapping

Logical Target Pi 4 Interface Pi 5 Interface (Kernel 6.6+) Script Variable
Primary Ethernet eth0 end0 PRIMARY_IFACE
WiFi Fallback wlan0 wlan0 FALLBACK_IFACE

Complete Compilable Code

#!/usr/bin/env python3
"""
Network Verification Script for Raspberry Pi OS Bookworm
Targets: Raspberry Pi 5 (end0) and Raspberry Pi 4 (eth0)
"""
import subprocess
import socket
import sys
import fcntl
import struct

# Interface definitions based on kernel naming conventions
PRIMARY_IFACE = "end0"   # Change to "eth0" if using Pi 4
FALLBACK_IFACE = "wlan0"
GATEWAY_IP = "192.168.1.1"

def get_ip_address(ifname):
    """Fetches the IPv4 address of a specific network interface."""
    try:
        # Using socket and fcntl to query the kernel directly
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
            s.fileno(),
            0x8915,  # SIOCGIFADDR
            struct.pack('256s', ifname[:15].encode('utf-8'))
        )[20:24])
    except OSError as e:
        return None

def ping_gateway(gateway):
    """Tests Layer 3 reachability to the default gateway."""
    try:
        # -c 2 (2 packets), -W 2 (2 second timeout)
        result = subprocess.run(
            ['ping', '-c', '2', '-W', '2', gateway],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.PIPE,
            text=True
        )
        return result.returncode == 0
    except Exception as e:
        print(f"Ping execution failed: {e}")
        return False

def main():
    print("--- Raspberry Pi Network Stack Verification ---")
    
    # 1. Check Primary Interface IP
    ip = get_ip_address(PRIMARY_IFACE)
    if ip:
        print(f"[OK] {PRIMARY_IFACE} is UP with IP: {ip}")
    else:
        print(f"[WARN] {PRIMARY_IFACE} not found or down. Checking fallback...")
        ip = get_ip_address(FALLBACK_IFACE)
        if ip:
            print(f"[OK] Fallback {FALLBACK_IFACE} is UP with IP: {ip}")
        else:
            print("[FAIL] No active network interfaces found. Check physical link.")
            sys.exit(1)

    # 2. Verify Gateway Reachability
    if ping_gateway(GATEWAY_IP):
        print(f"[OK] Gateway {GATEWAY_IP} is reachable.")
    else:
        print(f"[FAIL] Gateway {GATEWAY_IP} is unreachable. Check subnet mask.")
        sys.exit(1)

    # 3. Verify DNS Resolution
    try:
        socket.gethostbyname('raspberrypi.com')
        print("[OK] DNS resolution is functional.")
    except socket.gaierror:
        print("[FAIL] DNS resolution failed. Check ipv4.dns in nmcli.")
        sys.exit(1)

    print("--- Network Stack Healthy ---")

if __name__ == '__main__':
    main()

Debugging: When the Network Fails

When configuring a static IP address on Raspberry Pi hardware, things occasionally break. Here are the first three things to check, followed by the exact error strings you will see in the terminal.

The First Three Things to Check

  1. Verify the Interface Name: Run ip link show. If you are on a Pi 5 and trying to configure eth0, it will fail because the kernel renamed it to end0.
  2. Check for IP Conflicts: Disconnect the Pi from the network, then ping your intended static IP from your PC. If you get a reply, another device is already using that IP.
  3. Inspect the NetworkManager Logs: Run journalctl -u NetworkManager -n 50 --no-pager to see exactly why NetworkManager rejected your configuration.

Ranked Causes & Exact Error Strings

Exact Error String Root Cause The Fix
Error: Connection 'eth0' does not exist. Interface renamed on Pi 5 (Kernel 6.6+). Use end0 or find the correct name via nmcli device status.
ping: connect: Network is unreachable Subnet mask is wrong, or gateway is on a different subnet. Verify your /24 CIDR matches your router's subnet. Re-run the ipv4.addresses nmcli command.
Temporary failure in name resolution Static IP is working, but DNS servers were not defined. Run sudo nmcli connection modify 'Wired connection 1' ipv4.dns "1.1.1.1" and reconnect.
RTNETLINK answers: File exists Trying to manually add an IP via ip addr add that NetworkManager already assigned. Stop using manual ip commands; let NetworkManager handle the routing table.

For a comprehensive breakdown of how Debian handles these network transitions, consult the Raspberry Pi Official Configuration Documentation.

Extending and Simplifying the Build

While setting a static IP on the Pi itself is useful for headless deployments, it is not always the best architectural choice. Here is how to evaluate your options:

  • Simplify with DHCP Reservation (Recommended for Home Labs): Instead of touching the Pi's OS, leave the Pi set to DHCP. Log into your router (pfSense, UniFi, or standard consumer router), find the Pi's MAC address, and assign a static lease. Why? If you move the Pi to a different network or change your router's subnet, the Pi won't become a stranded, unreachable brick.
  • Extend with Fallback WiFi: If your Pi is running a critical MQTT broker, use nmcli to configure both end0 (Ethernet) and wlan0 (WiFi). Set the ipv4.route-metric on Ethernet to 100 and WiFi to 200. If the Ethernet switch dies, NetworkManager will automatically route traffic over WiFi without dropping the TCP sessions.
  • Extend with Avahi/mDNS: If you only need to reach the Pi by name (e.g., ssh pi@sensor-node.local) and don't strictly need a fixed numeric IP, ensure the avahi-daemon is installed. This bypasses the need for static IPs entirely for local network discovery.

Frequently Asked Questions

How do I set a static IP on Raspberry Pi 5 Bookworm?

On Raspberry Pi OS Bookworm, you must use nmcli. First, identify your connection name with nmcli connection show. Then apply the settings: sudo nmcli connection modify 'Wired connection 1' ipv4.method manual ipv4.addresses 192.168.1.50/24 ipv4.gateway 192.168.1.1 ipv4.dns "1.1.1.1". Finally, restart it with sudo nmcli connection up 'Wired connection 1'. Note that the Pi 5 Ethernet interface is end0, not eth0.

Why did my Raspberry Pi static IP stop working after an OS update?

If you updated from Bullseye (Debian 11) to Bookworm (Debian 12), the OS deprecated dhcpcd in favor of NetworkManager. Your old /etc/dhcpcd.conf file is now completely ignored by the system. You must migrate your static IP settings into NetworkManager using the nmcli commands outlined in this guide.

Can I set a static IP via router DHCP reservation instead?

Yes, and for most DIY smart home and IoT projects, DHCP reservation is actually superior. By binding the Pi's MAC address to a specific IP inside your router's admin panel, you keep the Pi's network configuration dynamic. This prevents you from being locked out of the Pi if you ever change your router's IP subnet or move the device to a different physical location.

How do I fix the 'Temporary failure in name resolution' error on a static IP?

This error means your Pi has a valid local IP but doesn't know how to translate domain names (like google.com) into IP addresses. When you configured your static IP via nmcli, you likely forgot the DNS flag. Fix it by running: sudo nmcli connection modify 'Wired connection 1' ipv4.dns "1.1.1.1 8.8.8.8" followed by sudo nmcli connection up 'Wired connection 1'.