diff --git a/users/modules/containers.nix b/users/modules/containers.nix
new file mode 100644
index 0000000..fccc606
--- /dev/null
+++ b/users/modules/containers.nix
@@ -0,0 +1,123 @@
+{ config, lib, pkgs, ... }:
+let
+ cfg = config.virtualisation.containers;
+
+ inherit (lib) mkOption types;
+
+ toml = pkgs.formats.toml { };
+in
+{
+ options.virtualisation.containers = {
+
+ enable =
+ mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ This option enables the common /etc/containers configuration module.
+ '';
+ };
+
+ ociSeccompBpfHook.enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Enable the OCI seccomp BPF hook";
+ };
+
+ containersConf.settings = mkOption {
+ type = toml.type;
+ default = { };
+ description = "containers.conf configuration";
+ };
+
+ containersConf.cniPlugins = mkOption {
+ type = types.listOf types.package;
+ defaultText = ''
+ [
+ pkgs.cni-plugins
+ ]
+ '';
+ example = lib.literalExample ''
+ [
+ pkgs.cniPlugins.dnsname
+ ]
+ '';
+ description = ''
+ CNI plugins to install on the system.
+ '';
+ };
+
+ registries = {
+ search = mkOption {
+ type = types.listOf types.str;
+ default = [ "docker.io" "quay.io" ];
+ description = ''
+ List of repositories to search.
+ '';
+ };
+
+ insecure = mkOption {
+ default = [];
+ type = types.listOf types.str;
+ description = ''
+ List of insecure repositories.
+ '';
+ };
+
+ block = mkOption {
+ default = [];
+ type = types.listOf types.str;
+ description = ''
+ List of blocked repositories.
+ '';
+ };
+ };
+
+ policy = mkOption {
+ default = {};
+ type = types.attrs;
+ example = lib.literalExample ''
+ {
+ default = [ { type = "insecureAcceptAnything"; } ];
+ transports = {
+ docker-daemon = {
+ "" = [ { type = "insecureAcceptAnything"; } ];
+ };
+ };
+ }
+ '';
+ description = ''
+ Signature verification policy file.
+ If this option is empty the default policy file from
+ skopeo will be used.
+ '';
+ };
+
+ };
+
+ config = lib.mkIf cfg.enable {
+
+ virtualisation.containers.containersConf.cniPlugins = [ pkgs.cni-plugins ];
+
+ virtualisation.containers.containersConf.settings = {
+ network.cni_plugin_dirs = map (p: "${lib.getBin p}/bin") cfg.containersConf.cniPlugins;
+ engine = {
+ init_path = "${pkgs.catatonit}/bin/catatonit";
+ } // lib.optionalAttrs cfg.ociSeccompBpfHook.enable {
+ hooks_dir = [ config.boot.kernelPackages.oci-seccomp-bpf-hook ];
+ };
+ };
+
+ xdg.configFile."containers/containers.conf".source =
+ toml.generate "containers.conf" cfg.containersConf.settings;
+
+ xdg.configFile."containers/registries.conf".source = toml.generate "registries.conf" {
+ registries = lib.mapAttrs (n: v: { registries = v; }) cfg.registries;
+ };
+
+ xdg.configFile."containers/policy.json".source =
+ if cfg.policy != {} then pkgs.writeText "policy.json" (builtins.toJSON cfg.policy)
+ else "${pkgs.skopeo.src}/default-policy.json";
+ };
+
+}
diff --git a/users/modules/podman-dnsname.nix b/users/modules/podman-dnsname.nix
new file mode 100644
index 0000000..3df4955
--- /dev/null
+++ b/users/modules/podman-dnsname.nix
@@ -0,0 +1,36 @@
+{ config, lib, pkgs, ... }:
+let
+ inherit (lib)
+ mkOption
+ mkIf
+ types
+ ;
+
+ cfg = config.services.podman;
+
+in
+{
+ options = {
+ services.podman = {
+
+ defaultNetwork.dnsname.enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Enable DNS resolution in the default podman network.
+ '';
+ };
+
+ };
+ };
+
+ config = {
+ virtualisation.containers.containersConf.cniPlugins = mkIf cfg.defaultNetwork.dnsname.enable [ pkgs.dnsname-cni ];
+ services.podman.defaultNetwork.extraPlugins =
+ lib.optional cfg.defaultNetwork.dnsname.enable {
+ type = "dnsname";
+ domainName = "dns.podman";
+ capabilities.aliases = true;
+ };
+ };
+}
diff --git a/users/modules/podman.nix b/users/modules/podman.nix
new file mode 100644
index 0000000..7d53f81
--- /dev/null
+++ b/users/modules/podman.nix
@@ -0,0 +1,182 @@
+{ config, lib, pkgs, ... }:
+let
+ cfg = config.services.podman;
+ toml = pkgs.formats.toml { };
+ json = pkgs.formats.json { };
+
+ inherit (lib) mkOption types;
+
+ podmanPackage = (pkgs.podman.override { inherit (cfg) extraPackages; });
+
+ # Provides a fake "docker" binary mapping to podman
+ dockerCompat = pkgs.runCommandNoCC "${podmanPackage.pname}-docker-compat-${podmanPackage.version}"
+ {
+ outputs = [ "out" "man" ];
+ inherit (podmanPackage) meta;
+ } ''
+ mkdir -p $out/bin
+ ln -s ${podmanPackage}/bin/podman $out/bin/docker
+
+ mkdir -p $man/share/man/man1
+ for f in ${podmanPackage.man}/share/man/man1/*; do
+ basename=$(basename $f | sed s/podman/docker/g)
+ ln -s $f $man/share/man/man1/$basename
+ done
+ '';
+
+ net-conflist = pkgs.runCommand "87-podman-bridge.conflist"
+ {
+ nativeBuildInputs = [ pkgs.jq ];
+ extraPlugins = builtins.toJSON cfg.defaultNetwork.extraPlugins;
+ jqScript = ''
+ . + { "plugins": (.plugins + $extraPlugins) }
+ '';
+ } ''
+ jq <${cfg.package}/etc/cni/net.d/87-podman-bridge.conflist \
+ --argjson extraPlugins "$extraPlugins" \
+ "$jqScript" \
+ >$out
+ '';
+
+in
+{
+ imports = [
+ ./podman-dnsname.nix
+ #./podman-network-socket.nix
+ (lib.mkRenamedOptionModule [ "virtualisation" "podman" "libpod" ] [ "virtualisation" "containers" "containersConf" ])
+ ];
+
+ meta = {
+ maintainers = lib.teams.podman.members;
+ };
+
+ options.services.podman = {
+
+ enable =
+ mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ This option enables Podman, a daemonless container engine for
+ developing, managing, and running OCI Containers on your Linux System.
+
+ It is a drop-in replacement for the docker command.
+ '';
+ };
+
+ dockerSocket.enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Make the Podman socket available in place of the Docker socket, so
+ Docker tools can find the Podman socket.
+
+ Podman implements the Docker API.
+ '';
+ };
+
+ dockerCompat = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Create an alias mapping docker to podman.
+ '';
+ };
+
+ enableNvidia = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Enable use of NVidia GPUs from within podman containers.
+ '';
+ };
+
+ extraPackages = mkOption {
+ type = with types; listOf package;
+ default = [ ];
+ example = lib.literalExample ''
+ [
+ pkgs.gvisor
+ ]
+ '';
+ description = ''
+ Extra packages to be installed in the Podman wrapper.
+ '';
+ };
+
+ package = lib.mkOption {
+ type = types.package;
+ default = podmanPackage;
+ internal = true;
+ description = ''
+ The final Podman package (including extra packages).
+ '';
+ };
+
+ defaultNetwork.extraPlugins = lib.mkOption {
+ type = types.listOf json.type;
+ default = [ ];
+ description = ''
+ Extra CNI plugin configurations to add to podman's default network.
+ '';
+ };
+
+ };
+
+ config = lib.mkIf cfg.enable (lib.mkMerge [
+ {
+ home.packages = [ cfg.package ]
+ ++ lib.optional cfg.dockerCompat dockerCompat;
+
+ xdg.configFile."cni/net.d/87-podman-bridge.conflist".source = net-conflist;
+
+ virtualisation.containers = {
+ enable = true; # Enable common /etc/containers configuration
+ containersConf.settings = lib.optionalAttrs cfg.enableNvidia {
+ engine = {
+ conmon_env_vars = [ "PATH=${lib.makeBinPath [ pkgs.nvidia-podman ]}" ];
+ runtimes.nvidia = [ "${pkgs.nvidia-podman}/bin/nvidia-container-runtime" ];
+ };
+ };
+ };
+
+ systemd.user = {
+
+ services.podman = {
+ Unit = {
+ Description = "Podman API Service";
+ Requires = "podman.socket";
+ After = "podman.socket";
+ Documentation = "man:podman-system-service(1)";
+ StartLimitIntervalSec = 0;
+ };
+ Service = {
+ Type = "exec";
+ KillMode = "process";
+ Environment = "LOGGING=\" --log-level=info\"";
+ ExecStart = [ "" "${cfg.package}/bin/podman $LOGGING system service" ];
+ };
+
+ Install = {
+ WantedBy = [ "multi-user.target" ];
+ };
+ };
+
+ sockets.podman = {
+ Unit = {
+ Description = "Podman API Socket";
+ Documentation = "man:podman-system-service(1)";
+ };
+ Socket = {
+ ListenStream = "%t/podman/podman.sock";
+ SocketMode = 0660;
+ };
+ Install.WantedBy = [ "sockets.target" ];
+ };
+
+ };
+ }
+ (lib.mkIf cfg.dockerSocket.enable {
+ home.sessionVariables."DOCKER_HOST" = "unix:///run/user/$UID/podman/podman.sock"; })
+ ]);
+ }