To change your Raspberry Pi IP address on modern OS versions (Bookworm and the upcoming Trixie), you must use nmcli to modify the NetworkManager connection profile. Editing /etc/dhcpcd.conf will fail because dhcpcd has been completely replaced. The direct command to set a static IP is: sudo nmcli connection modify "Wired connection 1" ipv4.addresses 192.168.1.50/24 ipv4.gateway 192.168.1.1 ipv4.dns 1.1.1.1 ipv4.method manual, followed by sudo nmcli connection up "Wired connection 1".
If you are following a tutorial from 2022 or earlier, it is likely obsolete. The shift to Debian 12 (Bookworm) fundamentally changed how the Pi handles networking. This guide targets the Raspberry Pi 5 (8GB variant) running the 64-bit Bookworm OS, providing a reliable, code-driven approach to managing your IP with physical GPIO feedback.
Hardware Spec Sheet & Interface Mapping
While changing an IP is primarily a software task, headless embedded deployments require physical feedback mechanisms to confirm network state without a monitor. We are adding a status LED to the GPIO header to indicate when the IP configuration script is running, succeeding, or failing.
| Component | Exact Variant / Specification | Notes |
|---|---|---|
| Microcontroller | Raspberry Pi 5 (8GB RAM) | Targets Bookworm 64-bit OS |
| Power Supply | Official 27W USB-C PD Power Supply | Required for full peripheral power |
| Networking | Cat6 Ethernet Cable (Shielded) | Gigabit Ethernet interface (eth0) |
| Status Indicator | 5mm Green LED + 330Ω Resistor | Current limiting for 3.3V GPIO |
| Wiring | 22 AWG Solid Core Jumper Wires | For breadboard GPIO connections |
GPIO Pin Mapping Table
The Python script below uses the gpiozero library, which defaults to Broadcom (BCM) pin numbering. Ensure your physical wiring matches the BCM definitions, not the physical board pin numbers.
| Function | BCM GPIO Pin | Physical Board Pin | Wiring Destination |
|---|---|---|---|
| Status LED Signal | GPIO 17 | Pin 11 | 330Ω Resistor → LED Anode (+) |
| Ground Reference | GND | Pin 9 | LED Cathode (-) |
Step-by-Step Terminal Configuration
Before automating this with Python, you need to understand the manual terminal sequence. NetworkManager organizes networking by connection profiles, not just hardware interfaces. By default, the Pi creates a profile named Wired connection 1 for the Ethernet port.
eth0) when modifying persistent settings in nmcli. Always use the connection profile name. Run nmcli connection show to verify your exact profile name.
- Identify the active connection:
nmcli connection show --active
Look for the name under theNAMEcolumn (usuallyWired connection 1). - Assign the static IP, Gateway, and DNS:
sudo nmcli connection modify "Wired connection 1" ipv4.addresses 192.168.1.50/24 ipv4.gateway 192.168.1.1 ipv4.dns "1.1.1.1 8.8.8.8" ipv4.method manual
Note the CIDR notation (/24). NetworkManager requires this; it will reject standard subnet masks like255.255.255.0. - Apply the changes by restarting the connection:
sudo nmcli connection up "Wired connection 1" - Verify the new IP assignment:
ip -4 addr show eth0
Python Automation: IP Manager with GPIO Feedback
In headless IoT deployments, you often need a script that provisions a static IP on first boot or via a trigger button. The following Python script uses subprocess to call nmcli safely, capturing standard error outputs if the command fails, while using the mapped GPIO 17 LED to provide visual state feedback.
Target Board: Raspberry Pi 5 (8GB) | OS: Bookworm 64-bit | Dependencies: sudo apt install python3-gpiozero
import subprocess
import sys
from gpiozero import LED
from time import sleep
# --- Pin Definitions (BCM Numbering) ---
STATUS_LED_PIN = 17
status_led = LED(STATUS_LED_PIN)
# --- Network Configuration Parameters ---
CONNECTION_NAME = "Wired connection 1"
TARGET_IP_CIDR = "192.168.1.50/24"
GATEWAY_IP = "192.168.1.1"
DNS_SERVERS = "1.1.1.1,8.8.8.8"
def set_static_ip():
"""Modifies NetworkManager profile and applies it, with GPIO feedback."""
print(f"[INFO] Configuring {CONNECTION_NAME} to {TARGET_IP_CIDR}...")
status_led.blink(on_time=0.5, off_time=0.5) # Slow blink: Processing
# Construct the nmcli command
modify_cmd = [
"nmcli", "connection", "modify", CONNECTION_NAME,
"ipv4.addresses", TARGET_IP_CIDR,
"ipv4.gateway", GATEWAY_IP,
"ipv4.dns", DNS_SERVERS,
"ipv4.method", "manual"
]
try:
# Execute modification with strict error checking
subprocess.run(modify_cmd, check=True, capture_output=True, text=True)
# Bring the connection up to apply changes immediately
subprocess.run(
["nmcli", "connection", "up", CONNECTION_NAME],
check=True, capture_output=True, text=True
)
status_led.on() # Solid ON: Success
print("[SUCCESS] Static IP applied and connection restarted.")
except subprocess.CalledProcessError as e:
status_led.blink(on_time=0.1, off_time=0.1) # Fast blink: Error
print(f"[ERROR] nmcli failed with exit code {e.returncode}")
print(f"[ERROR] stderr: {e.stderr.strip()}")
sys.exit(1)
except FileNotFoundError:
status_led.off()
print("[CRITICAL] 'nmcli' binary not found. Is NetworkManager installed?")
sys.exit(2)
if __name__ == "__main__":
try:
set_static_ip()
except KeyboardInterrupt:
print("\n[INFO] Script interrupted by user.")
status_led.off()
sys.exit(0)
Debugging: "Error: unknown connection 'eth0'"
When migrating from older Raspberry Pi OS versions or standard Debian server setups, the most frequent failure point is attempting to pass the hardware interface name to NetworkManager's modification command.
Error: unknown connection 'eth0'.Often accompanied by Python throwing:
subprocess.CalledProcessError: Command '...' returned non-zero exit status 10.
Ranked Causes for this Failure
- Using Interface Name Instead of Profile Name (90% of cases):
nmcli connection modifyexpects the logical profile name (e.g.,Wired connection 1), not the kernel interface (eth0). Usenmcli deviceto see interfaces, andnmcli connectionto see profiles. - NetworkManager is Masked or Stopped (8% of cases): If you previously attempted to "fix" networking by reinstalling
dhcpcd, you may have accidentally masked NetworkManager. - Missing CIDR Subnet Mask (2% of cases): Passing
192.168.1.50without the/24suffix will causenmclito reject the address format, though this usually throws a "prefix missing" error rather than an "unknown connection" error.
The First Three Things to Check When It Fails
If your Python script throws an error or your terminal command fails, execute these three diagnostic commands in order:
- Verify the exact profile name:
nmcli -t -f NAME,TYPE connection show
This outputs a clean, script-readable list of all profiles. Look for the802-3-ethernettype. - Check NetworkManager service state:
systemctl status NetworkManager
Ensure it saysactive (running). If it is masked, runsudo systemctl unmask NetworkManager. - Confirm no legacy DHCP conflicts:
systemctl status dhcpcd
On Bookworm, this should return "could not be found" or "inactive". If it is running, it will fight NetworkManager for control ofeth0. Disable it withsudo systemctl disable --now dhcpcd.
Extending and Simplifying the Build
Depending on your deployment environment, you may want to scale this setup up for a fleet of devices or scale it down for quick bench testing.
How to Simplify (The Bench-Tester Route)
If you don't want to write Python scripts or memorize nmcli syntax, use the built-in Terminal UI. Simply type sudo nmtui in your SSH session. This opens a pseudo-graphical interface where you can arrow-key your way to "Edit a connection", type in your static IP, and tab over to "OK". It is the fastest way to configure a static IP on a headless Pi without relying on external tools. Furthermore, if you are flashing a brand new SD card, the Raspberry Pi Imager allows you to set a static IP in the "Advanced Options" (Ctrl+Shift+X) menu before you even write the OS to the card.
How to Extend (The Fleet IoT Route)
To extend this for a fleet of 50+ headless sensors, hardcoding IPs in a Python script is inefficient. Instead, extend the build by implementing a MAC-to-IP reservation on your router's DHCP server (e.g., pfSense or UniFi). This allows the Pi to remain on ipv4.method auto (DHCP) while guaranteeing it always receives the same IP based on its Ethernet MAC address. If you must manage it from the Pi side, extend the Python script to read the target IP from a local config.json file or fetch it via an MQTT payload on boot, allowing centralized fleet management without touching the SD cards.
Frequently Asked Questions
How do I change my Raspberry Pi IP address without a monitor?
If you are completely headless and SSH is your only access, changing the IP will sever your current SSH session the moment you run nmcli connection up. To do this safely without getting locked out, use the at command to schedule a revert, or run the modification via a background script (like the Python example above) that includes a 60-second timeout to revert to DHCP if a specific "keep-alive" file isn't created. Alternatively, if you have physical access, plug in a USB-to-TTL serial console cable to the Pi's UART pins (GPIO 14/15) so you retain shell access even if the Ethernet IP changes or breaks.
Why did my static IP stop working after updating to Bookworm?
Prior to October 2023, Raspberry Pi OS used dhcpcd as its DHCP client and network configurator. Users would append static IP rules to the bottom of /etc/dhcpcd.conf. With the release of the Bookworm-based OS, Raspberry Pi Ltd adopted NetworkManager as the default networking stack to better handle complex WiFi roaming, enterprise WPA3, and VPN integrations. The OS completely ignores /etc/dhcpcd.conf now. You must migrate your static IP rules to nmcli connection profiles.
Can I set a static IP address using the Raspberry Pi Imager?
Yes, and this is the most reliable method for new deployments. When setting up your OS in the Raspberry Pi Imager application on your PC or Mac, click the gear icon (or press Ctrl+Shift+X / Cmd+Shift+X) to open the Advanced Options. Under "Network Settings", you can check "Set custom IP", input your desired address, router gateway, and DNS servers. The Imager writes a NetworkManager configuration file directly to the boot partition, which the Pi applies on its very first boot sequence.
Does changing the IP address affect my WiFi connection?
No, NetworkManager treats Ethernet (802-3-ethernet) and WiFi (802-11-wireless) as entirely separate connection profiles. Modifying "Wired connection 1" will not alter your WiFi profile (usually named after your SSID). If you want a static IP on WiFi, you must run the nmcli connection modify command against your specific SSID's profile name instead.






