Why Bind Multiple IPv6 Addresses?
With IPv6, the address space is vast enough that a single server can easily be assigned hundreds or even thousands of unique addresses. There are several practical reasons to bind multiple IPv6 addresses to a single interface:
- Web hosting: Each website or virtual host can have its own dedicated IPv6 address for SSL/TLS (SNI notwithstanding, some legacy clients benefit from unique IPs).
- Mail servers: Outbound email systems use multiple IPs to distribute sending volume, manage reputation, and comply with rate limits imposed by receiving mail servers.
- Load balancing: Different services on the same server can bind to different IPv6 addresses for traffic separation and monitoring.
- Testing and development: Simulating multi-host environments on a single server for development or testing purposes.
Adding a Single IPv6 Address with ip
The ip command (from the iproute2 package) is the standard tool for network configuration on modern Linux systems. To add a single IPv6 address:
sudo ip -6 addr add 2001:db8::1/64 dev eth0
Verify it was added:
ip -6 addr show dev eth0
Output:
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP
inet6 2001:db8::1/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::1/64 scope link
valid_lft forever preferred_lft forever
To remove an address:
sudo ip -6 addr del 2001:db8::1/64 dev eth0
Addresses added with the ip command are temporary and will not survive a reboot. For persistent configuration, use Netplan or the interfaces file as described below.
Netplan Configuration (Ubuntu 18.04+)
Ubuntu 18.04 and later use Netplan as the default network configuration tool. Netplan uses YAML configuration files stored in /etc/netplan/.
Adding Multiple IPv6 Addresses
Edit your Netplan configuration file (typically /etc/netplan/01-netcfg.yaml or /etc/netplan/50-cloud-init.yaml):
network:
version: 2
renderer: networkd
ethernets:
eth0:
addresses:
- 203.0.113.10/24
- 2001:db8::1/64
- 2001:db8::2/64
- 2001:db8::3/64
- 2001:db8::4/64
- 2001:db8::5/64
gateway4: 203.0.113.1
gateway6: 2001:db8::ffff
nameservers:
addresses:
- 8.8.8.8
- 2001:4860:4860::8888
Apply the configuration:
sudo netplan apply
Verify all addresses are bound:
ip -6 addr show dev eth0 | grep "inet6 2001"
Adding a Large Range
For dozens of addresses, listing them individually in Netplan is tedious. You can generate the YAML programmatically with a script (see the bash script section below) and write the output into the Netplan file.
Legacy /etc/network/interfaces Method
On older Debian and Ubuntu systems (before 18.04) that use ifupdown, configure IPv6 addresses in /etc/network/interfaces:
# Primary interface
auto eth0
iface eth0 inet static
address 203.0.113.10
netmask 255.255.255.0
gateway 203.0.113.1
iface eth0 inet6 static
address 2001:db8::1
netmask 64
gateway 2001:db8::ffff
# Additional IPv6 addresses
iface eth0 inet6 static
address 2001:db8::2
netmask 64
iface eth0 inet6 static
address 2001:db8::3
netmask 64
Alternatively, use the up directive to run ip commands when the interface comes up:
auto eth0
iface eth0 inet6 static
address 2001:db8::1
netmask 64
gateway 2001:db8::ffff
up ip -6 addr add 2001:db8::2/64 dev eth0
up ip -6 addr add 2001:db8::3/64 dev eth0
up ip -6 addr add 2001:db8::4/64 dev eth0
up ip -6 addr add 2001:db8::5/64 dev eth0
down ip -6 addr del 2001:db8::2/64 dev eth0
down ip -6 addr del 2001:db8::3/64 dev eth0
down ip -6 addr del 2001:db8::4/64 dev eth0
down ip -6 addr del 2001:db8::5/64 dev eth0
Apply changes with:
sudo ifdown eth0 && sudo ifup eth0
Warning: If you are connected via SSH, running ifdown on your primary interface will disconnect you. Use a console session or wrap the command in a nohup with ifup chained immediately after.
Bash Script for Bulk Binding
When you need to bind dozens or hundreds of IPv6 addresses, a bash script is the most efficient approach:
#!/bin/bash
# bind-ipv6.sh - Bind a range of IPv6 addresses to an interface
INTERFACE="eth0"
PREFIX="2001:db8::"
SUBNET="/64"
START=1
END=100
echo "Binding IPv6 addresses $PREFIX$START through $PREFIX$END to $INTERFACE..."
for i in $(seq $START $END); do
HEX=$(printf '%x' $i)
sudo ip -6 addr add "${PREFIX}${HEX}${SUBNET}" dev "$INTERFACE"
if [ $? -eq 0 ]; then
echo " Added ${PREFIX}${HEX}${SUBNET}"
else
echo " FAILED: ${PREFIX}${HEX}${SUBNET}"
fi
done
echo "Done. $(ip -6 addr show dev $INTERFACE | grep -c 'inet6 2001') addresses bound."
Make it executable and run it:
chmod +x bind-ipv6.sh
sudo ./bind-ipv6.sh
Generating a Netplan File with a Script
For persistent binding, generate Netplan YAML:
#!/bin/bash
# generate-netplan-ipv6.sh
PREFIX="2001:db8::"
START=1
END=50
echo "network:"
echo " version: 2"
echo " ethernets:"
echo " eth0:"
echo " addresses:"
echo " - 203.0.113.10/24"
for i in $(seq $START $END); do
HEX=$(printf '%x' $i)
echo " - ${PREFIX}${HEX}/64"
done
echo " gateway4: 203.0.113.1"
echo " gateway6: ${PREFIX}ffff"
bash generate-netplan-ipv6.sh | sudo tee /etc/netplan/60-ipv6-addresses.yaml
sudo netplan apply
Verifying Bound Addresses
After binding, verify that all addresses are configured and reachable:
# List all IPv6 addresses on an interface
ip -6 addr show dev eth0
# Count bound addresses
ip -6 addr show dev eth0 | grep -c "inet6 2001"
# Test connectivity from a specific source address
ping6 -I 2001:db8::5 google.com
# Verify a specific address is bound
ip -6 addr show dev eth0 | grep "2001:db8::a"
Persistent Configuration Across Reboots
The ip -6 addr add command creates temporary bindings that do not survive a reboot. To make bindings persistent, you have three options:
- Netplan: The preferred method on Ubuntu 18.04+. Addresses in the YAML configuration are applied automatically on boot.
- /etc/network/interfaces: The preferred method on older Debian systems. Addresses are applied when the interface comes up.
- systemd-networkd .network file: Create a
.networkfile in/etc/systemd/network/with multiple[Address]sections. - rc.local or systemd service: Run the binding script at boot using
/etc/rc.localor a custom systemd service unit.
systemd-networkd Example
# /etc/systemd/network/10-eth0.network
[Match]
Name=eth0
[Network]
Address=203.0.113.10/24
Gateway=203.0.113.1
Address=2001:db8::1/64
Address=2001:db8::2/64
Address=2001:db8::3/64
Gateway=2001:db8::ffff
DNS=8.8.8.8
DNS=2001:4860:4860::8888
Common Issues
- Duplicate address detection (DAD): IPv6 uses DAD to check if an address is already in use on the network. If DAD fails, the address enters a "tentative" state and is not usable. Check for conflicts with
ip -6 addr showand look for addresses marked as "tentative". - Routing: Ensure your gateway and routing table are configured correctly for the IPv6 subnet. Use
ip -6 route showto verify. - Firewall: If you use UFW or iptables, make sure IPv6 rules are in place to allow traffic to the new addresses. Check our Linux security checklist for firewall configuration guidance.
- Kernel limits: While Linux supports a large number of addresses per interface, extremely large numbers (thousands) can increase memory usage and slow down address resolution.
Summary
Binding multiple IPv6 addresses to a Linux server is straightforward with the right tools. Use ip -6 addr add for quick temporary bindings, Netplan YAML for persistent configuration on modern Ubuntu, /etc/network/interfaces on legacy Debian systems, or bash scripts for bulk operations. Always verify bindings with ip -6 addr show and test connectivity from the new addresses. Whether you are setting up a mail server, web hosting environment, or load-balanced infrastructure, IPv6 gives you the address space to assign unique IPs to every service that needs one.
If deploying DNS filtering on IPv6 networks, see CleanBrowsing's IPv6 content filtering guide.