diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..0ca2db01 --- /dev/null +++ b/flake.lock @@ -0,0 +1,77 @@ +{ + "nodes": { + "flake-utils": { + "locked": { + "lastModified": 1656928814, + "narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1657114324, + "narHash": "sha256-fWuaUNXrHcz/ciHRHlcSO92dvV3EVS0GJQUSBO5JIB4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "a5c867d9fe9e4380452628e8f171c26b69fa9d3d", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1657261001, + "narHash": "sha256-sUZeuRYfhG59uD6xafM07bc7bAIkpcGq84Vj4B+cyms=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "0be91cefefde5701f8fa957904618a13e3bb51d8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "poetry2nix": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1657149754, + "narHash": "sha256-iSnZoqwNDDVoO175whSuvl4sS9lAb/2zZ3Sa4ywo970=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "fc1930e011dea149db81863aac22fe701f36f1b5", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "poetry2nix", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "poetry2nix": "poetry2nix" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..77522866 --- /dev/null +++ b/flake.nix @@ -0,0 +1,55 @@ +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + poetry2nix.url = "github:nix-community/poetry2nix"; + }; + outputs = { self, nixpkgs, poetry2nix }@inputs: + let + supportedSystems = [ "x86_64-linux" "aarch64-linux" ]; + forSystems = systems: f: + nixpkgs.lib.genAttrs systems + (system: f system (import nixpkgs { inherit system; overlays = [ poetry2nix.overlay self.overlays.default ]; })); + forAllSystems = forSystems supportedSystems; + projectName = "lnbits"; + in + { + devShells = forAllSystems (system: pkgs: { + default = pkgs.mkShell { + buildInputs = with pkgs; [ + nodePackages.prettier + ]; + }; + }); + overlays = { + default = final: prev: { + ${projectName} = self.packages.${final.hostPlatform.system}.${projectName}; + }; + }; + packages = forAllSystems (system: pkgs: { + default = self.packages.${system}.${projectName}; + ${projectName} = pkgs.poetry2nix.mkPoetryApplication { + projectDir = ./.; + python = pkgs.python39; + }; + }); + nixosModules = forAllSystems (system: pkgs: { + default = { pkgs, lib, config, ... }: { + imports = [ "${./nix/modules/${projectName}-service.nix}" ]; + nixpkgs.overlays = [ self.overlays.default ]; + }; + }); + checks = forAllSystems (system: pkgs: + let + vmTests = import ./nix/tests { + makeTest = (import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; }).makeTest; + inherit inputs pkgs; + }; + in + pkgs.lib.optionalAttrs pkgs.stdenv.isLinux vmTests # vmTests can only be ran on Linux, so append them only if on Linux. + // + { + # Other checks here... + } + ); + }; +} diff --git a/nix/modules/lnbits-service.nix b/nix/modules/lnbits-service.nix new file mode 100644 index 00000000..5d8e0640 --- /dev/null +++ b/nix/modules/lnbits-service.nix @@ -0,0 +1,106 @@ +{ config, pkgs, lib, ... }: + +let + defaultUser = "lnbits"; + cfg = config.services.lnbits; + inherit (lib) mkOption mkIf types optionalAttrs; +in + +{ + options = { + services.lnbits = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to enable the lnbits service + ''; + }; + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Whether to open the ports used by lnbits in the firewall for the server + ''; + }; + package = mkOption { + type = types.package; + default = pkgs.lnbits; + description = '' + The lnbits package to use. + ''; + }; + stateDir = mkOption { + type = types.path; + default = "/var/lib/lnbits"; + description = '' + The lnbits state directory which LNBITS_DATA_FOLDER will be set to + ''; + }; + host = mkOption { + type = types.str; + default = "127.0.0.1"; + description = '' + The host to bind to + ''; + }; + port = mkOption { + type = types.port; + default = 8231; + description = '' + The port to run on + ''; + }; + user = mkOption { + type = types.str; + default = "lnbits"; + description = "user to run lnbits as"; + }; + group = mkOption { + type = types.str; + default = "lnbits"; + description = "group to run lnbits as"; + }; + }; + }; + + config = mkIf cfg.enable { + users.users = optionalAttrs (cfg.user == defaultUser) { + ${defaultUser} = { + isSystemUser = true; + group = defaultUser; + }; + }; + + users.groups = optionalAttrs (cfg.group == defaultUser) { + ${defaultUser} = { }; + }; + + systemd.tmpfiles.rules = [ + "d ${cfg.stateDir} 0700 ${cfg.user} ${cfg.group} - -" + ]; + + systemd.services.lnbits = { + enable = true; + description = "lnbits"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + environment = { + LNBITS_DATA_FOLDER = "${cfg.stateDir}"; + }; + serviceConfig = { + User = cfg.user; + Group = cfg.group; + WorkingDirectory = "${cfg.package.src}"; + StateDirectory = "${cfg.stateDir}"; + ExecStart = "${lib.getExe cfg.package} --port ${toString cfg.port} --host ${cfg.host}"; + Restart = "always"; + PrivateTmp = true; + }; + }; + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.port ]; + }; + }; +} + diff --git a/nix/tests/default.nix b/nix/tests/default.nix new file mode 100644 index 00000000..7b8513ac --- /dev/null +++ b/nix/tests/default.nix @@ -0,0 +1,4 @@ +{ pkgs, makeTest, inputs }: +{ + vmTest = import ./nixos-module { inherit pkgs makeTest inputs; }; +} diff --git a/nix/tests/nixos-module/default.nix b/nix/tests/nixos-module/default.nix new file mode 100644 index 00000000..5649ae59 --- /dev/null +++ b/nix/tests/nixos-module/default.nix @@ -0,0 +1,25 @@ +{ pkgs, makeTest, inputs }: +makeTest { + nodes = { + client = { config, pkgs, ... }: { + environment.systemPackages = [ pkgs.curl ]; + }; + lnbits = { ... }: { + imports = [ inputs.self.nixosModules.${pkgs.hostPlatform.system}.default ]; + services.lnbits = { + enable = true; + openFirewall = true; + host = "0.0.0.0"; + }; + }; + }; + testScript = { nodes, ... }: '' + start_all() + lnbits.wait_for_open_port(${toString nodes.lnbits.config.services.lnbits.port}) + client.wait_for_unit("multi-user.target") + with subtest("Check that the lnbits webserver can be reached."): + assert "