Rclone automount all locally configured drives

Many of us, I’m sure, have quite a few remote cloud storage providers that we want to access. Rclone seems like the logical solution, however, the nix wiki article is somewhat lacking in detail, assuming that your dotfiles are only local. Many of us place them online, where the nix approach to configuring your mounts manually, therefore leaving the passwords in plaintext, is less than ideal. I wanted to be able to configure rclone easily on a device-by-device basis, while keeping my logins secure.

I feet, you might disagree, that the best way of doing this is to setup rclone remotes locally, using the normal approach for a regular linux distro, and then use nix to automatically mount them using a systemd service defined in home-manager.

The below is able to do this, just use rclone config in the terminal as you normally would to setup the shares, and then call reload-rclone to mount all your “drives”. The mount point will be ~/[remote-name], where [remote-name] is the name given to the remote when creating it. You can see the name of the remote using rclone listremotes and rename it using rclone config (Note: the colon after the name will be removed in the mount point name).

To do this, simply import the below file into your home.nix:

#rclone.nix
{config, pkgs, ...}:
{
  home={
    packages = [pkgs.rclone];
    shellAliases = {
      "reload-rclone"="systemctl --user restart rCloneMounts.service";
    };
  };

  systemd.user.services.rCloneMounts = {
    Unit = {
      Description = "Mount all rClone configurations";
      After = [ "network-online.target" ];
    };
    Service = let home = config.home.homeDirectory; in {
      Type = "forking";
      ExecStartPre = "${pkgs.writeShellScript "rClonePre" ''
      remotes=$(${pkgs.rclone}/bin/rclone --config=${home}/.config/rclone/rclone.conf listremotes)
      for remote in $remotes;
      do
      name=$(/usr/bin/env echo "$remote" | /usr/bin/env sed "s/://g")
      /usr/bin/env mkdir -p ${home}/"$name"
      done
      '' }";
      
      ExecStart = "${pkgs.writeShellScript "rCloneStart" ''
      remotes=$(${pkgs.rclone}/bin/rclone --config=${home}/.config/rclone/rclone.conf listremotes)
      for remote in $remotes;
      do
      name=$(/usr/bin/env echo "$remote" | /usr/bin/env sed "s/://g")
      ${pkgs.rclone}/bin/rclone --config=${home}/.config/rclone/rclone.conf --vfs-cache-mode writes --ignore-checksum mount "$remote" "$name" &
      done
      '' }";

      ExecStop = "${pkgs.writeShellScript "rCloneStop" ''
      remotes=$(${pkgs.rclone}/bin/rclone --config=${home}/.config/rclone/rclone.conf listremotes)
      for remote in $remotes;
      do
      name=$(/usr/bin/env echo "$remote" | /usr/bin/env sed "s/://g")
      /usr/bin/env fusermount -u ${home}/"$name"
      done
      '' }";
    };
    Install.WantedBy = [ "default.target" ];
  };
}

A similar approach can be used for declaratively defining rclone remotes, although I’d follow the wiki’s advice and write to a different file, e.g, if you’re using rclone-nix.conf instead of rclone.conf:

xdg.configFile."rclone/rclone-nix.conf".text = ''
  [fichier] ## This is your mountpoint, in this case: fichier
  type = fichier
  user = foo@bar.com
  pass = p4ssw0rd
'';

Replace all instances of rclone.conf in the above service with rclone-nix.conf.

2 Likes