summary refs log tree commit diff
path: root/nixos/modules/profiles
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/profiles')
-rw-r--r--nixos/modules/profiles/all-hardware.nix120
-rw-r--r--nixos/modules/profiles/base.nix58
-rw-r--r--nixos/modules/profiles/clone-config.nix109
-rw-r--r--nixos/modules/profiles/demo.nix21
-rw-r--r--nixos/modules/profiles/docker-container.nix61
-rw-r--r--nixos/modules/profiles/graphical.nix20
-rw-r--r--nixos/modules/profiles/hardened.nix118
-rw-r--r--nixos/modules/profiles/headless.nix25
-rw-r--r--nixos/modules/profiles/installation-device.nix117
-rw-r--r--nixos/modules/profiles/minimal.nix19
-rw-r--r--nixos/modules/profiles/qemu-guest.nix17
11 files changed, 685 insertions, 0 deletions
diff --git a/nixos/modules/profiles/all-hardware.nix b/nixos/modules/profiles/all-hardware.nix
new file mode 100644
index 00000000000..25f68123a1d
--- /dev/null
+++ b/nixos/modules/profiles/all-hardware.nix
@@ -0,0 +1,120 @@
+# This module enables all hardware supported by NixOS: i.e., all
+# firmware is included, and all devices from which one may boot are
+# enabled in the initrd.  Its primary use is in the NixOS installation
+# CDs.
+
+{ pkgs, lib,... }:
+let
+  platform = pkgs.stdenv.hostPlatform;
+in
+{
+
+  # The initrd has to contain any module that might be necessary for
+  # supporting the most important parts of HW like drives.
+  boot.initrd.availableKernelModules =
+    [ # SATA/PATA support.
+      "ahci"
+
+      "ata_piix"
+
+      "sata_inic162x" "sata_nv" "sata_promise" "sata_qstor"
+      "sata_sil" "sata_sil24" "sata_sis" "sata_svw" "sata_sx4"
+      "sata_uli" "sata_via" "sata_vsc"
+
+      "pata_ali" "pata_amd" "pata_artop" "pata_atiixp" "pata_efar"
+      "pata_hpt366" "pata_hpt37x" "pata_hpt3x2n" "pata_hpt3x3"
+      "pata_it8213" "pata_it821x" "pata_jmicron" "pata_marvell"
+      "pata_mpiix" "pata_netcell" "pata_ns87410" "pata_oldpiix"
+      "pata_pcmcia" "pata_pdc2027x" "pata_qdi" "pata_rz1000"
+      "pata_serverworks" "pata_sil680" "pata_sis"
+      "pata_sl82c105" "pata_triflex" "pata_via"
+      "pata_winbond"
+
+      # SCSI support (incomplete).
+      "3w-9xxx" "3w-xxxx" "aic79xx" "aic7xxx" "arcmsr"
+
+      # USB support, especially for booting from USB CD-ROM
+      # drives.
+      "uas"
+
+      # SD cards.
+      "sdhci_pci"
+
+      # Firewire support.  Not tested.
+      "ohci1394" "sbp2"
+
+      # Virtio (QEMU, KVM etc.) support.
+      "virtio_net" "virtio_pci" "virtio_mmio" "virtio_blk" "virtio_scsi" "virtio_balloon" "virtio_console"
+
+      # VMware support.
+      "mptspi" "vmxnet3" "vsock"
+    ] ++ lib.optional platform.isx86 "vmw_balloon"
+    ++ lib.optionals (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) [
+      "vmw_vmci" "vmwgfx" "vmw_vsock_vmci_transport"
+
+      # Hyper-V support.
+      "hv_storvsc"
+    ] ++ lib.optionals (pkgs.stdenv.isAarch32 || pkgs.stdenv.isAarch64) [
+      # Most of the following falls into two categories:
+      #  - early KMS / early display
+      #  - early storage (e.g. USB) support
+
+      # Allows using framebuffer configured by the initial boot firmware
+      "simplefb"
+
+      # Allwinner support
+
+      # Required for early KMS
+      "sun4i-drm"
+      "sun8i-mixer" # Audio, but required for kms
+
+      # PWM for the backlight
+      "pwm-sun4i"
+
+      # Broadcom
+
+      "vc4"
+    ] ++ lib.optionals pkgs.stdenv.isAarch64 [
+      # Most of the following falls into two categories:
+      #  - early KMS / early display
+      #  - early storage (e.g. USB) support
+
+      # Broadcom
+
+      "pcie-brcmstb"
+
+      # Rockchip
+      "dw-hdmi"
+      "dw-mipi-dsi"
+      "rockchipdrm"
+      "rockchip-rga"
+      "phy-rockchip-pcie"
+      "pcie-rockchip-host"
+
+      # Misc. uncategorized hardware
+
+      # Used for some platform's integrated displays
+      "panel-simple"
+      "pwm-bl"
+
+      # Power supply drivers, some platforms need them for USB
+      "axp20x-ac-power"
+      "axp20x-battery"
+      "pinctrl-axp209"
+      "mp8859"
+
+      # USB drivers
+      "xhci-pci-renesas"
+
+      # Misc "weak" dependencies
+      "analogix-dp"
+      "analogix-anx6345" # For DP or eDP (e.g. integrated display)
+    ];
+
+  # Include lots of firmware.
+  hardware.enableRedistributableFirmware = true;
+
+  imports =
+    [ ../hardware/network/zydas-zd1211.nix ];
+
+}
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
new file mode 100644
index 00000000000..33dd80d7c5a
--- /dev/null
+++ b/nixos/modules/profiles/base.nix
@@ -0,0 +1,58 @@
+# This module defines the software packages included in the "minimal"
+# installation CD.  It might be useful elsewhere.
+
+{ lib, pkgs, ... }:
+
+{
+  # Include some utilities that are useful for installing or repairing
+  # the system.
+  environment.systemPackages = [
+    pkgs.w3m-nographics # needed for the manual anyway
+    pkgs.testdisk # useful for repairing boot problems
+    pkgs.ms-sys # for writing Microsoft boot sectors / MBRs
+    pkgs.efibootmgr
+    pkgs.efivar
+    pkgs.parted
+    pkgs.gptfdisk
+    pkgs.ddrescue
+    pkgs.ccrypt
+    pkgs.cryptsetup # needed for dm-crypt volumes
+    pkgs.mkpasswd # for generating password files
+
+    # Some text editors.
+    pkgs.vim
+
+    # Some networking tools.
+    pkgs.fuse
+    pkgs.fuse3
+    pkgs.sshfs-fuse
+    pkgs.rsync
+    pkgs.socat
+    pkgs.screen
+
+    # Hardware-related tools.
+    pkgs.sdparm
+    pkgs.hdparm
+    pkgs.smartmontools # for diagnosing hard disks
+    pkgs.pciutils
+    pkgs.usbutils
+
+    # Tools to create / manipulate filesystems.
+    pkgs.ntfsprogs # for resizing NTFS partitions
+    pkgs.dosfstools
+    pkgs.mtools
+    pkgs.xfsprogs.bin
+    pkgs.jfsutils
+    pkgs.f2fs-tools
+
+    # Some compression/archiver tools.
+    pkgs.unzip
+    pkgs.zip
+  ];
+
+  # Include support for various filesystems.
+  boot.supportedFilesystems = [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "zfs" "ntfs" "cifs" ];
+
+  # Configure host id for ZFS to work
+  networking.hostId = lib.mkDefault "8425e349";
+}
diff --git a/nixos/modules/profiles/clone-config.nix b/nixos/modules/profiles/clone-config.nix
new file mode 100644
index 00000000000..3f669ba7d2e
--- /dev/null
+++ b/nixos/modules/profiles/clone-config.nix
@@ -0,0 +1,109 @@
+{ config, lib, pkgs, modules, ... }:
+
+with lib;
+
+let
+
+  # Location of the repository on the harddrive
+  nixosPath = toString ../..;
+
+  # Check if the path is from the NixOS repository
+  isNixOSFile = path:
+    let s = toString path; in
+      removePrefix nixosPath s != s;
+
+  # Copy modules given as extra configuration files.  Unfortunately, we
+  # cannot serialized attribute set given in the list of modules (that's why
+  # you should use files).
+  moduleFiles =
+    # FIXME: use typeOf (Nix 1.6.1).
+    filter (x: !isAttrs x && !lib.isFunction x) modules;
+
+  # Partition module files because between NixOS and non-NixOS files.  NixOS
+  # files may change if the repository is updated.
+  partitionedModuleFiles =
+    let p = partition isNixOSFile moduleFiles; in
+    { nixos = p.right; others = p.wrong; };
+
+  # Path transformed to be valid on the installation device.  Thus the
+  # device configuration could be rebuild.
+  relocatedModuleFiles =
+    let
+      relocateNixOS = path:
+        "<nixpkgs/nixos" + removePrefix nixosPath (toString path) + ">";
+    in
+      { nixos = map relocateNixOS partitionedModuleFiles.nixos;
+        others = []; # TODO: copy the modules to the install-device repository.
+      };
+
+  # A dummy /etc/nixos/configuration.nix in the booted CD that
+  # rebuilds the CD's configuration (and allows the configuration to
+  # be modified, of course, providing a true live CD).  Problem is
+  # that we don't really know how the CD was built - the Nix
+  # expression language doesn't allow us to query the expression being
+  # evaluated.  So we'll just hope for the best.
+  configClone = pkgs.writeText "configuration.nix"
+    ''
+      { config, pkgs, ... }:
+
+      {
+        imports = [ ${toString config.installer.cloneConfigIncludes} ];
+
+        ${config.installer.cloneConfigExtra}
+      }
+    '';
+
+in
+
+{
+
+  options = {
+
+    installer.cloneConfig = mkOption {
+      default = true;
+      description = ''
+        Try to clone the installation-device configuration by re-using it's
+        profile from the list of imported modules.
+      '';
+    };
+
+    installer.cloneConfigIncludes = mkOption {
+      default = [];
+      example = [ "./nixos/modules/hardware/network/rt73.nix" ];
+      description = ''
+        List of modules used to re-build this installation device profile.
+      '';
+    };
+
+    installer.cloneConfigExtra = mkOption {
+      default = "";
+      description = ''
+        Extra text to include in the cloned configuration.nix included in this
+        installer.
+      '';
+    };
+  };
+
+  config = {
+
+    installer.cloneConfigIncludes =
+      relocatedModuleFiles.nixos ++ relocatedModuleFiles.others;
+
+    boot.postBootCommands =
+      ''
+        # Provide a mount point for nixos-install.
+        mkdir -p /mnt
+
+        ${optionalString config.installer.cloneConfig ''
+          # Provide a configuration for the CD/DVD itself, to allow users
+          # to run nixos-rebuild to change the configuration of the
+          # running system on the CD/DVD.
+          if ! [ -e /etc/nixos/configuration.nix ]; then
+            cp ${configClone} /etc/nixos/configuration.nix
+          fi
+       ''}
+      '';
+
+  };
+
+}
diff --git a/nixos/modules/profiles/demo.nix b/nixos/modules/profiles/demo.nix
new file mode 100644
index 00000000000..4e8c74deedb
--- /dev/null
+++ b/nixos/modules/profiles/demo.nix
@@ -0,0 +1,21 @@
+{ ... }:
+
+{
+  imports = [ ./graphical.nix ];
+
+  users.users.demo =
+    { isNormalUser = true;
+      description = "Demo user account";
+      extraGroups = [ "wheel" ];
+      password = "demo";
+      uid = 1000;
+    };
+
+  services.xserver.displayManager = {
+    autoLogin = {
+      enable = true;
+      user = "demo";
+    };
+    sddm.autoLogin.relogin = true;
+  };
+}
diff --git a/nixos/modules/profiles/docker-container.nix b/nixos/modules/profiles/docker-container.nix
new file mode 100644
index 00000000000..183645de36f
--- /dev/null
+++ b/nixos/modules/profiles/docker-container.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let inherit (pkgs) writeScript; in
+
+let
+ pkgs2storeContents = l : map (x: { object = x; symlink = "none"; }) l;
+
+in {
+  # Docker image config.
+  imports = [
+    ../installer/cd-dvd/channel.nix
+    ./minimal.nix
+    ./clone-config.nix
+  ];
+
+  # Create the tarball
+  system.build.tarball = pkgs.callPackage ../../lib/make-system-tarball.nix {
+    contents = [
+      {
+        source = "${config.system.build.toplevel}/.";
+        target = "./";
+      }
+    ];
+    extraArgs = "--owner=0";
+
+    # Add init script to image
+    storeContents = pkgs2storeContents [
+      config.system.build.toplevel
+      pkgs.stdenv
+    ];
+
+    # Some container managers like lxc need these
+    extraCommands =
+      let script = writeScript "extra-commands.sh" ''
+            rm etc
+            mkdir -p proc sys dev etc
+          '';
+      in script;
+  };
+
+  boot.isContainer = true;
+  boot.postBootCommands =
+    ''
+      # After booting, register the contents of the Nix store in the Nix
+      # database.
+      if [ -f /nix-path-registration ]; then
+        ${config.nix.package.out}/bin/nix-store --load-db < /nix-path-registration &&
+        rm /nix-path-registration
+      fi
+
+      # nixos-rebuild also requires a "system" profile
+      ${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
+    '';
+
+  # Install new init script
+  system.activationScripts.installInitScript = ''
+    ln -fs $systemConfig/init /init
+  '';
+}
diff --git a/nixos/modules/profiles/graphical.nix b/nixos/modules/profiles/graphical.nix
new file mode 100644
index 00000000000..d80456cede5
--- /dev/null
+++ b/nixos/modules/profiles/graphical.nix
@@ -0,0 +1,20 @@
+# This module defines a NixOS configuration with the Plasma 5 desktop.
+# It's used by the graphical installation CD.
+
+{ pkgs, ... }:
+
+{
+  services.xserver = {
+    enable = true;
+    displayManager.sddm.enable = true;
+    desktopManager.plasma5 = {
+      enable = true;
+    };
+    libinput.enable = true; # for touchpad support on many laptops
+  };
+
+  # Enable sound in virtualbox appliances.
+  hardware.pulseaudio.enable = true;
+
+  environment.systemPackages = [ pkgs.glxinfo pkgs.firefox ];
+}
diff --git a/nixos/modules/profiles/hardened.nix b/nixos/modules/profiles/hardened.nix
new file mode 100644
index 00000000000..856ee480fc0
--- /dev/null
+++ b/nixos/modules/profiles/hardened.nix
@@ -0,0 +1,118 @@
+# A profile with most (vanilla) hardening options enabled by default,
+# potentially at the cost of stability, features and performance.
+#
+# This profile enables options that are known to affect system
+# stability. If you experience any stability issues when using the
+# profile, try disabling it. If you report an issue and use this
+# profile, always mention that you do.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  meta = {
+    maintainers = [ maintainers.joachifm maintainers.emily ];
+  };
+
+  boot.kernelPackages = mkDefault pkgs.linuxPackages_hardened;
+
+  nix.settings.allowed-users = mkDefault [ "@users" ];
+
+  environment.memoryAllocator.provider = mkDefault "scudo";
+  environment.variables.SCUDO_OPTIONS = mkDefault "ZeroContents=1";
+
+  security.lockKernelModules = mkDefault true;
+
+  security.protectKernelImage = mkDefault true;
+
+  security.allowSimultaneousMultithreading = mkDefault false;
+
+  security.forcePageTableIsolation = mkDefault true;
+
+  # This is required by podman to run containers in rootless mode.
+  security.unprivilegedUsernsClone = mkDefault config.virtualisation.containers.enable;
+
+  security.virtualisation.flushL1DataCache = mkDefault "always";
+
+  security.apparmor.enable = mkDefault true;
+  security.apparmor.killUnconfinedConfinables = mkDefault true;
+
+  boot.kernelParams = [
+    # Slab/slub sanity checks, redzoning, and poisoning
+    "slub_debug=FZP"
+
+    # Overwrite free'd memory
+    "page_poison=1"
+
+    # Enable page allocator randomization
+    "page_alloc.shuffle=1"
+  ];
+
+  boot.blacklistedKernelModules = [
+    # Obscure network protocols
+    "ax25"
+    "netrom"
+    "rose"
+
+    # Old or rare or insufficiently audited filesystems
+    "adfs"
+    "affs"
+    "bfs"
+    "befs"
+    "cramfs"
+    "efs"
+    "erofs"
+    "exofs"
+    "freevxfs"
+    "f2fs"
+    "hfs"
+    "hpfs"
+    "jfs"
+    "minix"
+    "nilfs2"
+    "ntfs"
+    "omfs"
+    "qnx4"
+    "qnx6"
+    "sysv"
+    "ufs"
+  ];
+
+  # Restrict ptrace() usage to processes with a pre-defined relationship
+  # (e.g., parent/child)
+  boot.kernel.sysctl."kernel.yama.ptrace_scope" = mkOverride 500 1;
+
+  # Hide kptrs even for processes with CAP_SYSLOG
+  boot.kernel.sysctl."kernel.kptr_restrict" = mkOverride 500 2;
+
+  # Disable bpf() JIT (to eliminate spray attacks)
+  boot.kernel.sysctl."net.core.bpf_jit_enable" = mkDefault false;
+
+  # Disable ftrace debugging
+  boot.kernel.sysctl."kernel.ftrace_enabled" = mkDefault false;
+
+  # Enable strict reverse path filtering (that is, do not attempt to route
+  # packets that "obviously" do not belong to the iface's network; dropped
+  # packets are logged as martians).
+  boot.kernel.sysctl."net.ipv4.conf.all.log_martians" = mkDefault true;
+  boot.kernel.sysctl."net.ipv4.conf.all.rp_filter" = mkDefault "1";
+  boot.kernel.sysctl."net.ipv4.conf.default.log_martians" = mkDefault true;
+  boot.kernel.sysctl."net.ipv4.conf.default.rp_filter" = mkDefault "1";
+
+  # Ignore broadcast ICMP (mitigate SMURF)
+  boot.kernel.sysctl."net.ipv4.icmp_echo_ignore_broadcasts" = mkDefault true;
+
+  # Ignore incoming ICMP redirects (note: default is needed to ensure that the
+  # setting is applied to interfaces added after the sysctls are set)
+  boot.kernel.sysctl."net.ipv4.conf.all.accept_redirects" = mkDefault false;
+  boot.kernel.sysctl."net.ipv4.conf.all.secure_redirects" = mkDefault false;
+  boot.kernel.sysctl."net.ipv4.conf.default.accept_redirects" = mkDefault false;
+  boot.kernel.sysctl."net.ipv4.conf.default.secure_redirects" = mkDefault false;
+  boot.kernel.sysctl."net.ipv6.conf.all.accept_redirects" = mkDefault false;
+  boot.kernel.sysctl."net.ipv6.conf.default.accept_redirects" = mkDefault false;
+
+  # Ignore outgoing ICMP redirects (this is ipv4 only)
+  boot.kernel.sysctl."net.ipv4.conf.all.send_redirects" = mkDefault false;
+  boot.kernel.sysctl."net.ipv4.conf.default.send_redirects" = mkDefault false;
+}
diff --git a/nixos/modules/profiles/headless.nix b/nixos/modules/profiles/headless.nix
new file mode 100644
index 00000000000..c17cb287b72
--- /dev/null
+++ b/nixos/modules/profiles/headless.nix
@@ -0,0 +1,25 @@
+# Common configuration for headless machines (e.g., Amazon EC2
+# instances).
+
+{ lib, ... }:
+
+with lib;
+
+{
+  boot.vesa = false;
+
+  # Don't start a tty on the serial consoles.
+  systemd.services."serial-getty@ttyS0".enable = lib.mkDefault false;
+  systemd.services."serial-getty@hvc0".enable = false;
+  systemd.services."getty@tty1".enable = false;
+  systemd.services."autovt@".enable = false;
+
+  # Since we can't manually respond to a panic, just reboot.
+  boot.kernelParams = [ "panic=1" "boot.panic_on_fail" ];
+
+  # Don't allow emergency mode, because we don't have a console.
+  systemd.enableEmergencyMode = false;
+
+  # Being headless, we don't need a GRUB splash image.
+  boot.loader.grub.splashImage = null;
+}
diff --git a/nixos/modules/profiles/installation-device.nix b/nixos/modules/profiles/installation-device.nix
new file mode 100644
index 00000000000..3c503fba2a3
--- /dev/null
+++ b/nixos/modules/profiles/installation-device.nix
@@ -0,0 +1,117 @@
+# Provide a basic configuration for installation devices like CDs.
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+{
+  imports =
+    [ # Enable devices which are usually scanned, because we don't know the
+      # target system.
+      ../installer/scan/detected.nix
+      ../installer/scan/not-detected.nix
+
+      # Allow "nixos-rebuild" to work properly by providing
+      # /etc/nixos/configuration.nix.
+      ./clone-config.nix
+
+      # Include a copy of Nixpkgs so that nixos-install works out of
+      # the box.
+      ../installer/cd-dvd/channel.nix
+    ];
+
+  config = {
+
+    # Enable in installer, even if the minimal profile disables it.
+    documentation.enable = mkForce true;
+
+    # Show the manual.
+    documentation.nixos.enable = mkForce true;
+
+    # Use less privileged nixos user
+    users.users.nixos = {
+      isNormalUser = true;
+      extraGroups = [ "wheel" "networkmanager" "video" ];
+      # Allow the graphical user to login without password
+      initialHashedPassword = "";
+    };
+
+    # Allow the user to log in as root without a password.
+    users.users.root.initialHashedPassword = "";
+
+    # Allow passwordless sudo from nixos user
+    security.sudo = {
+      enable = mkDefault true;
+      wheelNeedsPassword = mkForce false;
+    };
+
+    # Automatically log in at the virtual consoles.
+    services.getty.autologinUser = "nixos";
+
+    # Some more help text.
+    services.getty.helpLine = ''
+      The "nixos" and "root" accounts have empty passwords.
+
+      An ssh daemon is running. You then must set a password
+      for either "root" or "nixos" with `passwd` or add an ssh key
+      to /home/nixos/.ssh/authorized_keys be able to login.
+
+      If you need a wireless connection, type
+      `sudo systemctl start wpa_supplicant` and configure a
+      network using `wpa_cli`. See the NixOS manual for details.
+    '' + optionalString config.services.xserver.enable ''
+
+      Type `sudo systemctl start display-manager' to
+      start the graphical user interface.
+    '';
+
+    # We run sshd by default. Login via root is only possible after adding a
+    # password via "passwd" or by adding a ssh key to /home/nixos/.ssh/authorized_keys.
+    # The latter one is particular useful if keys are manually added to
+    # installation device for head-less systems i.e. arm boards by manually
+    # mounting the storage in a different system.
+    services.openssh = {
+      enable = true;
+      permitRootLogin = "yes";
+    };
+
+    # Enable wpa_supplicant, but don't start it by default.
+    networking.wireless.enable = mkDefault true;
+    networking.wireless.userControlled.enable = true;
+    systemd.services.wpa_supplicant.wantedBy = mkOverride 50 [];
+
+    # Tell the Nix evaluator to garbage collect more aggressively.
+    # This is desirable in memory-constrained environments that don't
+    # (yet) have swap set up.
+    environment.variables.GC_INITIAL_HEAP_SIZE = "1M";
+
+    # Make the installer more likely to succeed in low memory
+    # environments.  The kernel's overcommit heustistics bite us
+    # fairly often, preventing processes such as nix-worker or
+    # download-using-manifests.pl from forking even if there is
+    # plenty of free memory.
+    boot.kernel.sysctl."vm.overcommit_memory" = "1";
+
+    # To speed up installation a little bit, include the complete
+    # stdenv in the Nix store on the CD.
+    system.extraDependencies = with pkgs;
+      [
+        stdenv
+        stdenvNoCC # for runCommand
+        busybox
+        jq # for closureInfo
+      ];
+
+    # Show all debug messages from the kernel but don't log refused packets
+    # because we have the firewall enabled. This makes installs from the
+    # console less cumbersome if the machine has a public IP.
+    networking.firewall.logRefusedConnections = mkDefault false;
+
+    # Prevent installation media from evacuating persistent storage, as their
+    # var directory is not persistent and it would thus result in deletion of
+    # those entries.
+    environment.etc."systemd/pstore.conf".text = ''
+      [PStore]
+      Unlink=no
+    '';
+  };
+}
diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix
new file mode 100644
index 00000000000..e79b9272384
--- /dev/null
+++ b/nixos/modules/profiles/minimal.nix
@@ -0,0 +1,19 @@
+# This module defines a small NixOS configuration.  It does not
+# contain any graphical stuff.
+
+{ config, lib, ... }:
+
+with lib;
+
+{
+  environment.noXlibs = mkDefault true;
+
+  # This isn't perfect, but let's expect the user specifies an UTF-8 defaultLocale
+  i18n.supportedLocales = [ (config.i18n.defaultLocale + "/UTF-8") ];
+
+  documentation.enable = mkDefault false;
+
+  documentation.nixos.enable = mkDefault false;
+
+  programs.command-not-found.enable = mkDefault false;
+}
diff --git a/nixos/modules/profiles/qemu-guest.nix b/nixos/modules/profiles/qemu-guest.nix
new file mode 100644
index 00000000000..d4335edfcf2
--- /dev/null
+++ b/nixos/modules/profiles/qemu-guest.nix
@@ -0,0 +1,17 @@
+# Common configuration for virtual machines running under QEMU (using
+# virtio).
+
+{ ... }:
+
+{
+  boot.initrd.availableKernelModules = [ "virtio_net" "virtio_pci" "virtio_mmio" "virtio_blk" "virtio_scsi" "9p" "9pnet_virtio" ];
+  boot.initrd.kernelModules = [ "virtio_balloon" "virtio_console" "virtio_rng" ];
+
+  boot.initrd.postDeviceCommands =
+    ''
+      # Set the system time from the hardware clock to work around a
+      # bug in qemu-kvm > 1.5.2 (where the VM clock is initialised
+      # to the *boot time* of the host).
+      hwclock -s
+    '';
+}