Netplan YAML file and server with static IPv4 and IPv6 addresses applied safely with netplan try
Networking

Netplan Static IP and IPv6 on Ubuntu: Safe Setup Guide

Changing the network settings of a server you can only reach over the network is the sysadmin equivalent of sawing off the branch you are sitting on. One wrong indent in a YAML file or one mistyped gateway, and your SSH session freezes mid-command, leaving you with a perfectly healthy VPS that nobody can talk to. The good news is that Ubuntu ships a tool designed for exactly this moment. In this tutorial we write a clean Netplan configuration with static IPv4 and IPv6 addresses, default gateways, DNS servers and additional IPs, and we apply it with netplan try, which puts the old configuration back automatically if we lose contact.

Netplan is developed by Canonical and documented at netplan.io . It has been the standard way to configure networking on Ubuntu since 17.10, so on a fresh Ubuntu 24.04 VPS it is already installed and already in charge. We like it on our own Ubuntu machines because a single, readable YAML file is much easier to review than a pile of scattered interface files, and because netplan try has saved more than one late-night maintenance window.

What Netplan is, and why your VPS uses it

Netplan is not a network daemon. It is a translator. You describe the network you want in a YAML file under /etc/netplan/, and Netplan converts that description into the configuration format of a “renderer”, the program that actually configures the network card. On Ubuntu Server the renderer is systemd-networkd; on Ubuntu Desktop it is usually NetworkManager. Once the translation is done, Netplan steps aside and the renderer does the work.

That design has one big advantage: you only learn one syntax. Whether the machine is a laptop or a VPS, addresses, routes and DNS servers are written the same way, and the same file can be read and reviewed by anyone on your team.

A quick networking refresher

If you already know what a /64 is, skip ahead. Otherwise, here are the concepts we use in this article:

  • IP address: the number that identifies your server on a network, like a street address. IPv4 addresses look like 203.0.113.10; IPv6 addresses look like 2001:db8:1234::10. The :: is shorthand for “a run of zeros”.
  • Prefix (or netmask): the /24 or /64 written after the address. It says how many leading bits describe the network, and therefore which other addresses are “neighbours” your server can reach directly. /24 in IPv4 means 256 addresses that share the first three numbers; /64 is the standard size of an IPv6 network.
  • Gateway: the router your server sends traffic to when the destination is not a neighbour, which is almost everything on the internet. In Netplan this is expressed as the default route.
  • DNS servers (resolvers): the servers that translate names like dreamserver.ro into IP addresses. Without them, ping by IP works, but nothing that uses names does.
  • DHCP and router advertisements: automatic ways for a server to receive its address. DHCP is common for IPv4; IPv6 can also use SLAAC, where the router announces the network and the server builds its own address. “Static” simply means we write the values ourselves instead of asking the network.

Why use a static IP on a VPS?

Many VPS images boot with DHCP for IPv4, and that works fine on day one. Static configuration starts to make sense when:

  • you ordered additional IPv4 addresses or want to use more addresses from your IPv6 subnet, which DHCP will not hand out for you;
  • your IPv6 subnet is assigned statically by the provider and is not announced through DHCPv6 or SLAAC, so the server has no IPv6 until you configure it;
  • you want the network to come up identically on every boot, without depending on a DHCP server answering in time;
  • you run services (mail, DNS, VPN) where the address must never change and must match firewall rules and reverse DNS.
From YAML file to working network/etc/netplan/10-static.yamlnetplangenerate/run/systemd/network/systemd-networkdeth0kernel stateyou edit thisvalidatesgeneratedapplies itwhat ip showsNetwork pathYour VPS: eth0IPv4203.0.113.10/24Extra203.0.113.11/24IPv62001:db8:1234::10/64DNSsystemd-resolvedProvider gateway203.0.113.12001:db8:1234::1InternetIPv4 + IPv6
Netplan translates your YAML into systemd-networkd configuration; the VPS then reaches the internet through the provider gateway on both IPv4 and IPv6 (example addresses).

What you need

  • A VPS running Ubuntu 24.04 (22.04 works too, the syntax is the same). A KVM VPS is ideal; LXC users should read the note further down first.
  • A user with sudo rights and a working SSH connection.
  • Your network details from the provider: IPv4 address and prefix, IPv4 gateway, IPv6 address or subnet with prefix, IPv6 gateway, and the DNS servers you want to use. On a DreamServer VPS these are shown in the client area and in the welcome email.
  • Access to the web console (VNC / noVNC) of the VPS, if your panel offers one. It is your plan B; open it once before starting, just so you know where it is.
  • tmux, which is installed by default on Ubuntu Server (sudo apt install tmux if it is missing).
  • About 15 minutes, and no other urgent changes running on the server at the same time.

All examples use addresses reserved for documentation (203.0.113.0/24 for IPv4 and 2001:db8::/32 for IPv6) and the interface name eth0. Replace them with your own values everywhere. Copying the examples literally will take your server offline, which is exactly what we are trying to avoid.

Static IP with Netplan: the 7 steps1234567GatherdetailsBack upconfigTamecloud-initWritethe YAMLValidategenerateApply withnetplan tryVerifyand rebootauto-revertafter 120 s
The seven steps of this tutorial, numbered exactly like the Step 1 to Step 7 headings below. Step 6 (netplan try) is the safety net that reverts a bad configuration after 120 seconds.

Step 1: Gather your network details

First, let us see what the server looks like right now. The ip command shows interfaces, addresses and routes:

ip -br link
ip -br addr
ip route show
ip -6 route show

-br means “brief”, one line per interface. The output looks roughly like this:

lo               UNKNOWN        127.0.0.1/8 ::1/128
eth0             UP             203.0.113.10/24 metric 100 fe80::5054:ff:fe12:3456/64
default via 203.0.113.1 dev eth0 proto dhcp src 203.0.113.10 metric 100

Three things to note: the interface name (here eth0; on many VPS it is ens3, ens18 or enp1s0), the current IPv4 address, and the words proto dhcp, which tell us the address came from DHCP. If the only IPv6 address you see starts with fe80::, that is a link-local address every IPv6 interface has automatically; it does not mean IPv6 is configured.

Now look at the existing Netplan files:

ls -l /etc/netplan/
sudo cat /etc/netplan/*.yaml

On a cloud image you will typically find 50-cloud-init.yaml; on a system installed from the ISO it may be 50-cloud-init.yaml or 00-installer-config.yaml. Note whether the file contains a match: block with a macaddress and a set-name: line. That means the interface is renamed at boot, and we must keep that block, more on this in step 4.

Finally, write your values down in one place. A small table in a text file on your own computer is perfect:

SettingExample valueYour value
Interfaceeth0
IPv4 address/prefix203.0.113.10/24
IPv4 gateway203.0.113.1
IPv6 address/prefix2001:db8:1234::10/64
IPv6 gateway2001:db8:1234::1 or fe80::1
DNS servers1.1.1.1, 9.9.9.9, 2606:4700:4700::1111
Extra IPs (optional)203.0.113.11/24, 2001:db8:1234::11/64

Some providers give an IPv6 gateway of fe80::1, a link-local address. That is perfectly valid and Netplan accepts it as is.

Step 2: Back up the current configuration

Before touching anything, copy the current Netplan directory somewhere safe:

sudo mkdir -p /root/netplan-backup
sudo cp -a /etc/netplan/. /root/netplan-backup/
sudo ls -l /root/netplan-backup/

The -a flag keeps permissions and timestamps, and the trailing /. copies the contents of the directory rather than the directory itself. The last command should list the same file names you saw in step 1.

Why /root/netplan-backup and not /etc/netplan/old.yaml? Because Netplan reads every file ending in .yaml in /etc/netplan/ and merges them in alphabetical order. A backup copy left in that directory is not a backup, it is a second, active configuration that will fight with your new one. Always keep backups outside the directory.

Step 3: Stop cloud-init from overwriting your changes

cloud-init is the tool that configures a cloud VPS on first boot: hostname, SSH keys, and often the network. If cloud-init generated your Netplan file, the file starts with a comment like this:

# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}

Take that warning literally: on some platforms cloud-init rewrites the network configuration at boot, and your carefully crafted static setup disappears after the next restart. We follow its own advice:

echo 'network: {config: disabled}' | sudo tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg

tee writes the line into the file with root rights and echoes it back, so you should see network: {config: disabled} printed in the terminal. If the /etc/cloud/ directory does not exist, your system does not use cloud-init and you can skip this step.

One consequence to keep in mind: from now on cloud-init will not update the network for you. If you later change IPs in the provider panel, you update the Netplan file yourself.

Step 4: Write the Netplan YAML for a static IP and IPv6

We create one new file that fully describes the interface, then remove the old one so there is exactly one source of truth. Open the editor:

sudo nano /etc/netplan/10-static.yaml

Paste the following, after replacing the example values with your own:

network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      # If your old file had a match + set-name block, copy it here unchanged:
      # match:
      #   macaddress: "52:54:00:12:34:56"
      # set-name: eth0
      dhcp4: false
      dhcp6: false
      accept-ra: false
      addresses:
        - 203.0.113.10/24
        - "2001:db8:1234::10/64"
      routes:
        - to: default
          via: 203.0.113.1
        - to: default
          via: "2001:db8:1234::1"
      nameservers:
        addresses:
          - 1.1.1.1
          - 9.9.9.9
          - "2606:4700:4700::1111"
          - "2620:fe::fe"

Save with Ctrl+O, Enter, and exit with Ctrl+X. Then lock down the permissions and remove the old file (we have a copy from step 2):

sudo chmod 600 /etc/netplan/10-static.yaml
sudo rm /etc/netplan/50-cloud-init.yaml
ls -l /etc/netplan/

Use the real name of your old file if it differs. The last command should list only 10-static.yaml, with permissions -rw-------. Netplan warns loudly when its files are readable by other users, because Netplan files can contain secrets such as Wi-Fi passwords.

Removing the old file does not change the running network yet; nothing is applied until step 6.

The YAML, line by line

YAML is a format where indentation is the structure. Always use spaces, never tabs, and keep each level two spaces deeper than its parent. Here is what each part means:

  • network: and version: 2: the top-level key and the Netplan format version. It is always 2.
  • renderer: networkd: hand the configuration to systemd-networkd, the default on Ubuntu Server.
  • ethernets: then eth0:: settings for the Ethernet interface called eth0.
  • match: and set-name: (commented out): only needed if your old file used them. They identify the card by MAC address and give it a fixed name. If your old file had them, uncomment them and use the exact values from that file.
  • dhcp4: false and dhcp6: false: do not ask for addresses automatically, we provide them.
  • accept-ra: false: ignore IPv6 router advertisements, so the server does not add extra SLAAC addresses or routes next to our static ones. If your provider told you that IPv6 works through router advertisements, set this to true or remove the line.
  • addresses:: a list of addresses with their prefixes. IPv4 and IPv6 can be mixed in the same list. We wrap IPv6 values in quotes so YAML never misreads the colons.
  • routes: with to: default: the default gateways, one for IPv4 and one for IPv6. Netplan works out which is which from the address family.
  • nameservers:: the DNS servers for this interface, passed on to systemd-resolved.

You may find older guides that use gateway4: and gateway6:. Those keys are deprecated and Netplan prints a warning when it sees them; the routes: form above is the current one.

When the gateway is outside your subnet

Some setups give you an IPv4 address with a /32 prefix, meaning “just this one address”, and a gateway that is not inside that range. The kernel would normally refuse such a route because it does not know how to reach the gateway. The on-link: true option tells it: “this gateway is directly on the wire, just send to it”:

      addresses:
        - 203.0.113.10/32
      routes:
        - to: default
          via: 203.0.113.1
          on-link: true

Only use this if your provider’s instructions call for it. With a normal /24 and a gateway inside it, you do not need it.

Step 5: Validate the configuration with netplan generate

Before applying anything, ask Netplan to parse the file and produce the backend configuration without touching the live network:

sudo netplan generate

No output means the YAML is valid. Errors point to the file, line and column. The exact wording depends on the Netplan version, but it looks like this:

/etc/netplan/10-static.yaml:9:1: Invalid YAML: found character that cannot start any token

That particular message usually means a tab character slipped in. Fix the reported line and run the command again until it is silent. You can also view the configuration exactly as Netplan understood it:

sudo netplan get

This prints the merged result of all files. If you see addresses or interfaces you did not expect, there is still another .yaml file somewhere in /etc/netplan/.

Keep in mind that generate catches syntax problems, not logic problems. A wrong but well-formed gateway passes validation perfectly. That is why the next step matters so much.

Step 6: Apply it safely with netplan try

netplan apply applies the configuration immediately and permanently. netplan try applies it temporarily: it switches the network over, then waits for you to press Enter. If you do not confirm within the timeout (120 seconds by default), it restores the previous network state on its own. A typo that kills your connection therefore costs you two minutes, not a support ticket.

Start a tmux session first, so the command keeps running even if your SSH connection hangs or drops:

tmux new -s net
sudo netplan try

You will see something like:

Do you want to keep these settings?

Press ENTER before the timeout to accept the new configuration

Changes will revert in 120 seconds

Now test before pressing Enter. Open a second terminal on your own computer and connect to the server again:

ssh youruser@203.0.113.10

If the new SSH session works, run a couple of quick checks from it (ping -c 3 1.1.1.1 and ping -6 -c 3 2606:4700:4700::1111), then go back to the first window and press Enter. Netplan answers with Configuration accepted. and the change is now permanent.

If you changed the address you were connected to, the first session will freeze, which is expected. Connect to the new address from the second terminal, attach to the tmux session with tmux attach -t net, and press Enter there. This is the main reason we use tmux: the confirmation prompt follows you to the new connection.

If nothing works, do nothing. After the timeout Netplan reverts, the old network comes back, and your frozen session usually wakes up on its own. You can shorten the wait with sudo netplan try --timeout 60.

An important detail: netplan try reverts the running network, not your file. Your edited 10-static.yaml is still on disk. Fix it and try again, or, to go back to the original setup completely:

sudo rm /etc/netplan/10-static.yaml
sudo cp -a /root/netplan-backup/. /etc/netplan/
sudo netplan generate

Never reboot while a broken file sits in /etc/netplan/, because the next boot will apply it without any safety net.

Downtime after a broken config (approximate)netplan try --timeout 30netplan try (default 120 s)netplan apply + web consolenetplan apply + support ticket~0.5 min~2 min~10 min~45 min015304560Minutes without network (approximate, illustrative)Method
Approximate time a VPS stays unreachable after a broken network change, depending on how it was applied in step 6. Illustrative values; what matters is the order of magnitude.

Step 7: Verify connectivity, DNS, and survive a reboot

With the configuration accepted, check each piece separately. Addresses and routes first:

ip -br addr show eth0
ip route show default
ip -6 route show default

Expected output, with your own values:

eth0             UP             203.0.113.10/24 2001:db8:1234::10/64 fe80::5054:ff:fe12:3456/64
default via 203.0.113.1 dev eth0 proto static
default via 2001:db8:1234::1 dev eth0 proto static metric 1024 pref medium

Notice that proto dhcp became proto static. Next, test connectivity over both protocols, first to the gateway, then to the internet:

ping -c 3 203.0.113.1
ping -c 3 1.1.1.1
ping -6 -c 3 2606:4700:4700::1111

Each command should report 3 received and 0% packet loss. Then check DNS. On Ubuntu, name resolution goes through systemd-resolved, and /etc/resolv.conf points to a local stub at 127.0.0.53, so do not edit that file by hand. Check what the interface actually uses:

resolvectl dns eth0
resolvectl query dreamserver.ro

The first command should list the servers from your YAML; the second should return one or more addresses. Netplan also has a combined overview:

sudo netplan status

It shows each interface with its addresses, routes and DNS servers on one screen, which is handy when you come back to the server months later.

Finally, the real test: does the configuration survive a reboot? Keep the web console open in your browser, then:

sudo reboot

Reconnect after a minute and rerun the checks above. If everything is identical, cloud-init is not interfering and the configuration is persistent. Netplan changes themselves never need a reboot; we only do it once, to prove the setup holds.

Adding additional IPv4 and IPv6 addresses

Extra addresses are simply more entries in the addresses: list. Suppose you ordered a second IPv4 in the same subnet and want a second IPv6 for a separate website:

      addresses:
        - 203.0.113.10/24
        - 203.0.113.11/24
        - "2001:db8:1234::10/64"
        - "2001:db8:1234::11/64"

Use the same prefix as the main address when the extra IP is in the same subnet. If the provider gives you an IP from a different range, often as a /32 for IPv4 or as a separate routed subnet, write it with the prefix they specify. In most setups you do not need a second gateway for it, because the provider routes that address to your main one. With IPv6 you usually receive a whole /64, which contains far more addresses than you will ever use, so you can pick any free ones inside it.

After editing, repeat the same safe routine: sudo netplan generate, then sudo netplan try inside tmux, test from a second terminal, press Enter. Then confirm the new address answers, for example by pinging it from your own computer with ping 203.0.113.11 and, if your connection has IPv6, ping -6 2001:db8:1234::11.

Which address do outgoing connections use?

Incoming traffic can reach any address in the list. Outgoing connections, such as your server sending email or calling an API, normally leave from the first address of each family. You can check which source address the kernel picks:

ip route get 1.1.1.1
ip -6 route get 2606:4700:4700::1111

The src field in the output is the address that will be used. If a specific service must send from an extra IP, the cleanest solution is to configure that service to bind to it; most mail and web servers have such an option. Netplan can also set a preferred source with from: on a route, but for most readers binding in the application is easier to reason about and to debug.

Debian 13 and LXC containers: what is different

Netplan is the default on Ubuntu. On Debian 13, a system installed from the standard installer configures the network with ifupdown: the file is /etc/network/interfaces and the service is called networking, not systemd-networkd. Debian does package Netplan (netplan.io), and some Debian cloud images already use it. The quick test is the same on both: if ls /etc/netplan shows YAML files, this guide applies. On Debian, also check whether systemd-resolved is installed; if it is not, the nameservers: from Netplan do not reach /etc/resolv.conf, and you set DNS in that file directly.

If your Debian system uses ifupdown, the equivalent static configuration looks like this:

auto eth0
iface eth0 inet static
    address 203.0.113.10/24
    gateway 203.0.113.1

iface eth0 inet6 static
    address 2001:db8:1234::10/64
    gateway 2001:db8:1234::1

ifupdown has no built-in try, so build your own safety net in a tmux session before restarting the service:

sudo -i
cp -a /etc/network/interfaces /root/interfaces.bak
nano /etc/network/interfaces
(sleep 180 && cp -a /root/interfaces.bak /etc/network/interfaces && systemctl restart networking) &
systemctl restart networking

The line in parentheses schedules a revert in 180 seconds. If everything still works, cancel it with kill %1 and then exit. Restarting ifupdown does not always remove old addresses cleanly, so a reboot test with the console open is still a good idea.

LXC containers are a special case. In an LXC container, privileged or unprivileged, the network is configured by the host: the IP, gateway and DNS you see are written into the container by the virtualization platform, and changes made inside are usually overwritten at the next start. On an LXC VPS, change IPs from the provider panel or ask support, instead of editing Netplan inside the container. Everything in this tutorial targets KVM VPS, where you own the kernel and the network stack.

Troubleshooting: common mistakes

  • “Invalid YAML” or “expected mapping (check indentation)”: an indentation problem. Use spaces only, two per level, and make sure list items (- ) line up under their key.
  • “Permissions for /etc/netplan/10-static.yaml are too open”: run sudo chmod 600 /etc/netplan/*.yaml. It is only a warning, but fix it.
  • "gateway4 has been deprecated, use default routes instead": replace gateway4 / gateway6 with the routes: block shown in step 4.
  • “Conflicting default route declarations”: two files or two entries define a default route for the same family. Usually an old .yaml file is still in /etc/netplan/. Run sudo netplan get to see the merged configuration.
  • “Cannot call Open vSwitch: ovsdb-server.service is not running”: harmless on Ubuntu 24.04 when Open vSwitch is not installed. Ignore it.
  • Nothing changes after try or apply: the interface name in the YAML does not match the real one. Compare with ip -br link.
  • Works until reboot, then the old IP is back: cloud-init regenerated its file. Recheck step 3 and look for a freshly created 50-cloud-init.yaml.
  • After reboot the interface has a different name and no IP: the old file renamed the interface with match + set-name, and that block was dropped. Log in through the web console, add the block back, and apply.
  • IPv4 works, IPv6 does not: compare prefix and gateway with the provider’s values, then run ip -6 neigh to see whether the gateway answers. A gateway outside your subnet needs on-link: true; a fe80::1 gateway needs nothing special.
  • Ping by IP works, names do not: a DNS problem. Check resolvectl dns eth0; on Debian without systemd-resolved, check /etc/resolv.conf.
  • netplan try exits immediately: it needs an interactive terminal, so do not run it from a script or a cron job.

Security notes

  • More addresses, more exposure. Every service that listens on all addresses (0.0.0.0 or ::) is now reachable on the new IPv4 and IPv6 addresses too. List listeners with sudo ss -tulpn and make sure nothing is open that should not be.
  • Firewall IPv6 as well as IPv4. Many people secure IPv4 and forget IPv6 entirely. With ufw, check that IPV6=yes is set in /etc/default/ufw (the default on Ubuntu) so every rule applies to both. Also remember that ports published by Docker bypass ufw; bind them to 127.0.0.1 or to a specific address when they should not be public.
  • Only configure addresses assigned to you. Using an IP that belongs to someone else breaks their service and violates acceptable use rules; anti-spoofing filters on the provider side will drop that traffic anyway.
  • Set reverse DNS (PTR) for public-facing IPs, especially for mail servers, from the provider panel or through support.
  • Keep the console reachable. Make sure you know your panel password and that the web console works; it is the only door left if a network change goes wrong.
  • Keep file permissions at 600 for everything in /etc/netplan/.

So, ready to go static?

A static Netplan configuration is three short blocks of YAML: addresses, routes and nameservers. The real skill is applying it without drama: back up outside /etc/netplan/, tame cloud-init, validate with netplan generate, apply with netplan try inside tmux, test from a second session, and only then press Enter. Follow that routine and network changes stop being scary, even on a server hundreds of kilometres away.

If you need a server to practise on, you can spin up a VPS with IPv4 and IPv6 in our Romanian data center in a few minutes. And if you would rather have someone else handle IP planning, extra addresses, reverse DNS and firewalls, our server administration team does this every day.

FAQ

Do I need to reboot after changing Netplan?

No. netplan try or netplan apply activate the configuration immediately. We recommend a single reboot after a big change only to confirm the setup persists.

What is the difference between netplan try and netplan apply?

apply makes the change permanent right away. try applies it temporarily and reverts automatically unless you confirm within the timeout, which makes it the safe choice on remote servers.

Can I still use gateway4 and gateway6?

They still work on many versions, but they are deprecated and print warnings. Use routes: with to: default instead.

Which IPv6 prefix should I use, /64 or /128?

Use exactly what your provider specifies. Most VPS receive a /64, and each address from it is written with /64.

Does this work on Debian 13?

Only if the system uses Netplan (check with ls /etc/netplan). A standard Debian 13 install uses /etc/network/interfaces; see the Debian section above for the equivalent setup and a manual safety net.

Trusted By & Member Of

We are proud members of leading internet infrastructure organizations.

RIPE NCC MANRS PeeringDB RoTLD DSIX SBIX 4IXP LOCIX Euro-IX RIPE NCC MANRS PeeringDB RoTLD DSIX SBIX 4IXP LOCIX Euro-IX