Install Docker
sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
curl -sSL https://get.docker.com/ | CHANNEL=stable bash
Install Docker Compose
sudo apt install jq -y && \
DOCKER_COMPOSE_VERSION=$(curl --silent https://api.github.com/repos/docker/compose/releases/latest | jq .name -r) && \
DOCKER_CLI_PLUGIN_PATH=/usr/local/lib/docker/cli-plugins && \
sudo mkdir -p $DOCKER_CLI_PLUGIN_PATH && \
sudo curl -L "https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)" -o $DOCKER_CLI_PLUGIN_PATH/docker-compose && \
sudo chmod +x $DOCKER_CLI_PLUGIN_PATH/docker-compose
Create Macvlan Network (LAN)
A macvlan network allows Docker containers to appear as physical devices on the physical network with their own MAC and IP addresses.
To create a macvlan network, you need to know the network's subnets, gateways, and the physical network interface name of the host machine.
Method 1: How to find Network Variables Manually
- Find Network Interface Name:
Run:ip route show default
Look for the worddev. (e.g.,default via 192.168.1.1 dev enp87s0-> Your interface is enp87s0). - Find IPv4 Gateway:
Run:ip route show default
Look for the IP aftervia. (e.g.,192.168.1.1). - Find IPv4 Subnet:
Run:ip -o -f inet addr show <your_interface_name>
Look for the IP with the slash. Replace the last number with a0. (e.g.,192.168.1.95/24becomes 192.168.1.0/24). - Find IPv6 Subnet & Gateway:
Run:ip -o -f inet6 addr show <your_interface_name>
Look for the line that saysscope global. (e.g.,fdaa:bbcc:ddee::/64). Your gateway is usually your router's IP on that same subnet, ending in::1.
Manual Command Execution:
docker network create -d macvlan \
--ipv6 \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.2 \
--subnet=fdaa:bbcc:ddee::/64 \
--gateway=fdaa:bbcc:ddee::1 \
-o parent=enp87s0 \
LAN
Method 2: Automated Macvlan Script
Use this automated script to detect the network settings and generate a Macvlan network.
nano create_macvlan.sh
#!/bin/bash
set -euo pipefail
# ANSI Escape Code for Colors
reset="\033[0m"
bold="\033[1m"
blue_bg="\033[44m"
yellow_bg="\033[43m"
red_bg="\033[41m"
blue_fg_strong="\033[94m"
yellow_fg_strong="\033[93m"
red_fg_strong="\033[91m"
cyan_fg_strong="\033[96m"
# Function to log messages with timestamps and colors
log_message() {
current_time=$(date +'%H:%M:%S')
case "$1" in
"INFO") echo -e "${blue_bg}[$current_time]${reset} ${blue_fg_strong}[INFO]${reset} $2" ;;
"WARN") echo -e "${yellow_bg}[$current_time]${reset} ${yellow_fg_strong}[WARN]${reset} $2" ;;
"ERROR") echo -e "${red_bg}[$current_time]${reset} ${red_fg_strong}[ERROR]${reset} $2" ;;
"SUCCESS") echo -e "${blue_bg}[$current_time]${reset} \033[92m[SUCCESS]${reset} $2" ;;
*) echo -e "${blue_bg}[$current_time]${reset} ${blue_fg_strong}[DEBUG]${reset} $2" ;;
esac
}
# Ensure root privileges
if [[ $EUID -ne 0 ]]; then
log_message "ERROR" "This script must be run as root. (Use sudo)"
exit 1
fi
clear
echo -e "\033]0;Docker [MACVLAN CONFIGURATOR]\007"
echo -e "${blue_fg_strong}${bold}╔══════════════════════════════════════════════════════════════╗${reset}"
echo -e "${blue_fg_strong}${bold}║ DOCKER MACVLAN AUTO-CONFIGURATOR ║${reset}"
echo -e "${blue_fg_strong}${bold}╚══════════════════════════════════════════════════════════════╝${reset}"
echo
# 1. Ask for Network Name & Check if it exists
while true; do
read -p " Enter Network Name [LAN]: " NET_NAME
NET_NAME=${NET_NAME:-LAN}
if docker network ls --format '{{.Name}}' | grep -wq "^${NET_NAME}$"; then
echo
log_message "WARN" "A Docker network named '${NET_NAME}' already exists!"
echo -e "${cyan_fg_strong} _____________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| Menu Options: |${reset}"
echo -e " 1. ${red_fg_strong}DELETE${reset} existing '${NET_NAME}' and recreate it"
echo -e " 2. Choose a different network name"
echo -e " 0. Cancel and Exit"
echo -e "${cyan_fg_strong} _____________________________________________________________${reset}"
read -p " Choose an option: " subchoice
case $subchoice in
1)
log_message "INFO" "Removing existing network '${NET_NAME}'..."
docker network rm "$NET_NAME" || { log_message "ERROR" "Failed to remove network. Ensure containers are disconnected first."; exit 1; }
break
;;
2)
echo
continue
;;
0)
log_message "INFO" "Exiting."
exit 0
;;
*)
log_message "ERROR" "Invalid option."
continue
;;
esac
else
break
fi
done
echo
log_message "INFO" "Scanning system for network interfaces and routes..."
# 2. Auto-detect default interface
DEFAULT_IFACE=$(ip route show default | awk '/default/ {print $5}' | head -n 1)
read -p " Network Interface Name [$DEFAULT_IFACE]: " IFACE
IFACE=${IFACE:-$DEFAULT_IFACE}
# 3. Auto-detect IPv4 Gateway
DEFAULT_IPV4_GW=$(ip route show default | awk '/default/ {print $3}' | head -n 1)
read -p " IPv4 Gateway [$DEFAULT_IPV4_GW]: " IPV4_GW
IPV4_GW=${IPV4_GW:-$DEFAULT_IPV4_GW}
# 4. Auto-detect IPv4 Subnet
HOST_IPV4_CIDR=$(ip -o -f inet addr show $IFACE | awk '{print $4}' | head -n 1)
DEFAULT_IPV4_SUBNET=$(echo $HOST_IPV4_CIDR | awk -F. '{print $1"."$2"."$3".0/"$4}' | awk -F/ '{print $1"/"$3}')
read -p " IPv4 Subnet [$DEFAULT_IPV4_SUBNET]: " IPV4_SUBNET
IPV4_SUBNET=${IPV4_SUBNET:-$DEFAULT_IPV4_SUBNET}
# 5. Auto-detect IPv6 Subnet (Global or ULA, ignoring link-local fe80)
DEFAULT_IPV6_SUBNET=$(ip -o -f inet6 addr show $IFACE | awk '!/fe80/ {print $4}' | head -n 1 | awk -F: '{print $1":"$2":"$3":"$4"::/64"}')
if [ -z "$DEFAULT_IPV6_SUBNET" ]; then
DEFAULT_IPV6_SUBNET="Disabled"
fi
read -p " IPv6 Subnet (Leave blank or type 'Disabled' if none) [$DEFAULT_IPV6_SUBNET]: " IPV6_SUBNET
IPV6_SUBNET=${IPV6_SUBNET:-$DEFAULT_IPV6_SUBNET}
# 6. Guess IPv6 Gateway
if [[ "$IPV6_SUBNET" != "Disabled" ]] && [[ -n "$IPV6_SUBNET" ]]; then
DEFAULT_IPV6_GW=$(echo $IPV6_SUBNET | awk -F:: '{print $1"::1"}')
read -p " IPv6 Gateway [$DEFAULT_IPV6_GW]: " IPV6_GW
IPV6_GW=${IPV6_GW:-$DEFAULT_IPV6_GW}
fi
echo
echo -e "${cyan_fg_strong} _____________________________________________________________${reset}"
echo -e "${cyan_fg_strong}| OVERVIEW: Macvlan Creation Summary |${reset}"
echo -e " Network Name : ${yellow_fg_strong}${NET_NAME}${reset}"
echo -e " Interface : ${yellow_fg_strong}${IFACE}${reset}"
echo -e " IPv4 Subnet : ${yellow_fg_strong}${IPV4_SUBNET}${reset} via ${yellow_fg_strong}${IPV4_GW}${reset}"
if [[ "$IPV6_SUBNET" != "Disabled" ]] && [[ -n "$IPV6_SUBNET" ]]; then
echo -e " IPv6 Subnet : ${yellow_fg_strong}${IPV6_SUBNET}${reset} via ${yellow_fg_strong}${IPV6_GW}${reset}"
else
echo -e " IPv6 Subnet : ${red_fg_strong}Disabled${reset}"
fi
echo -e "${cyan_fg_strong} _____________________________________________________________${reset}"
echo
read -p " Does this look correct? [Y/N]: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
log_message "WARN" "Aborted by user."
exit 0
fi
log_message "INFO" "Creating Macvlan network '${NET_NAME}'..."
if [[ "$IPV6_SUBNET" != "Disabled" ]] && [[ -n "$IPV6_SUBNET" ]]; then
docker network create -d macvlan \
--ipv6 \
--subnet="$IPV4_SUBNET" \
--gateway="$IPV4_GW" \
--subnet="$IPV6_SUBNET" \
--gateway="$IPV6_GW" \
-o parent="$IFACE" \
"$NET_NAME"
else
docker network create -d macvlan \
--subnet="$IPV4_SUBNET" \
--gateway="$IPV4_GW" \
-o parent="$IFACE" \
"$NET_NAME"
fi
if [[ $? -eq 0 ]]; then
log_message "SUCCESS" "Macvlan network '${NET_NAME}' created successfully!"
echo
log_message "INFO" "Macvlan IPAM Configuration saved in Docker:"
docker network inspect "$NET_NAME" | jq '.[0].IPAM.Config'
else
log_message "ERROR" "Failed to create Macvlan network. Please check the Docker output above."
fi
echo
chmod +x create_macvlan.sh && ./create_macvlan.sh
IPv6 for Docker Macvlans (For Beginners)
When configuring a Macvlan, setting up IPv4 is easy (it’s usually 192.168.1.0/24). However, when you check your IPv6 settings, you will likely see a massive list of addresses.
How do you know which one to use for the Docker Macvlan?
The 3 Types of IPv6 Addresses
Unlike IPv4, a single device (like your PC or phone) usually has three different types of IPv6 addresses at the same time. You can identify them by looking at the first few letters/numbers:
-
Global Unicast Address (Starts with
2or3) - Avoid for Local DNS- Example:
2a02:f6e:c2ac::1585 - This is your Public IP Address assigned by your ISP.
- Why we don't use it: ISPs often use "Dynamic Prefixes." This means your ISP might change this address randomly (e.g., after a router reboot). If you assign this to your DNS server, and your ISP changes it, your entire network loses internet access.
- Example:
-
Link-Local Address (Starts with
fe80::) - Ignore- Example:
fe80::6f25:4498:aba5 - This is a self-assigned "survival" address. Devices use it to talk only to other devices physically plugged into the same switch. It cannot be routed across different network segments.
- Example:
-
Unique Local Address / ULA (Starts with
fdorfc) - USE THIS ONE!!- Example:
fdaa:bbcc:ddee::1c51 - This is the IPv6 exact equivalent of
192.168.x.x. - It is strictly for your private local network. It is static (it never changes), and it never routes out to the public internet.
- Why we use it: Because it never changes, it is perfect for static IP assignments, homelabs, and local DNS servers like Technitium or Pi-Hole!
- Example:
How to Find Your IPv6 Subnet
Now that you know you are looking for an address starting with fd or fc, here is how you find it.
Method 1: Look at your Router (Best Method)
Log into your ISP Modem or Main Router. Look for the "LAN" or "Local Network" settings. You should see a setting like:
LAN IPv6 Address: fdaa:bbcc:ddee:0000::1/64
Method 2: Use Windows Command Prompt
open CMD and type:
ipconfig /all
Look under your network adapter for an IPv6 address starting with fd:
IPv6 Address. . . . . : fdaa:bbcc:ddee:0:9474:8200:facd:1c51
Method 3: Use Linux Terminal
Open Terminal and type:
ip -o -f inet6 addr
Look for the fd address:
inet6 fdaa:bbcc:ddee:0:5a47:caff:fe76:9dd1/64 scope global
How to format a IPv6 Subnet for the Script
IPv6 addresses are made up of 8 blocks separated by colons (:).
In a standard home network (/64), the first 4 blocks belong to the Network, and the last 4 blocks belong to the specific device.
Take the address you found:
fdaa : bbcc : ddee : 0000 : 9474 : 8200 : facd : 1c51
- Keep the first 4 blocks:
fdaa:bbcc:ddee:0000 - (Optional) Drop repeating zeros:
fdaa:bbcc:ddee:0(or just leave them off entirely if it's the 4th block). - Replace the device blocks with
::/64:fdaa:bbcc:ddee::/64
The final Docker Macvlan Subnet is: fdaa:bbcc:ddee::/64
The Docker Gateway (usually ends in 1): fdaa:bbcc:ddee::1
Docker network template
Easily deploy a structured Docker network template. Create isolated networks for management, production, and more with predefined subnets and gateways. Use this simple script to streamline network setup. Ideal for enhancing security and organization in Docker projects.
nano create_docker_networks.sh
#!/bin/bash
# Create Docker networks
# Create network: management
# VLAN ID: 99
docker network create --subnet=10.99.0.0/16 --gateway=10.99.0.1 --ip-range=10.99.0.0/16 --driver=bridge --attachable=true management
# Create network: DMZ
# VLAN ID: 80
docker network create --subnet=10.0.80.0/24 --gateway=10.0.80.1 --ip-range=10.0.80.0/24 --driver=bridge --attachable=true dmz
# Create network: security
# VLAN ID: 70
docker network create --subnet=10.0.70.0/24 --gateway=10.0.70.1 --ip-range=10.0.70.0/24 --driver=bridge --attachable=true security
# Create network: DN42
# VLAN ID: 42
# OPTIONAL!!! visit https://dn42.eu/Home
docker network create --subnet=10.42.42.0/24 --gateway=10.42.42.1 --ip-range=10.42.42.0/24 --driver=bridge --attachable=true dn42
# Create network: media
# VLAN ID: 30
docker network create --subnet=10.0.30.0/24 --gateway=10.0.30.1 --ip-range=10.0.30.0/24 --driver=bridge --attachable=true media
# Create network: GameLAN
# VLAN ID: 31
docker network create --subnet=10.0.31.0/24 --gateway=10.0.31.1 --ip-range=10.0.31.0/24 --driver=bridge --attachable=true gamelan
# Create network: PBS iSCSI
# VLAN ID: 21
# Proxmox Backup Server (PBS) to manage data transfers over iSCSI.
docker network create --subnet=10.0.21.0/24 --gateway=10.0.21.1 --ip-range=10.0.21.0/24 --driver=bridge --attachable=true pbs
# Create network: production
docker network create --subnet=10.0.1.0/24 --gateway=10.0.1.1 --ip-range=10.0.1.0/24 --driver=bridge --attachable=true production
# Create network: voip
docker network create --subnet=10.0.4.0/24 --gateway=10.0.4.1 --ip-range=10.0.4.0/24 --driver=bridge --attachable=true voip
# Create network: backup
docker network create --subnet=10.0.5.0/24 --gateway=10.0.5.1 --ip-range=10.0.5.0/24 --driver=bridge --attachable=true backup
# Create network: staging
docker network create --subnet=10.0.6.0/24 --gateway=10.0.6.1 --ip-range=10.0.6.0/24 --driver=bridge --attachable=true staging
# Create network: IoT
# VLAN ID: 101
docker network create --subnet=10.0.101.0/24 --gateway=10.0.101.1 --ip-range=10.0.101.0/24 --driver=bridge --attachable=true iot
# Create network: guest
# VLAN ID: 199
docker network create --subnet=10.0.199.0/24 --gateway=10.0.199.1 --ip-range=10.0.199.0/24 --driver=bridge --attachable=true guest
chmod +x create_docker_networks.sh && ./create_docker_networks.sh