How To Mount S3 Object Storage in NixOS
I previously wrote about how I mounted s3 object storage to my homelab running Ubuntu. I've since been configuring my homelab to run using NixOS. NixOS has a major advantage over Ubuntu for me, in that the entire system is configured declaratively, meaning once you have a working configuration you can use it to rebuild everything exactly how it was setup before.
Updating NixOS Configuration
Whilst you could in theory install the required tools and manually mount an s3 object store in NixOS, a better approach is to specify mount instruction in the NixOS configuration file.
After a default install of NixOS the configuration file is available to edit at /etc/nixos/configuration.nix
, to mount an s3 bucket we will expand on the configuration.nix
by adding a new module
, called s3fs
. We will do this by importing a separate s3fs.nix
file, which we will create shortly, for now edit /etc/nixos/configuration.nix
and add the following:
# /etc/nixos/configuration.nix
{ config, pkgs, ... }:
{
imports = [
./hardware-configuration.nix # should be present by default
./modules/s3fs.nix
];
services.s3fs.enable = true;
}
Add Modules Directory
Next we need to create the modules folder and create the s3fs.nix
file:
sudo mkdir /etc/nixos/modules && sudo touch s3fs.nix
Add s3fs Module
Finally we can edit /etc/nixos/modules/s3fs.nix
and add the following:
# /etc/nixos/modules/s3fs.nix
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.s3fs;
in {
options.services.s3fs = {
enable = mkEnableOption "Mounts s3 object storage using s3fs";
keyPath = mkOption {
type = types.str;
default = "/etc/passwd-s3fs";
};
mountPath = mkOption {
type = types.str;
default = "/mnt/data";
};
bucket = mkOption {
type = types.str;
default = "data";
};
url = mkOption {
type = types.str;
default = "https://ap-south-1.linodeobjects.com/";
};
};
config = mkIf cfg.enable {
systemd.services.s3fs = {
description = "Linode object storage s3fs";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStartPre = [
"${pkgs.coreutils}/bin/mkdir -m 777 -pv ${cfg.mountPath}"
"${pkgs.e2fsprogs}/bin/chattr +i ${cfg.mountPath}" # stop files being written to unmounted dir
];
ExecStart = let
options = [
"passwd_file=${cfg.keyPath}"
"use_path_request_style"
"allow_other"
"url=${cfg.url}"
"umask=0000"
];
in
"${pkgs.s3fs}/bin/s3fs ${cfg.bucket} ${cfg.mountPath} -f "
+ lib.concatMapStringsSep " " (opt: "-o ${opt}") options;
ExecStopPost = "-${pkgs.fuse}/bin/fusermount -u ${cfg.mountPath}";
KillMode = "process";
Restart = "on-failure";
};
};
};
}
The above sets up a module for services.s3fs
, allowing us to enable/disable the service as well as edit the default settings. When enabled a systemd
service is created which mounts the s3 bucket, making it available at the specified path (/mnt/data
by default).
The service will look for a file containing an access and API key by default in /etc/passwd-s3fs
, before running the service you will need to run the following to configure authentication details:
echo "ACCESS_KEY:SECRET_KEY" | sudo tee /etc/passwd-s3fs
sudo chmod 600 /etc/passwd-s3fs
Note: I recently ran into an issue when setting this up and had to comment out "${pkgs.e2fsprogs}/bin/chattr +i ${cfg.mountPath}"
to resolve the issue. I'll update if I figure out a solution. For now everything is working without it.
Much of the credit for this post goes to a forum post on the NixOS Discourse.