about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/configuration.xml15
-rw-r--r--nixos/modules/config/users-groups.nix2
-rw-r--r--nixos/modules/installer/tools/nixos-install.sh2
-rw-r--r--nixos/modules/installer/tools/nixos-rebuild.sh5
-rw-r--r--nixos/modules/misc/ids.nix5
-rw-r--r--nixos/modules/module-list.nix3
-rw-r--r--nixos/modules/programs/nano.nix35
-rw-r--r--nixos/modules/security/setuid-wrappers.nix3
-rw-r--r--nixos/modules/services/mail/mlmmj.nix128
-rw-r--r--nixos/modules/services/misc/siproxd.nix180
-rw-r--r--nixos/modules/services/networking/dhcpcd.nix5
-rw-r--r--nixos/modules/services/networking/dhcpd.nix35
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix6
-rw-r--r--nixos/modules/services/web-servers/lighttpd/default.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix25
-rw-r--r--nixos/modules/system/activation/activation-script.nix5
-rw-r--r--nixos/modules/system/boot/stage-1.nix15
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh4
-rw-r--r--nixos/modules/system/boot/systemd.nix2
-rw-r--r--nixos/modules/tasks/network-interfaces.nix89
-rw-r--r--nixos/modules/virtualisation/container-config.nix2
-rw-r--r--nixos/modules/virtualisation/containers.nix92
-rw-r--r--nixos/modules/virtualisation/nixos-container.pl54
-rw-r--r--nixos/release.nix52
24 files changed, 707 insertions, 63 deletions
diff --git a/nixos/doc/manual/configuration.xml b/nixos/doc/manual/configuration.xml
index 051f0fb8c1e0..64372f3bbf14 100644
--- a/nixos/doc/manual/configuration.xml
+++ b/nixos/doc/manual/configuration.xml
@@ -1053,6 +1053,12 @@ a password. However, you can use the <command>passwd</command> program
 to set a password, which is retained across invocations of
 <command>nixos-rebuild</command>.</para>
 
+<para>If you set users.mutableUsers to false, then the contents of /etc/passwd
+and /etc/group will be congruent to your NixOS configuration. For instance,
+if you remove a user from users.extraUsers and run nixos-rebuild, the user
+account will cease to exist. Also, imperative commands for managing users
+and groups, such as useradd, are no longer available.</para>
+
 <para>A user ID (uid) is assigned automatically.  You can also specify
 a uid manually by adding
 
@@ -1499,10 +1505,11 @@ are specific to the kernel version, such as the NVIDIA video drivers.
 This ensures that driver packages are consistent with the
 kernel.</para>
 
-<para>The default Linux kernel configuration should be fine for most
-users.  You can see the configuration of your current kernel in
-<filename>/run/booted-system/kernel-modules/config</filename>.  If you
-want to change the kernel configuration, you can use the
+<para>The default Linux kernel configuration should be fine for most users. You can see the configuration of your current kernel with the following command:
+<programlisting>
+cat /proc/config.gz | gunzip
+</programlisting>
+If you want to change the kernel configuration, you can use the
 <option>packageOverrides</option> feature (see <xref
 linkend="sec-customising-packages" />).  For instance, to enable
 support for the kernel debugger KGDB:
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 5de81a773424..7783f13b14b1 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -404,7 +404,7 @@ in {
         uid = ids.uids.root;
         description = "System administrator";
         home = "/root";
-        shell = cfg.defaultUserShell;
+        shell = mkDefault cfg.defaultUserShell;
         group = "root";
         extraGroups = [ "grsecurity" ];
         hashedPassword = mkDefault config.security.initialRootPassword;
diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh
index 9d62ba131dc7..a55eda1cb8fd 100644
--- a/nixos/modules/installer/tools/nixos-install.sh
+++ b/nixos/modules/installer/tools/nixos-install.sh
@@ -81,7 +81,7 @@ mount -t tmpfs -o "mode=0755" none $mountPoint/var/setuid-wrappers
 rm -rf $mountPoint/var/run
 ln -s /run $mountPoint/var/run
 rm -f $mountPoint/etc/{resolv.conf,hosts}
-cp -f /etc/resolv.conf /etc/hosts $mountPoint/etc/
+cp -Lf /etc/resolv.conf /etc/hosts $mountPoint/etc/
 
 
 if [ -n "$runChroot" ]; then
diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh
index be37e61151aa..52b64c37578e 100644
--- a/nixos/modules/installer/tools/nixos-rebuild.sh
+++ b/nixos/modules/installer/tools/nixos-rebuild.sh
@@ -225,7 +225,10 @@ fi
 # If we're not just building, then make the new configuration the boot
 # default and/or activate it now.
 if [ "$action" = switch -o "$action" = boot -o "$action" = test ]; then
-    $pathToConfig/bin/switch-to-configuration "$action"
+    if ! $pathToConfig/bin/switch-to-configuration "$action"; then
+        echo "warning: there were error switching to the new configuration" >&2
+        exit 1
+    fi
 fi
 
 
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 8a459ce5e889..b49837efd50e 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -140,6 +140,9 @@
       mopidy = 130;
       unifi = 131;
       gdm = 132;
+      dhcpd = 133;
+      siproxd = 134;
+      mlmmj = 135;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -255,6 +258,8 @@
       docker = 131;
       gdm = 132;
       tss = 133;
+      siproxd = 134;
+      mlmmj = 135;
 
       # When adding a gid, make sure it doesn't match an existing uid. And don't use gids above 399!
 
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index d90c56f2412a..c25110fc5b14 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -53,6 +53,7 @@
   ./programs/dconf.nix
   ./programs/environment.nix
   ./programs/info.nix
+  ./programs/nano.nix
   ./programs/screen.nix
   ./programs/shadow.nix
   ./programs/shell.nix
@@ -141,6 +142,7 @@
   ./services/mail/dovecot.nix
   ./services/mail/freepops.nix
   ./services/mail/mail.nix
+  ./services/mail/mlmmj.nix
   ./services/mail/opensmtpd.nix
   ./services/mail/postfix.nix
   ./services/mail/spamassassin.nix
@@ -158,6 +160,7 @@
   ./services/misc/nix-ssh-serve.nix
   ./services/misc/rippled.nix
   ./services/misc/rogue.nix
+  ./services/misc/siproxd.nix
   ./services/misc/svnserve.nix
   ./services/misc/synergy.nix
   ./services/monitoring/apcupsd.nix
diff --git a/nixos/modules/programs/nano.nix b/nixos/modules/programs/nano.nix
new file mode 100644
index 000000000000..b8803eec7be1
--- /dev/null
+++ b/nixos/modules/programs/nano.nix
@@ -0,0 +1,35 @@
+{ config, lib, ... }:
+
+let
+  cfg = config.programs.nano;
+in
+
+{
+  ###### interface
+
+  options = {
+    programs.nano = {
+
+      nanorc = lib.mkOption {
+        type = lib.types.lines;
+        default = "";
+        description = ''
+          The system-wide nano configuration.
+          See <citerefentry><refentrytitle>nanorc</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+        '';
+        example = ''
+          set nowrap
+          set tabstospaces
+          set tabsize 4
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = lib.mkIf (cfg.nanorc != "") {
+    environment.etc."nanorc".text = cfg.nanorc;
+  };
+
+}
diff --git a/nixos/modules/security/setuid-wrappers.nix b/nixos/modules/security/setuid-wrappers.nix
index 4cdc1023baab..373afffd3fb5 100644
--- a/nixos/modules/security/setuid-wrappers.nix
+++ b/nixos/modules/security/setuid-wrappers.nix
@@ -97,8 +97,7 @@ in
           }:
 
           ''
-            source=${if source != "" then source else "$(PATH=$SETUID_PATH type -tP ${program})"}
-            if test -z "$source"; then
+            if ! source=${if source != "" then source else "$(PATH=$SETUID_PATH type -tP ${program})"}; then
                 # If we can't find the program, fall back to the
                 # system profile.
                 source=/nix/var/nix/profiles/default/bin/${program}
diff --git a/nixos/modules/services/mail/mlmmj.nix b/nixos/modules/services/mail/mlmmj.nix
new file mode 100644
index 000000000000..637974f05cd1
--- /dev/null
+++ b/nixos/modules/services/mail/mlmmj.nix
@@ -0,0 +1,128 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.mlmmj;
+  stateDir = "/var/lib/mlmmj";
+  spoolDir = "/var/spool/mlmmj";
+  listDir = domain: list: "${spoolDir}/${domain}/${list}";
+  listCtl = domain: list: "${listDir domain list}/control";
+  transport = domain: list: "${domain}--${list}@local.list.mlmmj mlmmj:${domain}/${list}";
+  virtual = domain: list: "${list}@${domain} ${domain}--${list}@local.list.mlmmj";
+  alias = domain: list: "${list}: \"|${pkgs.mlmmj}/mlmmj-receive -L ${listDir domain list}/\"";
+  subjectPrefix = list: "[${list}]";
+  listAddress = domain: list: "${list}@${domain}";
+  customHeaders = list: domain: [ "List-Id: ${list}" "Reply-To: ${list}@${domain}" ];
+  footer = domain: list: "To unsubscribe send a mail to ${list}+unsubscribe@${domain}";
+  createList = d: l: ''
+    ${pkgs.coreutils}/bin/mkdir -p ${listCtl d l}
+    echo ${listAddress d l} > ${listCtl d l}/listadress
+    echo "${lib.concatStringsSep "\n" (customHeaders d l)}" > ${listCtl d l}/customheaders
+    echo ${footer d l} > ${listCtl d l}/footer
+    echo ${subjectPrefix l} > ${listCtl d l}/prefix
+  '';
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.mlmmj = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Enable mlmmj";
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "mlmmj";
+        description = "mailinglist local user";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "mlmmj";
+        description = "mailinglist local group";
+      };
+
+      listDomain = mkOption {
+        type = types.str;
+        default = "localhost";
+        description = "Set the mailing list domain";
+      };
+
+      mailLists = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = "The collection of hosted maillists";
+      };
+
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = singleton {
+      name = cfg.user;
+      description = "mlmmj user";
+      home = stateDir;
+      createHome = true;
+      uid = config.ids.uids.mlmmj;
+      group = cfg.group;
+      useDefaultShell = true;
+    };
+
+    users.extraGroups = singleton {
+      name = cfg.group;
+      gid = config.ids.gids.mlmmj;
+    };
+
+    services.postfix = {
+      enable = true;
+      recipientDelimiter= "+";
+      extraMasterConf = ''
+        mlmmj unix - n n - - pipe flags=ORhu user=mlmmj argv=${pkgs.mlmmj}/bin/mlmmj-recieve -F -L ${spoolDir}/$nextHop
+      '';
+
+      extraAliases = concatMapStrings (alias cfg.listDomain) cfg.mailLists;
+
+      extraConfig = ''
+        transport = hash:${stateDir}/transports
+        virtual = hash:${stateDir}/virtuals
+      '';
+    };
+
+    environment.systemPackages = [ pkgs.mlmmj ];
+
+    system.activationScripts.mlmmj = ''
+          ${pkgs.coreutils}/bin/mkdir -p ${stateDir} ${spoolDir}/${cfg.listDomain}
+          ${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} ${spoolDir}
+          ${lib.concatMapStrings (createList cfg.listDomain) cfg.mailLists}
+          echo ${lib.concatMapStrings (virtual cfg.listDomain) cfg.mailLists} > ${stateDir}/virtuals
+          echo ${cfg.listDomain} mailman: > ${stateDir}/transports
+          echo ${lib.concatMapStrings (transport cfg.listDomain) cfg.mailLists} >> ${stateDir}/transports
+    '';
+
+    systemd.services."mlmmj-maintd" = {
+      description = "mlmmj maintenance daemon";
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        ExecStart = "${pkgs.mlmmj}/bin/mlmmj-maintd -F -d ${spoolDir}/${cfg.listDomain}";
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/misc/siproxd.nix b/nixos/modules/services/misc/siproxd.nix
new file mode 100644
index 000000000000..9e8fb6c228f2
--- /dev/null
+++ b/nixos/modules/services/misc/siproxd.nix
@@ -0,0 +1,180 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.siproxd;
+
+  conf = ''
+    daemonize = 0
+    rtp_proxy_enable = 1
+    user = siproxd
+    if_inbound  = ${cfg.ifInbound}
+    if_outbound = ${cfg.ifOutbound}
+    sip_listen_port = ${toString cfg.sipListenPort}
+    rtp_port_low    = ${toString cfg.rtpPortLow}
+    rtp_port_high   = ${toString cfg.rtpPortHigh}
+    rtp_dscp        = ${toString cfg.rtpDscp}
+    sip_dscp        = ${toString cfg.sipDscp}
+    ${optionalString (cfg.hostsAllowReg != []) "hosts_allow_reg = ${concatStringsSep "," cfg.hostsAllowReg}"}
+    ${optionalString (cfg.hostsAllowSip != []) "hosts_allow_sip = ${concatStringsSep "," cfg.hostsAllowSip}"}
+    ${optionalString (cfg.hostsDenySip != []) "hosts_deny_sip  = ${concatStringsSep "," cfg.hostsDenySip}"}
+    ${if (cfg.passwordFile != "") then "proxy_auth_pwfile = ${cfg.passwordFile}" else ""}
+    ${cfg.extraConfig}
+  '';
+
+  confFile = builtins.toFile "siproxd.conf" conf;
+
+in
+{
+  ##### interface
+
+  options = {
+
+    services.siproxd = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the Siproxd SIP 
+	  proxy/masquerading daemon.
+        '';
+      };
+
+      ifInbound = mkOption {
+        type = types.str;
+        example = "eth0";
+        description = "Local network interface";
+      };
+
+      ifOutbound = mkOption {
+        type = types.str;
+        example = "ppp0";
+        description = "Public network interface";
+      };
+
+      hostsAllowReg = mkOption {
+        type = types.listOf types.str;
+	default = [ ];
+        example = [ "192.168.1.0/24" "192.168.2.0/24" ];
+	description = ''
+          Acess control list for incoming SIP registrations.
+        '';
+      };
+
+      hostsAllowSip = mkOption {
+        type = types.listOf types.str;
+	default = [ ];
+        example = [ "123.45.0.0/16" "123.46.0.0/16" ];
+	description = ''
+          Acess control list for incoming SIP traffic.
+        '';
+      };
+
+      hostsDenySip = mkOption {
+        type = types.listOf types.str;
+	default = [ ];
+        example = [ "10.0.0.0/8" "11.0.0.0/8" ];
+	description = ''
+          Acess control list for denying incoming
+	   SIP registrations and traffic.
+        '';
+      };
+
+      sipListenPort = mkOption {
+        type = types.int;
+        default = 5060;
+        description = ''
+	  Port to listen for incoming SIP messages.
+        '';
+      };
+
+      rtpPortLow = mkOption {
+        type = types.int;
+        default = 7070;
+        description = ''
+         Bottom of UDP port range for incoming and outgoing RTP traffic
+        '';
+      };
+
+      rtpPortHigh = mkOption {
+        type = types.int;
+        default = 7089;
+        description = ''
+         Top of UDP port range for incoming and outgoing RTP traffic
+        '';
+      };
+
+      rtpTimeout = mkOption {
+        type = types.int;
+        default = 300;
+        description = ''
+          Timeout for an RTP stream. If for the specified 
+          number of seconds no data is relayed on an active
+          stream, it is considered dead and will be killed.
+        '';
+      };
+
+      rtpDscp = mkOption {
+        type = types.int;
+        default = 46;
+        description = ''
+          DSCP (differentiated services) value to be assigned
+          to RTP packets. Allows QOS aware routers to handle 
+          different types traffic with different priorities.
+        '';
+      };
+
+      sipDscp = mkOption {
+        type = types.int;
+        default = 0;
+        description = ''
+          DSCP (differentiated services) value to be assigned
+          to SIP packets. Allows QOS aware routers to handle 
+          different types traffic with different priorities.
+        '';
+      };
+
+      passwordFile = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Path to per-user password file.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra configuration to add to siproxd configuration.
+        '';
+      };
+
+    };
+
+  };
+
+  ##### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = singleton {
+      name = "siproxyd";
+      uid = config.ids.uids.siproxd;
+    };
+
+    systemd.services.siproxd = {
+      description = "SIP proxy/masquerading daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      serviceConfig = {
+        ExecStart = "${pkgs.siproxd}/sbin/siproxd -c ${confFile}";
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix
index 5a353fc0942a..866707c3a913 100644
--- a/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixos/modules/services/networking/dhcpcd.nix
@@ -7,9 +7,10 @@ let
   dhcpcd = if !config.boot.isContainer then pkgs.dhcpcd else pkgs.dhcpcd.override { udev = null; };
 
   # Don't start dhcpcd on explicitly configured interfaces or on
-  # interfaces that are part of a bridge.
+  # interfaces that are part of a bridge, bond or sit device.
   ignoredInterfaces =
     map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces))
+    ++ mapAttrsToList (i: _: i) config.networking.sits
     ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges))
     ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds))
     ++ config.networking.dhcpcd.denyInterfaces;
@@ -35,7 +36,7 @@ let
       # Ignore peth* devices; on Xen, they're renamed physical
       # Ethernet cards used for bridging.  Likewise for vif* and tap*
       # (Xen) and virbr* and vnet* (libvirt).
-      denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet*
+      denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet* sit*
 
       ${config.networking.dhcpcd.extraConfig}
     '';
diff --git a/nixos/modules/services/networking/dhcpd.nix b/nixos/modules/services/networking/dhcpd.nix
index e5e1c103c686..900df67b53aa 100644
--- a/nixos/modules/services/networking/dhcpd.nix
+++ b/nixos/modules/services/networking/dhcpd.nix
@@ -13,7 +13,7 @@ let
       default-lease-time 600;
       max-lease-time 7200;
       authoritative;
-      ddns-update-style ad-hoc;
+      ddns-update-style interim;
       log-facility local1; # see dhcpd.nix
 
       ${cfg.extraConfig}
@@ -108,22 +108,41 @@ in
 
   config = mkIf config.services.dhcpd.enable {
 
-    jobs.dhcpd =
+    users = {
+      extraUsers.dhcpd = {
+        uid = config.ids.uids.dhcpd;
+        description = "DHCP daemon user";
+      };
+    };
+
+    systemd.services.dhcpd =
       { description = "DHCP server";
 
-        startOn = "started network-interfaces";
-        stopOn = "stopping network-interfaces";
+        wantedBy = [ "multi-user.target" ];
 
-        script =
+        after = [ "network.target" ];
+
+        path = [ pkgs.dhcp ];
+
+        preStart =
           ''
             mkdir -m 755 -p ${stateDir}
 
             touch ${stateDir}/dhcpd.leases
 
-            exec ${pkgs.dhcp}/sbin/dhcpd -f -cf ${configFile} \
-                -lf ${stateDir}/dhcpd.leases \
-                ${toString cfg.interfaces}
+            mkdir -m 755 -p /run/dhcpd
+            chown dhcpd /run/dhcpd
           '';
+
+        serviceConfig =
+          { ExecStart = "@${pkgs.dhcp}/sbin/dhcpd dhcpd"
+              + " -pf /run/dhcpd/dhcpd.pid -cf ${configFile}"
+              + " -lf ${stateDir}/dhcpd.leases -user dhcpd -group nogroup"
+              + " ${toString cfg.interfaces}";
+            Restart = "always";
+            Type = "forking";
+            PIDFile = "/run/dhcpd/dhcpd.pid";
+          };
       };
 
   };
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 78f3cf2b7e49..b83cf276ed52 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -130,7 +130,7 @@ let
   '';
 
 
-  loggingConf = ''
+  loggingConf = (if mainCfg.logFormat != "none" then ''
     ErrorLog ${mainCfg.logDir}/error_log
 
     LogLevel notice
@@ -141,7 +141,9 @@ let
     LogFormat "%{User-agent}i" agent
 
     CustomLog ${mainCfg.logDir}/access_log ${mainCfg.logFormat}
-  '';
+  '' else ''
+    ErrorLog /dev/null
+  '');
 
 
   browserHacks = ''
diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix
index f0f59a664026..fc9487ab4859 100644
--- a/nixos/modules/services/web-servers/lighttpd/default.nix
+++ b/nixos/modules/services/web-servers/lighttpd/default.nix
@@ -9,9 +9,9 @@ let
   cfg = config.services.lighttpd;
 
   needModRedirect = cfg.gitweb.enable;
-  needModAlias = cfg.cgit.enable or cfg.gitweb.enable;
-  needModSetenv = cfg.cgit.enable or cfg.gitweb.enable;
-  needModCgi = cfg.cgit.enable or cfg.gitweb.enable;
+  needModAlias = cfg.cgit.enable || cfg.gitweb.enable;
+  needModSetenv = cfg.cgit.enable || cfg.gitweb.enable;
+  needModCgi = cfg.cgit.enable || cfg.gitweb.enable;
   needModStatus = cfg.mod_status;
   needModUserdir = cfg.mod_userdir;
 
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index df50ca8c905c..06bcb6dbb8be 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -35,6 +35,14 @@ in {
       description = "Enable Gnome 3 desktop manager.";
     };
 
+    services.xserver.desktopManager.gnome3.sessionPath = mkOption {
+      default = [];
+      example = "[ pkgs.gnome3.gpaste ]";
+      description = "Additional list of packages to be added to the session search path.
+                     Useful for gnome shell extensions or gsettings-conditionated autostart.";
+      apply = list: list ++ [ gnome3.gnome_shell ]; 
+    };
+
     environment.gnome3.packageSet = mkOption {
       default = pkgs.gnome3;
       example = literalExample "pkgs.gnome3_12";
@@ -86,10 +94,19 @@ in {
 
           export XDG_MENU_PREFIX=gnome
 
-          # Don't let epiphany depend upon gnome-shell
-          # Don't let gnome-session depend upon vino (for .desktop autostart condition)
+          ${concatMapStrings (p: ''
+            if [ -d "${p}/share/gsettings-schemas/${p.name}" ]; then
+              export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${p}/share/gsettings-schemas/${p.name}
+            fi
+
+            if [ -d "${p}/lib/girepository-1.0" ]; then
+              export GI_TYPELIB_PATH=$GI_TYPELIB_PATH''${GI_TYPELIB_PATH:+:}${p}/lib/girepository-1.0
+              export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}${p}/lib
+            fi
+          '') cfg.sessionPath}
+
           # Override default mimeapps
-          export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${gnome3.gnome_shell}/share/gsettings-schemas/${gnome3.gnome_shell.name}:${gnome3.vino}/share/gsettings-schemas/${gnome3.vino.name}:${mimeAppsList}/share
+          export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${mimeAppsList}/share
 
           # Let gnome-control-center find gnome-shell search providers
           export GNOME_SEARCH_PROVIDERS_DIR=${config.system.path}/share/gnome-shell/search-providers/
@@ -123,7 +140,7 @@ in {
         gnome3.gnome_settings_daemon
         gnome3.gnome_shell
         gnome3.gnome_themes_standard
-      ] ++ (removePackagesByName [
+      ] ++ cfg.sessionPath ++ (removePackagesByName [
         gnome3.baobab
         gnome3.empathy
         gnome3.eog
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index b1bad956b4bb..2e5a70b3aa54 100644
--- a/nixos/modules/system/activation/activation-script.nix
+++ b/nixos/modules/system/activation/activation-script.nix
@@ -66,6 +66,9 @@ in
                 PATH=$PATH:$i/bin:$i/sbin
             done
 
+            _status=0
+            trap "_status=1" ERR
+
             # Ensure a consistent umask.
             umask 0022
 
@@ -84,6 +87,8 @@ in
 
             # Prevent the current configuration from being garbage-collected.
             ln -sfn /run/current-system /nix/var/nix/gcroots/current-system
+
+            exit $_status
           '';
       };
 
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 6a069c5d0540..1d3878054432 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -199,6 +199,21 @@ let
         { object = pkgs.writeText "mdadm.conf" config.boot.initrd.mdadmConf;
           symlink = "/etc/mdadm.conf";
         }
+        { object = config.environment.etc."modprobe.d/nixos.conf".source;
+          symlink = "/etc/modprobe.d/nixos.conf";
+        }
+        { object = pkgs.stdenv.mkDerivation {
+            name = "initrd-kmod-blacklist-ubuntu";
+            builder = pkgs.writeText "builder.sh" ''
+              source $stdenv/setup
+              target=$out
+
+              ${pkgs.perl}/bin/perl -0pe 's/## file: iwlwifi.conf(.+?)##/##/s;' $src > $out
+            '';
+            src = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf";
+          };
+          symlink = "/etc/modprobe.d/ubuntu.conf";
+        }
       ];
   };
 
diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh
index fcefdfa88a36..6fff776f8581 100644
--- a/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixos/modules/system/boot/stage-2-init.sh
@@ -29,7 +29,9 @@ setPath "@path@"
 # Normally, stage 1 mounts the root filesystem read/writable.
 # However, in some environments, stage 2 is executed directly, and the
 # root is read-only.  So make it writable here.
-mount -n -o remount,rw none /
+if [ "$container" != systemd-nspawn ]; then
+    mount -n -o remount,rw none /
+fi
 
 
 # Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 455c40693b00..e353e9246b0e 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -744,7 +744,7 @@ in
         # Make all journals readable to users in the wheel and adm
         # groups, in addition to those in the systemd-journal group.
         # Users can always read their own journals.
-        ${pkgs.acl}/bin/setfacl -nm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal
+        ${pkgs.acl}/bin/setfacl -nm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal || true
       '';
 
     # Target for ‘charon send-keys’ to hook into.
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 991f9f261450..7dabe70f00c4 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -7,6 +7,7 @@ let
   cfg = config.networking;
   interfaces = attrValues cfg.interfaces;
   hasVirtuals = any (i: i.virtual) interfaces;
+  hasSits = cfg.sits != { };
   hasBonds = cfg.bonds != { };
 
   interfaceOpts = { name, ... }: {
@@ -321,6 +322,66 @@ in
       };
     };
 
+    networking.sits = mkOption {
+      type = types.attrsOf types.optionSet;
+      default = { };
+      example = {
+        hurricane = {
+          remote = "10.0.0.1";
+          local = "10.0.0.22";
+          ttl = 255;
+        };
+        msipv6 = {
+          remote = "192.168.0.1";
+          dev = "enp3s0";
+          ttl = 127;
+        };
+      };
+      description = ''
+        This option allows you to define 6-to-4 interfaces which should be automatically created.
+      '';
+      options = {
+
+        remote = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          example = "10.0.0.1";
+          description = ''
+            The address of the remote endpoint to forward traffic over.
+          '';
+        };
+
+        local = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          example = "10.0.0.22";
+          description = ''
+            The address of the local endpoint which the remote
+            side should send packets to.
+          '';
+        };
+
+        ttl = mkOption {
+          type = types.nullOr types.int;
+          default = null;
+          example = 255;
+          description = ''
+            The time-to-live of the connection to the remote tunnel endpoint.
+          '';
+        };
+
+        dev = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          example = "enp4s0f0";
+          description = ''
+            The underlying network device on which the tunnel resides.
+          '';
+        };
+
+      };
+    };
+
     networking.vlans = mkOption {
       default = { };
       example = {
@@ -380,6 +441,7 @@ in
     boot.kernelModules = [ ]
       ++ optional cfg.enableIPv6 "ipv6"
       ++ optional hasVirtuals "tun"
+      ++ optional hasSits "sit"
       ++ optional hasBonds "bonding";
 
     boot.extraModprobeConfig =
@@ -641,6 +703,32 @@ in
             '';
           };
 
+        createSitDevice = n: v:
+          let
+            deps = optional (v.dev != null) "sys-subsystem-net-devices-${v.dev}.device";
+          in
+          { description = "6-to-4 Tunnel Interface ${n}";
+            wantedBy = [ "network.target" "sys-subsystem-net-devices-${n}.device" ];
+            bindsTo = deps;
+            after = deps;
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.iproute ];
+            script = ''
+              # Remove Dead Interfaces
+              ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
+              ip link add "${n}" type sit \
+                ${optionalString (v.remote != null) "remote \"${v.remote}\""} \
+                ${optionalString (v.local != null) "local \"${v.local}\""} \
+                ${optionalString (v.ttl != null) "ttl ${toString v.ttl}"} \
+                ${optionalString (v.dev != null) "dev \"${v.dev}\""}
+              ip link set "${n}" up
+            '';
+            postStop = ''
+              ip link delete "${n}"
+            '';
+          };
+
         createVlanDevice = n: v:
           let
             deps = [ "sys-subsystem-net-devices-${v.interface}.device" ];
@@ -668,6 +756,7 @@ in
            map createTunDevice (filter (i: i.virtual) interfaces))
          // mapAttrs createBridgeDevice cfg.bridges
          // mapAttrs createBondDevice cfg.bonds
+         // mapAttrs createSitDevice cfg.sits
          // mapAttrs createVlanDevice cfg.vlans
          // { "network-setup" = networkSetup; };
 
diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix
index b81f97f2b4ec..84e3aa283520 100644
--- a/nixos/modules/virtualisation/container-config.nix
+++ b/nixos/modules/virtualisation/container-config.nix
@@ -89,6 +89,8 @@ with lib;
         restartIfChanged = false;
       };
 
+    systemd.services.systemd-remount-fs.enable = false;
+
   };
 
 }
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index d0d04d9a1e5d..292b96e6eb24 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -32,7 +32,10 @@ let
         fi
       fi
 
-      exec "$1"
+      # Start the regular stage 1 script, passing the bind-mounted
+      # notification socket from the host to allow the container
+      # systemd to signal readiness to the host systemd.
+      NOTIFY_SOCKET=/var/lib/private/host-notify exec "$1"
     '';
 
   system = config.nixpkgs.system;
@@ -168,17 +171,18 @@ in
 
         preStart =
           ''
-            mkdir -p -m 0755 $root/var/lib
+            # Clean up existing machined registration and interfaces.
+            machinectl terminate "$INSTANCE" 2> /dev/null || true
 
-            # Create a named pipe to get a signal when the container
-            # has finished booting.
-            rm -f $root/var/lib/startup-done
-            mkfifo -m 0600 $root/var/lib/startup-done
+            if [ "$PRIVATE_NETWORK" = 1 ]; then
+              ip link del dev "ve-$INSTANCE" 2> /dev/null || true
+            fi
          '';
 
         script =
           ''
             mkdir -p -m 0755 "$root/etc" "$root/var/lib"
+            mkdir -p -m 0700 "$root/var/lib/private"
             if ! [ -e "$root/etc/os-release" ]; then
               touch "$root/etc/os-release"
             fi
@@ -187,6 +191,8 @@ in
               "/nix/var/nix/profiles/per-container/$INSTANCE" \
               "/nix/var/nix/gcroots/per-container/$INSTANCE"
 
+            cp -f /etc/resolv.conf "$root/etc/resolv.conf"
+
             if [ "$PRIVATE_NETWORK" = 1 ]; then
               extraFlags+=" --network-veth"
             fi
@@ -203,12 +209,16 @@ in
               fi
             ''}
 
+            # Run systemd-nspawn without startup notification (we'll
+            # wait for the container systemd to signal readiness).
+            EXIT_ON_REBOOT=1 NOTIFY_SOCKET= \
             exec ${config.systemd.package}/bin/systemd-nspawn \
               --keep-unit \
               -M "$INSTANCE" -D "$root" $extraFlags \
               --bind-ro=/nix/store \
               --bind-ro=/nix/var/nix/db \
               --bind-ro=/nix/var/nix/daemon-socket \
+              --bind=/run/systemd/notify:/var/lib/private/host-notify \
               --bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \
               --bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \
               --setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \
@@ -220,12 +230,6 @@ in
 
         postStart =
           ''
-            # This blocks until the container-startup-done service
-            # writes something to this pipe.  FIXME: it also hangs
-            # until the start timeout expires if systemd-nspawn exits.
-            read x < $root/var/lib/startup-done
-            rm -f $root/var/lib/startup-done
-
             if [ "$PRIVATE_NETWORK" = 1 ]; then
               ifaceHost=ve-$INSTANCE
               ip link set dev $ifaceHost up
@@ -240,23 +244,42 @@ in
 
         preStop =
           ''
-            machinectl poweroff "$INSTANCE"
+            machinectl poweroff "$INSTANCE" || true
           '';
 
         restartIfChanged = false;
         #reloadIfChanged = true; # FIXME
 
-        serviceConfig.ExecReload = pkgs.writeScript "reload-container"
-          ''
-            #! ${pkgs.stdenv.shell} -e
-            SYSTEM_PATH=/nix/var/nix/profiles/system
-            echo $SYSTEM_PATH/bin/switch-to-configuration test | \
-              ${pkgs.socat}/bin/socat unix:$root/var/lib/run-command.socket -
-          '';
+        serviceConfig = {
+          ExecReload = pkgs.writeScript "reload-container"
+            ''
+              #! ${pkgs.stdenv.shell} -e
+              SYSTEM_PATH=/nix/var/nix/profiles/system
+              echo $SYSTEM_PATH/bin/switch-to-configuration test | \
+                ${pkgs.socat}/bin/socat unix:$root/var/lib/run-command.socket -
+            '';
+
+          SyslogIdentifier = "container %i";
+
+          EnvironmentFile = "-/etc/containers/%i.conf";
+
+          Type = "notify";
+
+          NotifyAccess = "all";
 
-        serviceConfig.SyslogIdentifier = "container %i";
+          # Note that on reboot, systemd-nspawn returns 10, so this
+          # unit will be restarted. On poweroff, it returns 0, so the
+          # unit won't be restarted.
+          Restart = "on-failure";
 
-        serviceConfig.EnvironmentFile = "-/etc/containers/%i.conf";
+          # Hack: we don't want to kill systemd-nspawn, since we call
+          # "machinectl poweroff" in preStop to shut down the
+          # container cleanly. But systemd requires sending a signal
+          # (at least if we want remaining processes to be killed
+          # after the timeout). So send an ignored signal.
+          KillMode = "mixed";
+          KillSignal = "WINCH";
+        };
       };
 
     # Generate a configuration file in /etc/containers for each
@@ -290,5 +313,30 @@ in
 
     environment.systemPackages = [ nixos-container ];
 
+    # Start containers at boot time.
+    systemd.services.all-containers =
+      { description = "All Containers";
+
+        wantedBy = [ "multi-user.target" ];
+
+        unitConfig.ConditionDirectoryNotEmpty = "/etc/containers";
+
+        serviceConfig.Type = "oneshot";
+
+        script =
+          ''
+            res=0
+            shopt -s nullglob
+            for i in /etc/containers/*.conf; do
+              AUTO_START=
+              source "$i"
+              if [ "$AUTO_START" = 1 ]; then
+                systemctl start "container@$(basename "$i" .conf).service" || res=1
+              fi
+            done
+            exit $res
+          ''; # */
+      };
+
   };
 }
diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl
index 5083abd84489..bf6f16fc6c77 100644
--- a/nixos/modules/virtualisation/nixos-container.pl
+++ b/nixos/modules/virtualisation/nixos-container.pl
@@ -17,25 +17,31 @@ umask 0022;
 sub showHelp {
     print <<EOF;
 Usage: nixos-container list
-       nixos-container create <container-name> [--config <string>] [--ensure-unique-name]
+       nixos-container create <container-name> [--system-path <path>] [--config <string>] [--ensure-unique-name] [--auto-start]
        nixos-container destroy <container-name>
        nixos-container start <container-name>
        nixos-container stop <container-name>
+       nixos-container status <container-name>
        nixos-container login <container-name>
        nixos-container root-login <container-name>
        nixos-container run <container-name> -- args...
        nixos-container set-root-password <container-name> <password>
        nixos-container show-ip <container-name>
+       nixos-container show-host-key <container-name>
 EOF
     exit 0;
 }
 
+my $systemPath;
 my $ensureUniqueName = 0;
+my $autoStart = 0;
 my $extraConfig;
 
 GetOptions(
     "help" => sub { showHelp() },
     "ensure-unique-name" => \$ensureUniqueName,
+    "auto-start" => \$autoStart,
+    "system-path=s" => \$systemPath,
     "config=s" => \$extraConfig
     ) or exit 1;
 
@@ -122,17 +128,13 @@ if ($action eq "create") {
     push @conf, "PRIVATE_NETWORK=1\n";
     push @conf, "HOST_ADDRESS=$hostAddress\n";
     push @conf, "LOCAL_ADDRESS=$localAddress\n";
+    push @conf, "AUTO_START=$autoStart\n";
     write_file($confFile, \@conf);
 
     close($lock);
 
     print STDERR "host IP is $hostAddress, container IP is $localAddress\n";
 
-    mkpath("$root/etc/nixos", 0, 0755);
-
-    my $nixosConfigFile = "$root/etc/nixos/configuration.nix";
-    writeNixOSConfig $nixosConfigFile;
-
     # The per-container directory is restricted to prevent users on
     # the host from messing with guest users who happen to have the
     # same uid.
@@ -141,10 +143,21 @@ if ($action eq "create") {
     $profileDir = "$profileDir/$containerName";
     mkpath($profileDir, 0, 0755);
 
-    system("nix-env", "-p", "$profileDir/system",
-           "-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>",
-           "--set", "-A", "system") == 0
-        or die "$0: failed to build initial container configuration\n";
+    # Build/set the initial configuration.
+    if (defined $systemPath) {
+        system("nix-env", "-p", "$profileDir/system", "--set", $systemPath) == 0
+            or die "$0: failed to set initial container configuration\n";
+    } else {
+        mkpath("$root/etc/nixos", 0, 0755);
+
+        my $nixosConfigFile = "$root/etc/nixos/configuration.nix";
+        writeNixOSConfig $nixosConfigFile;
+
+        system("nix-env", "-p", "$profileDir/system",
+               "-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>",
+               "--set", "-A", "system") == 0
+            or die "$0: failed to build initial container configuration\n";
+    }
 
     print "$containerName\n" if $ensureUniqueName;
     exit 0;
@@ -152,8 +165,16 @@ if ($action eq "create") {
 
 my $root = "/var/lib/containers/$containerName";
 my $profileDir = "/nix/var/nix/profiles/per-container/$containerName";
+my $gcRootsDir = "/nix/var/nix/gcroots/per-container/$containerName";
 my $confFile = "/etc/containers/$containerName.conf";
-die "$0: container ‘$containerName’ does not exist\n" if !-e $confFile;
+if (!-e $confFile) {
+    if ($action eq "destroy") {
+        exit 0;
+    } elsif ($action eq "status") {
+        print "gone\n";
+    }
+    die "$0: container ‘$containerName’ does not exist\n" ;
+}
 
 sub isContainerRunning {
     my $status = `systemctl show 'container\@$containerName'`;
@@ -172,6 +193,7 @@ if ($action eq "destroy") {
     stopContainer if isContainerRunning;
 
     rmtree($profileDir) if -e $profileDir;
+    rmtree($gcRootsDir) if -e $gcRootsDir;
     rmtree($root) if -e $root;
     unlink($confFile) or die;
 }
@@ -185,6 +207,10 @@ elsif ($action eq "stop") {
     stopContainer;
 }
 
+elsif ($action eq "status") {
+    print isContainerRunning() ? "up" : "down", "\n";
+}
+
 elsif ($action eq "update") {
     my $nixosConfigFile = "$root/etc/nixos/configuration.nix";
 
@@ -239,6 +265,12 @@ elsif ($action eq "show-ip") {
     print "$1\n";
 }
 
+elsif ($action eq "show-host-key") {
+    my $fn = "$root/etc/ssh/ssh_host_ecdsa_key.pub";
+    exit 1 if ! -f $fn;
+    print read_file($fn);
+}
+
 else {
     die "$0: unknown action ‘$action’\n";
 }
diff --git a/nixos/release.nix b/nixos/release.nix
index ed413d3e928f..0620b46d46ad 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -78,6 +78,16 @@ let
         };
 
 
+  makeClosure = module: forAllSystems (system: (import ./lib/eval-config.nix {
+    inherit system;
+    modules = [ module ] ++ lib.singleton
+      ({ config, lib, ... }:
+      { fileSystems."/".device  = lib.mkDefault "/dev/sda1";
+        boot.loader.grub.device = lib.mkDefault "/dev/sda";
+      });
+  }).config.system.build.toplevel);
+
+
 in rec {
 
   channel =
@@ -242,4 +252,46 @@ in rec {
   tests.udisks2 = callTest tests/udisks2.nix {};
   tests.xfce = callTest tests/xfce.nix {};
 
+
+  /* Build a bunch of typical closures so that Hydra can keep track of
+     the evolution of closure sizes. */
+
+  closures = {
+
+    smallContainer = makeClosure ({ pkgs, ... }:
+      { boot.isContainer = true;
+        services.openssh.enable = true;
+      });
+
+    tinyContainer = makeClosure ({ pkgs, ... }:
+      { boot.isContainer = true;
+        imports = [ modules/profiles/minimal.nix ];
+      });
+
+    ec2 = makeClosure ({ pkgs, ... }:
+      { imports = [ modules/virtualisation/amazon-image.nix ];
+      });
+
+    kde = makeClosure ({ pkgs, ... }:
+      { services.xserver.enable = true;
+        services.xserver.displayManager.kdm.enable = true;
+        services.xserver.desktopManager.kde4.enable = true;
+      });
+
+    xfce = makeClosure ({ pkgs, ... }:
+      { services.xserver.enable = true;
+        services.xserver.desktopManager.xfce.enable = true;
+      });
+
+    # Linux/Apache/PostgreSQL/PHP stack.
+    lapp = makeClosure ({ pkgs, ... }:
+      { services.httpd.enable = true;
+        services.httpd.adminAddr = "foo@example.org";
+        services.postgresql.enable = true;
+        services.postgresql.package = pkgs.postgresql93;
+        environment.systemPackages = [ pkgs.php ];
+      });
+
+  };
+
 }