Rootless Docker broken; Unit docker.service not found

Hi, I’m attempting to use Docker in rootless mode with the following in my configuration.nix:

virtualisation.docker = {
  enable = false;

  rootless = {
    enable = true;
    setSocketVariable = true;
  };
};

When running systemctl status docker the output is Unit docker.service could not be found, as expected as I have disabled the system wide Docker daemon.

The problem is, systemctl --user status docker returns the same thing. It was returning the same thing before I tried setting virtualisation.docker.enable to false, too. systemctl --user start docker and systemctl --user enable --now docker both return Failed to start docker.service: Unit docker.service not found.

I have turned my machine off and on again after each tweak to my config and switched without any issues (tried switching with compilation error as a sanity check, everything worked as expected).

So far, the farthest I’ve gotten has just been communicating with the system wide daemon when I had it enabled before.

I am on nixpkgs version 25.05.

What do you expect?

You are telling NixOS, I do not want to have Docker, but if I ever change my mind, it should be rootless.

Hi, the issue was happening the exact same way when I had that option set to true (then I started following the example from here Docker - NixOS Wiki)

Okay, I checked the implementation of the module, and the way it is implemented is counterintuitive to be honest…

Anyway, given that virtualisation.docker.rootless.enable = true docker.service should exist as a user unit and systemctl --user enable docker.service should find it, if you have reloaded the deamon or did a reboot.

If it really doesn’t work, please ensure that you have the file with the options actually imported correctly.

If you think it is, but it still doesn’t work, please share your config as a whole.

I can only imagine that you’re right and I am importing the options wrong somehow, I’ll include the bits of my configuration that seem relevant because I don’t really want to go through the trouble of anonymizing thoroughly ATM

# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).

{ config, lib, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  # Bootloader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;
...


  virtualisation.docker = {
    enable = false;
    
    rootless = {
      enable = true;
      setSocketVariable = true;
    };
 
    # ignore this, just some random thing I tried
    daemon.settings = {
      userland-proxy = false;
    };
  };
...
  # Allow unfree packages
  nixpkgs.config.allowUnfree = true;
  nixpkgs.config.permittedInsecurePackages = [
    "electron-33.4.11"
  ];

Nothing else in my configuration pertains to virtualisation.

I get a feeling it might somehow be related to when I updated to 25.05, so here’s my output from nix-channel list:

nixos https://nixos.org/channels/nixos-24.11
nixos-25.05 https://nixos.org/channels/nixos-25.05
nixos-hardware https://github.com/NixOS/nixos-hardware/archive/master.tar.gz

Unrelated: if you are building your system without explicitly pointing to the nixos-25.05 channel you may be still on 24.11, what does nixos-version return?

Oh you are absolutely right, I was still on 24.11. I’m updating everything right now, about to feel very silly if this was the problem.

Edit: was not. Still appreciate the heads up!

What’s the output of sudo nix-channel --list?

After going back and updating it:

nixos https://nixos.org/channels/nixos-25.05
nixos-hardware https://github.com/NixOS/nixos-hardware/archive/master.tar.gz

I updated my system with sudo nix-channel --update then sudo nixos-rebuild switch --upgrade and it has not changed the Docker daemon behavior after rebooting.

Here’s my minimum reproduction of the configuration you shared:

{
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";

  outputs =
    { nixpkgs, ... }:
    {
      nixosConfigurations.test = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          {
            users.users.test = {
              password = "insecure";
              isNormalUser = true;
            };

            virtualisation.docker = {
              enable = false;

              rootless = {
                enable = true;
                setSocketVariable = true;
              };

              # ignore this, just some random thing I tried
              daemon.settings = {
                userland-proxy = false;
              };
            };
          }
        ];
      };
    };
}

Unfortunately that configuration does install the docker service correctly in a VM - I can log in as test and systemctl --user status docker shows a running service. Your other configuration is doing something, we can’t really tell you what that something is without knowing what your configuration is.

If you’d like help but can’t share your configuration, you can try to produce a proper minimal reproduction of your issue with a little ad-hoc flake like that. You can build the VM with nixos-rebuild build-vm --flake .#test and then start it with ./result/bin/run-nixos-vm.

But as-is, guessing what your other configuration might be doing wrong (or correctly to trigger a NixOS bug) is kind of hard.

2 Likes

I’m completely at a loss here. I copied my entire configuration.nix into a vm, built it, ran it, and the docker daemon is actually working inside of it. systemctl --user status docker returns the expected output with all the information about Docker running rootless.

Here’s the flake I used:

{

    inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
    outputs = 
        {nixpkgs, ...}:
    {
        nixosConfigurations.test = nixpkgs.lib.nixosSystem {
            system = "x86_64-linux";
            modules = [
                ({config, lib, pkgs, ... }:
                {
                    # Bootloader.
                    boot.loader.systemd-boot.enable = true;
                    boot.loader.efi.canTouchEfiVariables = true;

                    networking.hostName = "nixos"; # Define your hostname.
                    # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.

                    # Configure network proxy if necessary
                    # networking.proxy.default = "http://user:password@proxy:port/";
                    # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";

                    # Enable networking
                    networking.networkmanager.enable = true;

                    # Set your time zone.
                    time.timeZone = [redacted]

                    # Select internationalisation properties.
                    i18n.defaultLocale = [redacted]

                    i18n.extraLocaleSettings = {
                    [redacted]
                    };

                    # Enable the X11 windowing system.
                    services.xserver.enable = true;

                    services.xserver.videoDrivers = ["nvidia"];

                    # Enable the GNOME Desktop Environment.
                    services.xserver.displayManager.gdm.enable = true;
                    services.xserver.desktopManager.gnome.enable = true;

                    # Configure keymap in X11
                    services.xserver.xkb = {
                        layout = "us";
                        variant = "";
                    };

                    # Enable CUPS to print documents.
                    services.printing.enable = true;

                    # Pulse Audio
                    #  services.pipewire.enable = false;
                    #  hardware.pulseaudio = {
                    #    enable = true;
                    #    support32Bit = true;
                    #  };

                    # Enable sound with pipewire.
                    services.pulseaudio.enable = false;
                    security.rtkit.enable = true;
                    services.pipewire = {
                        enable = true;
                        alsa.enable = true;
                        alsa.support32Bit = true;
                        pulse.enable = true;
                        #  If you want to use JACK applications, uncomment this
                        jack.enable = true;

                        # use the example session manager (no others are packaged yet so this is enabled by default,
                        # no need to redefine it in your config for now)
                        #media-session.enable = true;
                    };

                    # Enable touchpad support (enabled default in most desktopManager).
                    # services.xserver.libinput.enable = true;

                    # Define a user account. Don't forget to set a password with ‘passwd’.
                    users.users.test = {
                        isNormalUser = true;
                        password = "insecure";
                        extraGroups = [ "networkmanager" "wheel" "scanner" "lp" "audio" ];
                        packages = with pkgs; [
                        #  thunderbird
                        discord
                        calibre
                        obsidian
                        libreoffice
                        gimp
                        prismlauncher
                        spotify
                        gnomeExtensions.mute-spotify-ads
                        crawlTiles
                        stremio
                        heroic-unwrapped
                        qbittorrent
                        protonup
                        wine64
                        protontricks
                        blender
                        yt-dlp
                        r2modman
                        ];
                    };

                    # Install firefox.
                    programs.firefox.enable = true;
                    programs.direnv.enable = true;

                    virtualisation.docker = {
                        enable = false;
                        
                        rootless = {
                        enable = true;
                        setSocketVariable = true;
                        };
                    
                        daemon.settings = {
                        userland-proxy = false;
                        };
                    };

                    # Allow unfree packages
                    nixpkgs.config.allowUnfree = true;
                    nixpkgs.config.permittedInsecurePackages = [
                        "electron-33.4.11"
                    ];


                    # List packages installed in system profile. To search, run:
                    # $ nix search wget
                    environment.systemPackages = with pkgs; [
                    #  vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
                    #  wget
                        gnome-terminal
                        nvidia-vaapi-driver
                        (vscode-with-extensions.override {
                            vscodeExtensions = with vscode-extensions; [
                                ms-python.python
                                ms-python.debugpy
                                ms-azuretools.vscode-docker
                                github.vscode-pull-request-github
                                eamodio.gitlens
                            mkhl.direnv
                            ];
                        })
                        git
                        python3
                        hplip
                        valent
                        kdePackages.kdenlive
                    ];

                    # Steam
                    programs.steam.enable = true;
                    # Some programs need SUID wrappers, can be configured further or are
                    # started in user sessions.
                    # programs.mtr.enable = true;
                    # programs.gnupg.agent = {
                    #   enable = true;
                    #   enableSSHSupport = true;
                    # };

                    # List services that you want to enable:

                    # Enable the OpenSSH daemon.
                    # services.openssh.enable = true;

                    # Open ports in the firewall.
                    # networking.firewall.allowedTCPPorts = [ ... ];
                    # networking.firewall.allowedUDPPorts = [ ... ];
                    # Or disable the firewall altogether.
                    # networking.firewall.enable = false;

                    # This value determines the NixOS release from which the default
                    # settings for stateful data, like file locations and database versions
                    # on your system were taken. It‘s perfectly fine and recommended to leave
                    # this value at the release version of the first install of this system.
                    # Before changing this value read the documentation for this option
                    # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
                    system.stateVersion = "24.11"; # Did you read the comment?

                    # OpenGL
                    programs.gamemode.enable = true;
                    hardware.graphics = {
                        enable = true;
                        # driSupport32Bit = true;
                    };
                    hardware.sane.enable = true;
                    hardware.sane.extraBackends = [ pkgs.hplip ];

                    hardware.nvidia = {
                        modesetting.enable = true;
                        open = false;
                        nvidiaSettings = true;
                        package = config.boot.kernelPackages.nvidiaPackages.latest;
                    };

                    powerManagement.enable = true;
                })
            ];
        };
    };


}

Update: I think the problem lies somewhere in systemd, but I am honestly out of my depth as to what could have caused this. Any help with debugging is appreciated.

/etc/systemd/user/docker.service definitely exists as a file. I ran the command under ExecStart, which was /nix/store/fwvljmyvnkp04s3icjkrfzy2ljvs4l00-docker-27.5.1/bin/dockerd-rootless --config-file=/nix/store/yx9ksz00s1il3lrj02b 6rhg7ffja8np4-daemon.json. This started the rootless Docker service just fine and I was able to connect to it from my IDE.

So somewhere along the line, systemd has lost the ability to see the docker.service unit, despite it being located in the right place.

Edit:
Output of ls -lrt /etc/systemd/user/docker.service:
lrwxrwxrwx 1 root root 78 Dec 31 1969 /etc/systemd/user/docker.service -> /nix/store/id55ykzg2c9ifc1h6h5b9yp39kdhg9lr-unit-docker.service/docker.service

Edit:
I have fixed the problem. At some point, I ran sudo nix-collect-garbage -d and it deleted some files that the docker systemd service needed, but it did not delete links that were in my ~/.config/systemd/user directory. I deleted the invalid links and it all seems to be working now. If someone knows how this could’ve happened, if it was a bug or a mistake on my part, I’d appreciate it!

Those would not have been created by NixOS; NixOS doesn’t touch $HOME. User units are created in the global paths.

You can make systemd create files with enable, mask, edit, etc. My guess would be that you ran some of these commands on accident at some point, and that with the next update that changed the path to the units in /nix/store suddenly the underlying service file disappeared, resulting in systemd seeing a broken symlink when trying to access the unit, which would override the system-wide unit but not actually work.

I think mask is the most likely culprit, though I don’t know why you woul have masked a unit either.

I did run systemd enable, the wiki entry at Docker - NixOS Wiki says to run this command: $ systemctl --user enable --now docker to enable Docker (which I didn’t run after fixing things, so it appears that it is not actually necessary, and probably shouldn’t be there as a part of the instructions)

Is it correct behavior for the Nix garbage collector to delete objects in /nix/store that still have links to them? I was under the impression it wouldn’t do that.

Yes, if they weren’t created by nix. It’s actually files with symlinks in /nix/var/gcroots that aren’t deleted.

Yeah, that wiki entry is actively misleading. Use the official wiki, the unofficial one is mostly bitrotting: Docker - NixOS Wiki

1 Like