vagrant-docker-networks-manager
Vagrant plugin to manage Docker networks with labeled ownership, safe lifecycle hooks, JSON output, and conflict-aware validation.
- Creates a Docker network on
vagrant up(with labels & marker) - Cleans it on
vagrant destroyonly if owned by this machine (safe) vagrant networkCLI:init | destroy | info | reload | list | prune | rename- IPv4/CIDR validation, subnet conflict detection, optional macvlan
- i18n (English 🇬🇧 / Français 🇫🇷), emojis, and normalized JSON output
Requirements: Vagrant ≥ 2.2, Ruby ≥ 3.1, Docker (CLI + daemon) running
Table of contents
- Why this plugin?
- Installation
- Quick start
- Vagrantfile configuration
- CLI usage
- JSON output examples
- Ownership & safety
- Subnet validation & conflicts
- Internationalization
- Environment variables
- Permissions & OS notes
- Troubleshooting
- Contributing & Development
- License
🇫🇷 Français : voir README.fr.md
Why this plugin?
Managing Docker networks across Vagrant projects is tedious:
- naming consistency, subnet overlaps, and safe cleanup are error-prone
- destroying a VM shouldn’t delete someone else’s shared network
- operators need deterministic CLI and machine-readable output
This plugin solves these by labeling networks, keeping a marker per machine, validating CIDR + detecting overlaps, and offering a clean CLI with JSON output.
Installation
From RubyGems (once published):
vagrant plugin install vagrant-docker-networks-manager
From source (local path):
git clone https://github.com/julienpoirou/vagrant-docker-networks-manager
cd vagrant-docker-networks-manager
bundle install
rake
vagrant plugin install . # install from the local gemspec
Check it’s available:
vagrant network version
vagrant network help
Quick start
Minimal Vagrantfile
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/ubuntu-22.04"
# Docker network plugin config
config.docker_network.network_name = "myproj_net" # ⚠️ personalize to avoid collisions
config.docker_network.network_subnet = "172.28.50.0/24"
config.docker_network.network_gateway = "172.28.50.1"
config.docker_network.network_type = "bridge" # or "macvlan"
config.docker_network.network_parent = nil # required if macvlan
config.docker_network.network_attachable = true
config.docker_network.enable_ipv6 = false
config.docker_network.ip_range = nil # optional
config.docker_network.cleanup_on_destroy = true
config.docker_network.locale = "en" # "en" or "fr"
end
Create the network on up
vagrant up
If a network with the same name already exists:
- if it’s owned by this machine (labels match), it’s “adopted”
- otherwise you simply get an info message (no destructive action)
Destroy VM and clean the network
vagrant destroy
- The network is removed only if created/owned by this machine.
- To also remove attached containers during Vagrant destroy:
VDNM_DESTROY_WITH_CONTAINERS=1 vagrant destroy
Vagrantfile configuration
All options (with defaults):
| Key | Type | Default | Notes |
|---|---|---|---|
network_name |
String | "network_lo1" |
⚠️ Personalize to avoid collisions across projects. |
network_subnet |
String | "172.28.100.0/26" |
Must be aligned IPv4/CIDR (e.g. x.y.z.0/nn). |
network_type |
String | "bridge" |
"bridge" or "macvlan". |
network_gateway |
String | "172.28.100.1" |
Must be a host address inside network_subnet. |
network_parent |
String | nil |
Required if network_type == "macvlan". |
network_attachable |
Bool | false |
Adds --attachable. |
enable_ipv6 |
Bool | false |
Adds --ipv6. |
ip_range |
String | nil |
IPv4/CIDR inside network_subnet. |
cleanup_on_destroy |
Bool | true |
Remove network on vagrant destroy if owned/created. |
locale |
String | "en" |
"en" or "fr". |
Validation performed:
- Docker name constraints, aligned IPv4/CIDR,
gatewaynot network/broadcast ip_rangemust be included innetwork_subnetmacvlanrequiresnetwork_parent
CLI usage
vagrant network <command> [args] []
Commands:
init <name> <subnet>
destroy <name> [--with-containers] [--yes]
reload <name> [--yes]
info <name>
list [--json]
prune [--yes]
rename <old> <new> [<subnet>] [--yes]
version
Global options:
--json # machine-readable output
--yes, -y # auto-confirm prompts
--quiet # reduce output (hide info)
--no-emoji # disable emojis
--lang en|fr # force language
Examples:
vagrant network init mynet 172.28.100.0/26
vagrant network info mynet
vagrant network list
vagrant network destroy mynet --with-containers --yes
vagrant network reload mynet --yes
vagrant network rename oldnet newnet --yes
vagrant network rename oldnet same-name 10.10.0.0/24 --yes
vagrant network prune --yes
JSON output examples
Enable with --json for any command.
init
{"action":"init","status":"success","data":{"name":"mynet","subnet":"172.28.100.0/26"}}
info
{
"action":"info",
"status":"success",
"data":{
"network":{
"Name":"mynet",
"Id":"...docker-id...",
"Driver":"bridge",
"Subnets":["172.28.100.0/26"],
"Containers":[{"Name":"web","IPv4":"172.28.100.2/26"}]
}
}
}
prune (nothing to do)
{"action":"prune","status":"success","data":{"pruned":0,"items":[]}}
Errors are normalized:
{"action":"destroy","status":"error","error":"Network not found.","data":{"name":"ghost"}, "code":1}
Ownership & safety
- Networks are created with labels:
com.vagrant.plugin=docker_networks_managercom.vagrant.machine_id=<VAGRANT_MACHINE_ID>
- A marker file is also written in:
.vagrant/machines/<name>/<provider>/docker-networks/<network>.json
On vagrant destroy, the plugin only removes a network if:
- the marker indicates it was created by this machine, or
- labels match this machine’s id (ownership)
If a network exists but is not owned, the plugin leaves it untouched.
Subnet validation & conflicts
Before creating (or renaming to a new subnet), the plugin:
- Validates
network_subnetis an aligned IPv4/CIDR
(e.g.172.28.100.0/24, not172.28.100.1/24) - Scans existing Docker networks and checks for overlaps
(ignoring the target network when appropriate)
This prevents hard-to-debug IP conflicts.
Internationalization
- Locales: en, fr
- Choose via CLI
--lang en|fr, or setlocalein your Vagrantfile, orVDNM_LANG=en|fr.
Emojis can be disabled with --no-emoji.
Environment variables
| Variable | Purpose |
|---|---|
VDNM_LANG |
Force locale (en/fr) in hooks. |
VDNM_VERBOSE |
When 1, prints the full docker command on STDERR and shows the native Docker output. |
VDNM_SKIP_CONFLICTS |
When 1, the reload ignores subnet conflict detection (dangerous, for experts only). |
VDNM_DESTROY_WITH_CONTAINERS |
When 1, on Vagrant destroy the plugin also runs docker rm -f for attached containers (in addition to disconnect). |
The CLI
vagrant network destroy <name> --with-containersachieves the same for the manual command.
Permissions & OS notes
- Linux / macOS: modifying
/etc/hostsrequires privileges. The plugin pipes throughsudo tee -awhen appending, and writes the file when removing. You may be prompted for your password. - Windows: the plugin uses PowerShell elevation (
Start-Process -Verb RunAs) when needed to append or rewrite the hosts file.
If your shell is already elevated (root/Admin), no prompts appear.
Troubleshooting
- Docker is unavailable: ensure Docker Desktop/daemon is running and the CLI works (
docker info). - Invalid subnet: use aligned IPv4/CIDR (e.g.
10.0.0.0/24). - Subnet already in use: another network overlaps. Pick a different range.
- Remove failed: some containers or other constraints may block
docker network rm. Try--verbose(VDNM_VERBOSE=1) to see Docker’s output. - macvlan: remember to set
network_parent(host interface).
Contributing & Development
git clone https://github.com/julienpoirou/vagrant-docker-networks-manager
cd vagrant-docker-networks-manager
bundle install
rake # runs RSpec
- Conventional Commits enforced in PRs.
- CI runs RuboCop, tests, and builds the gem.
- See
docs/en/CONTRIBUTING.mdanddocs/en/DEVELOPMENT.mdif present.
License
MIT © 2025 Julien Poirou
Tip: prefer setting a project-specific
network_name(e.g.myapp_net) to avoid collisions if multiple Vagrant projects run on the same host.