diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 6331e76c648..75df6c8d453 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -770,6 +770,7 @@
./services/system/uptimed.nix
./services/torrent/deluge.nix
./services/torrent/flexget.nix
+ ./services/torrent/magnetico.nix
./services/torrent/opentracker.nix
./services/torrent/peerflix.nix
./services/torrent/transmission.nix
diff --git a/nixos/modules/services/torrent/magnetico.nix b/nixos/modules/services/torrent/magnetico.nix
new file mode 100644
index 00000000000..02fa2ac0750
--- /dev/null
+++ b/nixos/modules/services/torrent/magnetico.nix
@@ -0,0 +1,214 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.magnetico;
+
+ dataDir = "/var/lib/magnetico";
+
+ credFile = with cfg.web;
+ if credentialsFile != null
+ then credentialsFile
+ else pkgs.writeText "magnetico-credentials"
+ (concatStrings (mapAttrsToList
+ (user: hash: "${user}:${hash}\n")
+ cfg.web.credentials));
+
+ # default options in magneticod/main.go
+ dbURI = concatStrings
+ [ "sqlite3://${dataDir}/database.sqlite3"
+ "?_journal_mode=WAL"
+ "&_busy_timeout=3000"
+ "&_foreign_keys=true"
+ ];
+
+ crawlerArgs = with cfg.crawler; escapeShellArgs
+ ([ "--database=${dbURI}"
+ "--indexer-addr=${address}:${toString port}"
+ "--indexer-max-neighbors=${toString maxNeighbors}"
+ "--leech-max-n=${toString maxLeeches}"
+ ] ++ extraOptions);
+
+ webArgs = with cfg.web; escapeShellArgs
+ ([ "--database=${dbURI}"
+ (if (cfg.web.credentialsFile != null || cfg.web.credentials != { })
+ then "--credentials=${toString credFile}"
+ else "--no-auth")
+ ] ++ extraOptions);
+
+in {
+
+ ###### interface
+
+ options.services.magnetico = {
+ enable = mkEnableOption "Magnetico, Bittorrent DHT crawler";
+
+ crawler.address = mkOption {
+ type = types.str;
+ default = "0.0.0.0";
+ example = "1.2.3.4";
+ description = ''
+ Address to be used for indexing DHT nodes.
+ '';
+ };
+
+ crawler.port = mkOption {
+ type = types.port;
+ default = 0;
+ description = ''
+ Port to be used for indexing DHT nodes.
+ This port should be added to
+ .
+ '';
+ };
+
+ crawler.maxNeighbors = mkOption {
+ type = types.ints.positive;
+ default = 1000;
+ description = ''
+ Maximum number of simultaneous neighbors of an indexer.
+ Be careful changing this number: high values can very
+ easily cause your network to be congested or even crash
+ your router.
+ '';
+ };
+
+ crawler.maxLeeches = mkOption {
+ type = types.ints.positive;
+ default = 200;
+ description = ''
+ Maximum number of simultaneous leeches.
+ '';
+ };
+
+ crawler.extraOptions = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = ''
+ Extra command line arguments to pass to magneticod.
+ '';
+ };
+
+ web.address = mkOption {
+ type = types.str;
+ default = "localhost";
+ example = "1.2.3.4";
+ description = ''
+ Address the web interface will listen to.
+ '';
+ };
+
+ web.port = mkOption {
+ type = types.port;
+ default = 8080;
+ description = ''
+ Port the web interface will listen to.
+ '';
+ };
+
+ web.credentials = mkOption {
+ type = types.attrsOf types.str;
+ default = {};
+ example = lib.literalExample ''
+ {
+ myuser = "$2y$12$YE01LZ8jrbQbx6c0s2hdZO71dSjn2p/O9XsYJpz.5968yCysUgiaG";
+ }
+ '';
+ description = ''
+ The credentials to access the web interface, in case authentication is
+ enabled, in the format username:hash. If unset no
+ authentication will be required.
+
+ Usernames must start with a lowercase ([a-z]) ASCII character, might
+ contain non-consecutive underscores except at the end, and consists of
+ small-case a-z characters and digits 0-9. The
+ htpasswd tool from the apacheHttpd
+ package may be used to generate the hash: htpasswd
+ -bnBC 12 username password
+
+
+
+ The hashes will be stored world-readable in the nix store.
+ Consider using the credentialsFile option if you
+ don't want this.
+
+
+ '';
+ };
+
+ web.credentialsFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ The path to the file holding the credentials to access the web
+ interface. If unset no authentication will be required.
+
+ The file must constain user names and password hashes in the format
+ username:hash , one for each line. Usernames must
+ start with a lowecase ([a-z]) ASCII character, might contain
+ non-consecutive underscores except at the end, and consists of
+ small-case a-z characters and digits 0-9.
+ The htpasswd tool from the apacheHttpd
+ package may be used to generate the hash:
+ htpasswd -bnBC 12 username password
+ '';
+ };
+
+ web.extraOptions = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = ''
+ Extra command line arguments to pass to magneticow.
+ '';
+ };
+
+ };
+
+ ###### implementation
+
+ config = mkIf cfg.enable {
+
+ users.users.magnetico = {
+ description = "Magnetico daemons user";
+ };
+
+ systemd.services.magneticod = {
+ description = "Magnetico DHT crawler";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network-online.target" ];
+
+ serviceConfig = {
+ User = "magnetico";
+ Restart = "on-failure";
+ ExecStart = "${pkgs.magnetico}/bin/magneticod ${crawlerArgs}";
+ };
+ };
+
+ systemd.services.magneticow = {
+ description = "Magnetico web interface";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network-online.target" "magneticod.service"];
+
+ serviceConfig = {
+ User = "magnetico";
+ StateDirectory = "magnetico";
+ Restart = "on-failure";
+ ExecStart = "${pkgs.magnetico}/bin/magneticow ${webArgs}";
+ };
+ };
+
+ assertions =
+ [
+ {
+ assertion = cfg.web.credentialsFile != null || cfg.web.credentials != { };
+ message = ''
+ The options services.magnetico.web.credentialsFile and
+ services.magnetico.web.credentials are mutually exclusives.
+ '';
+ }
+ ];
+
+ };
+
+}
diff --git a/nixos/tests/magnetico.nix b/nixos/tests/magnetico.nix
new file mode 100644
index 00000000000..bc7aef653ee
--- /dev/null
+++ b/nixos/tests/magnetico.nix
@@ -0,0 +1,28 @@
+import ./make-test.nix ({ pkgs, ...} : {
+ name = "magnetico";
+ meta = with pkgs.stdenv.lib.maintainers; {
+ maintainers = [ rnhmjoj ];
+ };
+
+ machine = { ... }: {
+ imports = [ ../modules/profiles/minimal.nix ];
+
+ networking.firewall.allowedTCPPorts = [ 9000 ];
+
+ services.magnetico = {
+ enable = true;
+ crawler.port = 9000;
+ web.credentials.user = "$2y$12$P88ZF6soFthiiAeXnz64aOWDsY3Dw7Yw8fZ6GtiqFNjknD70zDmNe";
+ };
+ };
+
+ testScript =
+ ''
+ startAll;
+ $machine->waitForUnit("magneticod");
+ $machine->waitForUnit("magneticow");
+ $machine->succeed("${pkgs.curl}/bin/curl -u user:password http://localhost:8080");
+ $machine->succeed("${pkgs.curl}/bin/curl -u user:wrongpwd http://localhost:8080") =~ "Unauthorised." or die;
+ $machine->shutdown();
+ '';
+})
diff --git a/pkgs/applications/networking/p2p/magnetico/default.nix b/pkgs/applications/networking/p2p/magnetico/default.nix
new file mode 100644
index 00000000000..1c266d247b7
--- /dev/null
+++ b/pkgs/applications/networking/p2p/magnetico/default.nix
@@ -0,0 +1,33 @@
+{ lib, fetchFromGitHub, buildGoModule, go-bindata }:
+
+buildGoModule rec {
+ pname = "magnetico";
+ version = "0.8.1";
+
+ src = fetchFromGitHub {
+ owner = "boramalper";
+ repo = "magnetico";
+ rev = "v${version}";
+ sha256 = "1f7y3z9ql079ix6ycihkmd3z3da3sfiqw2fap31pbvvjs65sg644";
+ };
+
+ modSha256 = "1h9fij8mxlxfw7kxix00n10fkhkvmf8529fxbk1n30cxc1bs2szf";
+
+ buildInputs = [ go-bindata ];
+ buildPhase = ''
+ make magneticow magneticod
+ '';
+
+ doCheck = true;
+ checkPhase = ''
+ make test
+ '';
+
+ meta = with lib; {
+ description = "Autonomous (self-hosted) BitTorrent DHT search engine suite.";
+ homepage = https://github.com/boramalper/magnetico;
+ license = licenses.agpl3;
+ badPlatforms = platforms.darwin;
+ maintainers = with maintainers; [ rnhmjoj ];
+ };
+}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index f19df2862c5..31c35347800 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -19460,6 +19460,8 @@ in
marp = callPackage ../applications/office/marp { };
+ magnetico = callPackage ../applications/networking/p2p/magnetico { };
+
matchbox = callPackage ../applications/window-managers/matchbox { };
mblaze = callPackage ../applications/networking/mailreaders/mblaze { };