{ inputs = { # nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; systems.url = "github:nix-systems/default"; flake-parts.url = "github:hercules-ci/flake-parts"; # Lexical is an alternative LSP server. There are several options for Elixir # LSP. See https://gist.github.com/Nezteb/dc63f1d5ad9d88907dd103da2ca000b1 lexical.url = "github:lexical-lsp/lexical"; # Use process-compose to manage background processes during development process-compose-flake.url = "github:Platonic-Systems/process-compose-flake"; }; outputs = { self, nixpkgs, systems, flake-parts, ... } @ inputs: let # Set the Erlang version erlangVersion = "erlang"; # Set the Elixir version elixirVersion = "elixir"; in flake-parts.lib.mkFlake {inherit inputs;} { systems = import systems; imports = [inputs.process-compose-flake.flakeModule]; flake = { nixosModules.default = { config, lib, pkgs, ... }: with lib; let cfg = config.sites.zoeycomputer; in { options.sites.zoeycomputer = { enable = mkEnableOption "Enables the zoey computer"; domain = mkOption rec { type = types.str; default = "zoeys.computer"; example = default; description = "The domain name for the website"; }; ssl = mkOption rec { type = types.bool; default = true; example = default; description = "Whether to enable SSL on the domain or not"; }; phx = { port = mkOption rec { type = types.int; default = 4000; example = default; description = "What port should phoenix run on"; }; package = mkOption rec { type = types.derivation; default = self.packages.${pkgs.system}.default; example = default; description = "The phoenix package containing the application"; }; enableServer = mkOption rec { type = types.bool; default = true; example = default; description = "Enable Phoenix Server, why would you not enable this?"; }; }; }; config = mkIf cfg.enable { services.nginx.virtualHosts.${cfg.domain} = { forceSSL = cfg.ssl; enableACME = cfg.ssl; locations."/".proxyPass = "http://127.0.0.1:${cfg.phx.port}"; }; systemd.services.${release_name} = let release_name = "zoeyscomputer"; working_directory = "/var/lib/zoeycomputer"; in { wantedBy = ["multi-user.target"]; after = ["network.target" "postgresql.service"]; # note that if you are connecting to a postgres instance on a different host # postgresql.service should not be included in the requires. requires = ["network-online.target" "postgresql.service"]; description = "zoey computer"; environment = { # RELEASE_TMP is used to write the state of the # VM configuration when the system is running # it needs to be a writable directory RELEASE_TMP = working_directory; # can be generated in an elixir console with # Base.encode32(:crypto.strong_rand_bytes(32)) PORT = cfg.phx.port; PHX_HOST = cfg.domain; PHX_SERVER = cfg.phx.enableServer; }; serviceConfig = { Type = "exec"; DynamicUser = true; WorkingDirectory = working_directory; # Implied by DynamicUser, but just to emphasize due to RELEASE_TMP PrivateTmp = true; ExecStart = pkgs.writeShellScript "start-zoeycomputer" '' ${cfg.phx.package}/bin/${release_name} eval "ZoeysComputer.Release.migrate" ${cfg.phx.package}/bin/${release_name} start ''; ExecStop = '' ${cfg.phx.package}/bin/${release_name} stop ''; ExecReload = '' ${cfg.phx.package}/bin/${release_name} restart ''; Restart = "on-failure"; RestartSec = 5; StartLimitBurst = 3; StartLimitInterval = 10; }; # disksup requires bash path = [pkgs.bash]; }; }; }; }; perSystem = { # self', config, system, pkgs, lib, ... }: let npmDeps = (pkgs.callPackage ./assets/default.nix {}).shell.nodeDependencies; heroicons = pkgs.fetchFromGitHub { owner = "tailwindlabs"; repo = "heroicons"; rev = "v2.1.1"; hash = "sha256-y/kY8HPJmzB2e7ErgkUdQijU7oUhfS3fI093Rsvyvqs="; sparseCheckout = ["optimized"]; }; in { # Define a consistent package set for development, testing, and # production. _module.args.pkgs = import nixpkgs { inherit system; overlays = [ ( final: _: let erlang = final.beam.interpreters.${erlangVersion}; beamPackages = final.beam.packages.${erlangVersion}; elixir = beamPackages.${elixirVersion}; in { inherit erlang elixir; # Hex is not used in the devShell. # inherit (beamPackages) hex; } ) ]; }; # # Add hydraJob for x86_64-linux # hydraJobs = lib.optionalAttrs (system == "x86_64-linux") { # default = self.packages.${system}.default; # }; # You can build your Elixir application using mixRelease. packages.default = pkgs.beamPackages.mixRelease { pname = "zoeys-computer"; version = "0.1.0"; src = ./.; removeCookie = false; mixNixDeps = with pkgs; import ./deps.nix { inherit pkgs lib beamPackages; }; buildInputs = with pkgs; [nodejs]; postBuild = '' echo ${heroicons} ln -sf ${npmDeps}/lib/node_modules assets/node_modules ln -sf ${heroicons} deps/heroicons ls deps/ npm run deploy --prefix ./assets mix do deps.loadpaths --no-deps-check, phx.digest ''; }; # Add dependencies to develop your application using Mix. devShells.default = pkgs.mkShell { buildInputs = with pkgs; ( [ erlang elixir # You are likely to need Node.js if you develop a Phoenix # application. nodejs mix2nix node2nix # Add the language server of your choice. inputs.lexical.packages.${system}.default # I once added Hex via a Nix development shell, but now I install # and upgrade it using Mix. Hex installed using Nix can cause an # issue if you manage Elixir dependencies using Mix. ] # Add a dependency for a file watcher if you develop a Phoenix # application. ++ lib.optional stdenv.isLinux inotify-tools ++ (lib.optionals stdenv.isDarwin ( with darwin.apple_sdk.frameworks; [ CoreFoundation CoreServices ] )) ); }; # You can define background processes in Nix using # process-compose-flake. process-compose.example = { settings = { processes = { ponysay.command = '' while true; do ${lib.getExe pkgs.ponysay} "Enjoy our ponysay demo!" sleep 2 done ''; }; }; }; }; }; }