diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index b2cb121d1d63..149062a6b332 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -267,6 +267,7 @@
graylog = 243;
sniproxy = 244;
nzbget = 245;
+ mosquitto = 246;
# When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
@@ -504,6 +505,7 @@
emby = 242;
sniproxy = 244;
nzbget = 245;
+ mosquitto = 246;
# When adding a gid, make sure it doesn't match an existing
# uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 370220d253a5..be41b5ebcdd7 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -347,6 +347,7 @@
./services/networking/mjpg-streamer.nix
./services/networking/minidlna.nix
./services/networking/miniupnpd.nix
+ ./services/networking/mosquitto.nix
./services/networking/mstpd.nix
./services/networking/murmur.nix
./services/networking/namecoind.nix
diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix
new file mode 100644
index 000000000000..f926cd710c8d
--- /dev/null
+++ b/nixos/modules/services/networking/mosquitto.nix
@@ -0,0 +1,219 @@
+{ config, lib, pkgs, ...}:
+
+with lib;
+
+let
+ cfg = config.services.mosquitto;
+
+ listenerConf = optionalString cfg.ssl.enable ''
+ listener ${toString cfg.ssl.port} ${cfg.ssl.host}
+ cafile ${cfg.ssl.cafile}
+ certfile ${cfg.ssl.certfile}
+ keyfile ${cfg.ssl.keyfile}
+ '';
+
+ mosquittoConf = pkgs.writeText "mosquitto.conf" ''
+ pid_file /run/mosquitto/pid
+ acl_file ${aclFile}
+ persistence true
+ allow_anonymous ${if cfg.allowAnonymous then "true" else "false"}
+ bind_address ${cfg.host}
+ port ${toString cfg.port}
+ ${listenerConf}
+ ${cfg.extraConf}
+ '';
+
+ userAcl = (concatStringsSep "\n\n" (mapAttrsToList (n: c:
+ "user ${n}\n" + (concatStringsSep "\n" c.acl)) cfg.users
+ ));
+
+ aclFile = pkgs.writeText "mosquitto.acl" ''
+ ${cfg.aclExtraConf}
+ ${userAcl}
+ '';
+
+in
+
+{
+
+ ###### Interface
+
+ options = {
+ services.mosquitto = {
+ enable = mkEnableOption "Enable the MQTT Mosquitto broker.";
+
+ host = mkOption {
+ default = "127.0.0.1";
+ example = "0.0.0.0";
+ type = types.string;
+ description = ''
+ Host to listen on without SSL.
+ '';
+ };
+
+ port = mkOption {
+ default = 1883;
+ example = 1883;
+ type = types.int;
+ description = ''
+ Port on which to listen without SSL.
+ '';
+ };
+
+ ssl = {
+ enable = mkEnableOption "Enable SSL listener.";
+
+ cafile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = "Path to PEM encoded CA certificates.";
+ };
+
+ certfile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = "Path to PEM encoded server certificate.";
+ };
+
+ keyfile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = "Path to PEM encoded server key.";
+ };
+
+ host = mkOption {
+ default = "0.0.0.0";
+ example = "localhost";
+ type = types.string;
+ description = ''
+ Host to listen on with SSL.
+ '';
+ };
+
+ port = mkOption {
+ default = 8883;
+ example = 8883;
+ type = types.int;
+ description = ''
+ Port on which to listen with SSL.
+ '';
+ };
+ };
+
+ dataDir = mkOption {
+ default = "/var/lib/mosquitto";
+ type = types.path;
+ description = ''
+ The data directory.
+ '';
+ };
+
+ users = mkOption {
+ type = types.attrsOf (types.submodule {
+ options = {
+ password = mkOption {
+ type = with types; uniq (nullOr str);
+ default = null;
+ description = ''
+ Specifies the (clear text) password for the MQTT User.
+ '';
+ };
+
+ hashedPassword = mkOption {
+ type = with types; uniq (nullOr str);
+ default = null;
+ description = ''
+ Specifies the hashed password for the MQTT User.
+ overrides .
+ To generate hashed password install mkpasswd
+ package and run mkpasswd -m sha-512.
+ '';
+ };
+
+ acl = mkOption {
+ type = types.listOf types.string;
+ example = [ "topic read A/B" "topic A/#" ];
+ description = ''
+ Control client access to topics on the broker.
+ '';
+ };
+ };
+ });
+ example = { john = { password = "123456"; acl = [ "topic readwrite john/#" ]; }; };
+ description = ''
+ A set of users and their passwords and ACLs.
+ '';
+ };
+
+ allowAnonymous = mkOption {
+ default = false;
+ example = true;
+ type = types.bool;
+ description = ''
+ Allow clients to connect without authentication.
+ '';
+ };
+
+ extraConf = mkOption {
+ default = "";
+ type = types.lines;
+ description = ''
+ Extra config to append to `mosquitto.conf` file.
+ '';
+ };
+
+ aclExtraConf = mkOption {
+ default = "";
+ type = types.lines;
+ description = ''
+ Extra config to prepend to the ACL file.
+ '';
+ };
+
+ };
+ };
+
+
+ ###### Implementation
+
+ config = mkIf cfg.enable {
+
+ systemd.services.mosquitto = {
+ description = "Mosquitto MQTT Broker Daemon";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
+ serviceConfig = {
+ Type = "forking";
+ User = "mosquitto";
+ Group = "mosquitto";
+ RuntimeDirectory = "mosquitto";
+ WorkingDirectory = cfg.dataDir;
+ Restart = "on-failure";
+ ExecStart = "${pkgs.mosquitto}/bin/mosquitto -c ${mosquittoConf} -d";
+ ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+ PIDFile = "/run/mosquitto/pid";
+ };
+ preStart = ''
+ rm -f ${cfg.dataDir}/passwd
+ touch ${cfg.dataDir}/passwd
+ '' + concatStringsSep "\n" (
+ mapAttrsToList (n: c:
+ if c.hashedPassword != null then
+ "echo '${n}:${c.hashedPassword}' > ${cfg.dataDir}/passwd"
+ else optionalString (c.password != null)
+ "${pkgs.mosquitto}/bin/mosquitto_passwd -b ${cfg.dataDir}/passwd ${n} ${c.password}"
+ ) cfg.users);
+ };
+
+ users.extraUsers.mosquitto = {
+ description = "Mosquitto MQTT Broker Daemon owner";
+ group = "mosquitto";
+ uid = config.ids.uids.mosquitto;
+ home = cfg.dataDir;
+ createHome = true;
+ };
+
+ users.extraGroups.mosquitto.gid = config.ids.gids.mosquitto;
+
+ };
+}