{"id":2553,"date":"2025-10-26T15:57:43","date_gmt":"2025-10-26T19:57:43","guid":{"rendered":"https:\/\/lowtek.ca\/roo\/?p=2553"},"modified":"2025-10-26T20:02:27","modified_gmt":"2025-10-27T00:02:27","slug":"nixos-docker-with-macvlan-ipv4","status":"publish","type":"post","link":"https:\/\/lowtek.ca\/roo\/2025\/nixos-docker-with-macvlan-ipv4\/","title":{"rendered":"NixOS + Docker with MacVLAN (IPv4)"},"content":{"rendered":"<p>I continue to make use of the <a href=\"https:\/\/docs.docker.com\/engine\/network\/drivers\/macvlan\/\">docker macvlan<\/a> network support as it allows me to treat some of my <a href=\"https:\/\/en.wikipedia.org\/wiki\/Docker_(software)\">containers<\/a> as if they are <a href=\"https:\/\/en.wikipedia.org\/wiki\/Virtual_machine\">virtual machines<\/a> (VMs). Using this feature I can assign an IP address that is distinct from my host, but is still just a container running on the host. I&#8217;ve written about <a href=\"https:\/\/lowtek.ca\/roo\/2020\/docker-and-macvlan-networking-ipv4\/\">creating one<\/a>, and <a href=\"https:\/\/lowtek.ca\/roo\/2023\/expanding-a-docker-macvlan-network\/\">expanding it<\/a>.<\/p>\n<p>As I&#8217;m now building out a new server and have selected <a href=\"https:\/\/nixos.org\/\">NixOS<\/a> as my base, I need to make some changes to how I&#8217;ve setup the docker macvlan. This blog post captures those changes.<\/p>\n<p>While NixOS supports the <a href=\"https:\/\/nix.dev\/tutorials\/nixos\/building-and-running-docker-images.html\">declaration of containers<\/a>, I&#8217;m not doing that right now by choice. It&#8217;ll make my migration easier and I can always go back and refactor. Thus there are just two things I need to include in my NixOS configuration:<\/p>\n<ol>\n<li>Enable docker support<\/li>\n<li>Modify the host network to route to the macvlan network<\/li>\n<\/ol>\n<p>The first (enable docker support) is so very easy with NixOS. You need a single line added to your <code>\/etc\/nixos\/configuration.nix<\/code><\/p>\n<pre class=\"lang:default decode:true \">virtualisation.docker.enable = true;<\/pre>\n<p>You probably want to modify your user to be in the &#8220;docker&#8221; group allowing direct access to docker commands vs. needing to <code>sudo<\/code> each time.<\/p>\n<p>There is a third thing we need to do, create the docker macvlan network. I don&#8217;t have this baked into my NixOS configuration because I was too lazy to write an idempotent version of doing it and figuring out where in the start up sequence to make it run. This turns out to be just a one line script:<\/p>\n<pre class=\"lang:default decode:true \">$ docker network create -d macvlan -o parent=enp3s0 \\\r\n  --subnet 192.168.1.0\/24 \\\r\n  --gateway 192.168.1.1 \\\r\n  --ip-range 192.168.1.64\/30 \\\r\n  --aux-address 'host=192.168.1.67' \\\r\n  myNewNet<\/pre>\n<p>Docker will persist this network configuration across reboots.<\/p>\n<p>If you stop here, you will be able to create containers with their own IP address. I pass along these two docker command line options to create a container with it&#8217;s own IP:<\/p>\n<pre class=\"lang:default decode:true\"> --network myNewNet \\\r\n --ip 192.168.1.64 \\\r\n<\/pre>\n<p>The docker macvlan network I&#8217;ve defined has 4 IPs reserved, but you can specify a larger <code>ip-range<\/code> if you want when you create the docker mavlan network.<\/p>\n<p>However, if you did stop here, you would not be able to reach the container running on <code>192.168.1.64<\/code> from the host. This is the second change to our Nix configuration (modify the host network to route to the macvlan network). In my <a href=\"https:\/\/lowtek.ca\/roo\/2020\/docker-and-macvlan-networking-ipv4\/\">original post<\/a> I used a script to create the route from host to container, as this wasn&#8217;t persistent I needed to run that script after every boot.<\/p>\n<p>One way to do a similar thing in NixOS is to create a <a href=\"https:\/\/wiki.nixos.org\/wiki\/Systemd\/User_Services\">systemd service<\/a>. I was exploring this and did <a href=\"https:\/\/discourse.nixos.org\/t\/help-network-magic-on-boot-or-systemd-one-time-script-docker-macvlan\/71333\/2?u=roo\">figure it out<\/a>. However, I was wrong in my approach. While this worked, it wasn&#8217;t the best way to do it. NixOS has <code>networking.macvlans<\/code> which is a more NixOS-y way to solve the problem. The <a href=\"https:\/\/discourse.nixos.org\/t\/help-network-magic-on-boot-or-systemd-one-time-script-docker-macvlan\/71333\/11?u=roo\">very helpful community<\/a> helped me discover this.<\/p>\n<pre class=\"lang:default decode:true \">{\r\n  networking.macvlans.\"myNewNet-shim\" = {\r\n    mode = \"bridge\";\r\n    interface = \"enp3s0\";\r\n  };\r\n\r\n  networking.interfaces.\"myNewNet-shim\".ipv4 = {\r\n    addresses = [{ address = \"192.168.1.67\"; prefixLength = 32; }];\r\n    routes = [{ address = \"192.168.1.64\"; prefixLength = 30; }];\r\n  };\r\n\r\n}<\/pre>\n<p>If you dig into the implementation (<a href=\"https:\/\/github.com\/NixOS\/nixpkgs\/blob\/8751081b87e503cb863b2018586c5f5022362975\/nixos\/modules\/tasks\/network-interfaces-scripted.nix#L559\">createMacvlanDevice<\/a>, <a href=\"https:\/\/github.com\/NixOS\/nixpkgs\/blob\/8751081b87e503cb863b2018586c5f5022362975\/nixos\/modules\/tasks\/network-interfaces-scripted.nix#L218\">configureAddrs<\/a>), you can get some insight into how this maps onto basically the same thing my boot time script did.<\/p>\n<p>This feels a lot less of a hack than using a script. Both work, but using the <code>networking.macvlans<\/code> approach is nice and clean. I should probably do the work to declare the docker macvlan inside my NixOS configuration to make this complete, but that&#8217;s a task for another day.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I continue to make use of the docker macvlan network support as it allows me to treat some of my containers as if they are virtual machines (VMs). Using this feature I can assign an IP address that is distinct from my host, but is still just a container running on the host. I&#8217;ve written &hellip; <a href=\"https:\/\/lowtek.ca\/roo\/2025\/nixos-docker-with-macvlan-ipv4\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;NixOS + Docker with MacVLAN (IPv4)&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,12],"tags":[],"class_list":["post-2553","post","type-post","status-publish","format-standard","hentry","category-computing","category-how-to"],"_links":{"self":[{"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/posts\/2553","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/comments?post=2553"}],"version-history":[{"count":4,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/posts\/2553\/revisions"}],"predecessor-version":[{"id":2557,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/posts\/2553\/revisions\/2557"}],"wp:attachment":[{"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/media?parent=2553"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/categories?post=2553"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lowtek.ca\/roo\/wp-json\/wp\/v2\/tags?post=2553"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}