How to Configure a Static IP and Pi-hole DNS on Ubuntu Server with Netplan
A Current Guide for Ubuntu Server, systemd-resolved, cloud-init and IPv6
Introduction
A static IP address is important for a server running services such as Pi-hole. It ensures that the server and its DNS service remain available at a predictable address.
Modern Ubuntu Server versions use Netplan for network configuration. Netplan normally uses systemd-networkd on servers. Ubuntu Desktop installations often use NetworkManager instead.
This guide explains how to configure a static IPv4 address and configure the Ubuntu server itself to use its local Pi-hole service for DNS.
Important: This guide assumes Pi-hole is installed on this server and can answer DNS requests on 127.0.0.1:53.
Prerequisites
- Ubuntu Server: A recent Ubuntu Server installation using Netplan.
- Access: SSH access or local console access to the server.
- Static IP address: An address outside the router's normal DHCP range, or an address reserved in the router's DHCP configuration.
- Gateway: Your router or gateway IP address.
- Network interface: The name of the active network interface.
- Pi-hole: Pi-hole installed and running on this server.
Example values used in this guide:
- Server IP address: 192.168.178.10
- Network prefix: /24
- Subnet mask: 255.255.255.0
- Gateway/router: 192.168.178.1
- Network interface: eno2
Replace these example values with the values for your own network.
Step 1: Identify Your Network Interface Name
First, identify the network interface that is currently connected to your local network.
ip -brief address
Look for the interface with your current local IP address.
Example:
lo UNKNOWN 127.0.0.1/8 ::1/128
eno2 UP 192.168.178.25/24
In this example, the active interface is eno2.
Check the current default gateway:
ip route
Example:
default via 192.168.178.1 dev eno2 proto dhcp src 192.168.178.25 metric 100
Step 2: Inspect and Back Up Existing Netplan Configuration
Check which Netplan files currently exist:
ls -la /etc/netplan/
sudo cat /etc/netplan/*.yaml
Common file names include:
- 00-installer-config.yaml: Often created during the Ubuntu Server installation.
- 50-cloud-init.yaml: Often created by cloud-init on cloud images.
- 01-network-manager-all.yaml: May be present on systems using NetworkManager.
Important: Netplan reads and merges all files ending in `.yaml` in `/etc/netplan/`. Avoid keeping multiple conflicting configurations for the same network interface.
Create a backup before making changes:
sudo mkdir -p /root/netplan-backup
sudo cp -a /etc/netplan/. /root/netplan-backup/
Step 3: Check Which Network Service Manages the Interface
Ubuntu Server normally uses systemd-networkd. Check the status of the network services:
systemctl is-active systemd-networkd
systemctl is-active NetworkManager
Check whether systemd-networkd manages your network interface:
networkctl status eno2
If NetworkManager is active, check whether it manages the interface:
nmcli device status
Important: Do not configure NetworkManager and systemd-networkd to manage the same interface.
This guide uses:
renderer: networkd
This is normally the preferred option for Ubuntu Server.
Step 4: Handle cloud-init Configuration, If Applicable
Some Ubuntu Server cloud images use cloud-init to create a Netplan file during startup. This is often:
/etc/netplan/50-cloud-init.yaml
If you want to manage the server network configuration manually, disable cloud-init networking:
sudo mkdir -p /etc/cloud/cloud.cfg.d
sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg >/dev/null <<'EOF'
network: {config: disabled}
EOF
If the cloud-init Netplan file exists, rename it so Netplan no longer loads it:
sudo mv /etc/netplan/50-cloud-init.yaml /etc/netplan/50-cloud-init.yaml.disabled
Note: Only run this command if `50-cloud-init.yaml` exists and you intentionally want to replace its configuration with a manually managed Netplan file.
Step 5: Create Your Static Netplan Configuration
Create a new Netplan configuration file:
sudo nano /etc/netplan/10-static-ip.yaml
Paste the following configuration. Replace eno2, the IP address and the gateway with the values for your own network.
# /etc/netplan/10-static-ip.yaml
network:
version: 2
renderer: networkd
ethernets:
eno2:
dhcp4: false
addresses:
- 192.168.178.10/24
routes:
- to: default
via: 192.168.178.1
nameservers:
addresses:
- 127.0.0.1
Save the file in Nano:
- Ctrl+O: Save the file.
- Enter: Confirm the file name.
- Ctrl+X: Exit Nano.
Explanation of Key Settings:
- renderer: networkd: Uses systemd-networkd to manage the network interface.
- dhcp4: false: Prevents the server from receiving an IPv4 address, DNS settings and routes through DHCP.
- addresses: Sets the static IPv4 address and network prefix.
- routes: Sets the default route through the router or gateway.
- nameservers: Defines the DNS resolver used by this Ubuntu server.
- 127.0.0.1: Sends the server's DNS requests to the Pi-hole service running locally.
Why is there no public fallback DNS server?
Do not add a public DNS resolver, such as 1.1.1.1 or 8.8.8.8, to the Netplan configuration if you want all DNS traffic from this server to go through Pi-hole.
A fallback DNS server can bypass Pi-hole blocking and query logging.
Configure reliable upstream DNS servers inside Pi-hole instead. Pi-hole can forward allowed DNS queries to the upstream DNS providers that you select.
Step 6: Optional - Disable IPv6 Configuration
Only use this step if you intentionally do not want IPv6 connectivity on this server.
Some routers advertise IPv6 addresses, routes and DNS servers through IPv6 Router Advertisements or DHCPv6.
To stop the server from accepting this IPv6 configuration, add these lines below `dhcp4: false`:
dhcp6: false
accept-ra: false
The full configuration then becomes:
# /etc/netplan/10-static-ip.yaml
network:
version: 2
renderer: networkd
ethernets:
eno2:
dhcp4: false
dhcp6: false
accept-ra: false
addresses:
- 192.168.178.10/24
routes:
- to: default
via: 192.168.178.1
nameservers:
addresses:
- 127.0.0.1
Warning: These settings do more than stop router DNS configuration.
- dhcp6: false: Stops DHCPv6 configuration.
- accept-ra: false: Stops IPv6 Router Advertisements.
- Result: The server may not receive an IPv6 address, IPv6 default route or IPv6 DNS server.
Do not use these settings if the server requires IPv6 connectivity.
Step 7: Set Correct File Permissions
Netplan warns if active YAML files are readable or writable by non-root users.
Set secure permissions on active Netplan files:
sudo chmod 600 /etc/netplan/*.yaml
Verify the permissions:
ls -l /etc/netplan/
The active YAML file should normally look similar to this:
-rw------- 1 root root
Step 8: Validate and Apply the Netplan Configuration
Important for SSH users: An incorrect interface name, IP address, subnet prefix or gateway can disconnect the server.
First validate the configuration:
sudo netplan generate
If no errors appear, test the configuration safely:
sudo netplan try
`netplan try` temporarily applies the new configuration. If the server loses network connectivity, or if you do not confirm the change, Netplan restores the previous configuration automatically.
When the server remains reachable, apply the configuration permanently:
sudo netplan apply
Step 9: Verify the Static IP Address and Default Route
Check the configured IP address:
ip -brief address show eno2
Expected result:
eno2 UP 192.168.178.10/24
Check the default route:
ip route
Expected result:
default via 192.168.178.1 dev eno2
Test the connection to the router:
ping -c 4 192.168.178.1
Step 10: Verify DNS Configuration Correctly
On current Ubuntu versions, `/etc/resolv.conf` is often managed by systemd-resolved.
It may show this entry:
nameserver 127.0.0.53
This is normal. `127.0.0.53` is the local systemd-resolved DNS stub. It does not necessarily mean that Ubuntu is ignoring Pi-hole.
Check the DNS server configured for the interface:
resolvectl status eno2
Look for an entry similar to this:
Link 2 (eno2)
Current Scopes: DNS
DNS Servers: 127.0.0.1
Test DNS resolution through the normal system resolver:
resolvectl query example.com
Test Pi-hole directly:
dig @127.0.0.1 example.com
If `dig` is not installed, install the DNS utilities package:
sudo apt update
sudo apt install dnsutils
You can also test Pi-hole with:
nslookup example.com 127.0.0.1
Step 11: Confirm Pi-hole Is Listening on Port 53
Check whether a DNS service is listening on port 53:
sudo ss -lntup '( sport = :53 )'
You should see Pi-hole listening on port 53, either on 127.0.0.1, the server's static IP address, or both.
Check the Pi-hole service status:
sudo systemctl status pihole-FTL
If Pi-hole does not answer DNS queries:
- Check the service: Run `sudo systemctl status pihole-FTL`.
- Check port 53: Run `sudo ss -lntup '( sport = :53 )'`.
- Test DNS locally: Run `dig @127.0.0.1 example.com`.
- Check Pi-hole settings: Confirm that Pi-hole listens on localhost or on the required network interface.
Step 12: Reboot and Verify Persistence
After the live test succeeds, reboot the server:
sudo reboot
After reconnecting, run:
ip -brief address show eno2
ip route
resolvectl status eno2
resolvectl query example.com
dig @127.0.0.1 example.com
If the static IP address, default route and local DNS settings remain correct after rebooting, the configuration is persistent.
Common Problems and Solutions
Problem: Netplan Reports YAML or Indentation Errors
- Spaces: Use spaces and never use tabs in YAML files.
- Indentation: Check that each YAML level uses consistent indentation.
- Interface name: Confirm that the interface name matches the output of `ip -brief address`.
- Validation: Run `sudo netplan generate` to identify errors.
Problem: SSH Connection Is Lost After Applying the Configuration
- Interface: Check that the interface name is correct.
- IP address: Check the configured static IP address and network prefix.
- Gateway: Confirm that the gateway address is correct.
- Safe testing: Use `sudo netplan try` before applying future changes.
- Recovery: Restore the backup in `/root/netplan-backup/` through local console access if required.
Problem: resolv.conf Shows 127.0.0.53 Instead of 127.0.0.1
- Expected behaviour: This is normal when Ubuntu uses systemd-resolved.
- Check DNS: Run `resolvectl status eno2` to view the configured DNS server.
- Test Pi-hole: Run `dig @127.0.0.1 example.com` to query Pi-hole directly.
Problem: DNS Servers From the Router Still Appear
- Netplan files: Check all active configurations with `sudo cat /etc/netplan/*.yaml`.
- cloud-init: Check whether cloud-init recreates a Netplan configuration.
- NetworkManager: Check whether it manages the interface with `nmcli device status`.
- IPv6 disabled: If IPv6 is intentionally disabled, use `dhcp6: false` and `accept-ra: false`.
- IPv6 required: Configure IPv6 explicitly instead of blocking Router Advertisements.
Problem: Public Fallback DNS Bypasses Pi-hole
- Remove fallback resolvers: Remove public DNS addresses, such as `1.1.1.1`, from the Netplan nameserver configuration.
- Use local Pi-hole: Keep `127.0.0.1` as the DNS resolver for this server.
- Configure upstream DNS: Configure reliable upstream resolvers inside Pi-hole.
Conclusion
Your Ubuntu server should now have:
- Static IPv4: A persistent static IPv4 address.
- Default route: A configured gateway through the router.
- Local DNS: DNS resolution through the local Pi-hole service.
- Current Ubuntu support: A configuration compatible with Netplan and systemd-resolved.
- Optional IPv6 control: The option to stop unwanted IPv6 router configuration when IPv6 is not required.
Tip: Keep a copy of the working Netplan configuration and document the server IP address, gateway, interface name and Pi-hole upstream DNS settings.