diff --git a/aether/config.nix b/aether/config.nix new file mode 100644 index 0000000..8cdfed0 --- /dev/null +++ b/aether/config.nix @@ -0,0 +1,68 @@ +{ config, lib, pkgs, self, ... }: +{ + networking.hostName = "toki-aether"; + time.timeZone = "America/New_York"; + + nix.package = pkgs.nixVersions.latest; + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + users.mutableUsers = false; + users.users.root = { + hashedPassword = "$y$j9T$LHeAgn5XytQM5DLfGSDT30$9OD3eIua5vEy4/GFBbT1oe1UnlNxDHt9thqsiqcGXy7"; + openssh.authorizedKeys.keys = (import secrets/secrets.nix).keys; + }; + + environment.systemPackages = with pkgs; [ + openssl + rsync + curl + git + wget + ]; + + # Aether modules + + imports = [ + self.nixosModules.aether + self.nixosModules.deploy-rpi5 + ]; + + aether.domain = "tokinanpa.dev"; + aether.acmeEmail = "kiana.a.sheibani@gmail.com"; + + aether.forgejo.templates = ./forgejo-templates; + services.forgejo.settings = { + DEFAULT.APP_NAME = "Code by toki!"; + service.DISABLE_REGISTRATION = true; + + repository = { + DEFAULT_REPO_UNITS = "repo.code,repo.issues,repo.pulls"; + + ENABLE_PUSH_CREATE_USER = true; + DEFAULT_PUSH_CREATE_PRIVATE = false; + + PREFERRED_LICENSES = "MIT,GPL-3.0-or-later"; + }; + mirror.DEFAULT_INTERVAL = "1h"; + + indexer = { + REPO_INDEXER_ENABLED = true; + REPO_INDEXER_EXCLUDE = "**.pdf, **.png, **.jpg, **.jpeg, **.svg, **.web, **.gpg, **.age"; + }; + + ui = { + DEFAULT_THEME = "forgejo-dark"; + GRAPH_MAX_COMMIT_NUM = 250; + }; + "ui.meta" = { + AUTHOR = "Kiana Sheibani"; + DESCRIPTION = "Code by toki! Powered by Forgejo"; + KEYWORDS = "git,forge,forgejo,toki,tokinanpa"; + }; + "service.explore".DISABLE_USERS_PAGE = true; + + federation.ENABLED = true; + }; + + system.stateVersion = "24.05"; +} diff --git a/modules/forgejo-templates/base/head_navbar.tmpl b/aether/forgejo-templates/base/head_navbar.tmpl similarity index 100% rename from modules/forgejo-templates/base/head_navbar.tmpl rename to aether/forgejo-templates/base/head_navbar.tmpl diff --git a/modules/forgejo-templates/home.tmpl b/aether/forgejo-templates/home.tmpl similarity index 100% rename from modules/forgejo-templates/home.tmpl rename to aether/forgejo-templates/home.tmpl diff --git a/hardware-configuration.nix b/aether/hardware-configuration.nix similarity index 100% rename from hardware-configuration.nix rename to aether/hardware-configuration.nix diff --git a/secrets/secrets.nix b/aether/secrets/secrets.nix similarity index 100% rename from secrets/secrets.nix rename to aether/secrets/secrets.nix diff --git a/config.nix b/config.nix deleted file mode 100644 index dc06a9d..0000000 --- a/config.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ config, lib, pkgs, rpi5-kernel, ... }: -let modules = builtins.map (mod: modules/${mod}.nix); -in { - imports = - modules [ "acme" "fail2ban" "forgejo" ]; - - boot.kernelPackages = rpi5-kernel.legacyPackages.aarch64-linux.linuxPackages_rpi5; - boot.loader.systemd-boot.enable = true; - boot.loader.efi.canTouchEfiVariables = false; - - nix.package = pkgs.nixVersions.latest; - nix.settings.experimental-features = [ "nix-command" "flakes" ]; - - time.timeZone = "America/New_York"; - - networking.hostName = "toki-aether"; - networking.wireless.iwd.enable = true; - networking.wireless.iwd.settings = { - Settings.AutoConnect = true; - Network.EnableIPv6 = false; - General.EnableNetworkConfiguration = true; - }; - - services.openssh.enable = true; - services.openssh.settings = { - PasswordAuthentication = false; - PermitRootLogin = "yes"; - }; - users.mutableUsers = false; - users.users.root = { - hashedPassword = "$y$j9T$LHeAgn5XytQM5DLfGSDT30$9OD3eIua5vEy4/GFBbT1oe1UnlNxDHt9thqsiqcGXy7"; - openssh.authorizedKeys.keys = (import secrets/secrets.nix).keys; - }; - - networking.firewall.allowedTCPPorts = [ 22 80 443 ]; - - environment.systemPackages = with pkgs; [ - openssl - rsync - curl - git - wget - ]; - - system.stateVersion = "24.05"; -} - diff --git a/deploy/rpi5/default.nix b/deploy/rpi5/default.nix new file mode 100644 index 0000000..33f4a14 --- /dev/null +++ b/deploy/rpi5/default.nix @@ -0,0 +1,18 @@ +{ config, lib }: +{ + options.aether.deploy.rpi5 = { + kernelPackages = lib.mkOption { + type = lib.types.raw; + description = "Kernel package to use for Raspberry Pi 5 support"; + }; + }; + + config = + let cfg = config.aether.deploy.rpi5; + in { + nixpkgs.system = "aarch64-linux"; + boot.kernelPackages = cfg.kernelPackages; + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = false; + }; +} diff --git a/flake.nix b/flake.nix index 768cdf2..95c6cb0 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { -description = "Server system conf"; +description = "Aether - web server configuration"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; @@ -12,16 +12,36 @@ inputs = { agenix.inputs.darwin.follows = ""; }; -outputs = inputs@{ self, nixpkgs, agenix, ... }: - { +outputs = inputs@{ self, nixpkgs, agenix, rpi5-kernel, ... }: + let + inherit (nixpkgs) lib; + + moduleNames = + let sub = builtins.readDir ./modules; + in builtins.filter + (d: sub.${d} == "directory") + (builtins.attrNames sub); + + modules = lib.genAttrs moduleNames (name: ./modules/${name}); + in { + nixosModules = + modules + // { + aether.imports = lib.attrValues modules; + deploy-rpi5 = { + imports = [ ./deploy/rpi5 ]; + aether.deploy.rpi5.kernelPackages = + rpi5-kernel.legacyPackages.aarch64-linux.linuxPackages_rpi5; + }; + }; + nixosConfigurations."toki-aether" = nixpkgs.lib.nixosSystem { - system = "aarch64-linux"; modules = [ { _module.args = inputs; } agenix.nixosModules.default - ./hardware-configuration.nix - ./config.nix + ./aether/hardware-configuration.nix + ./aether/config.nix ]; }; nixosConfigurations.default = self.nixosConfigurations."toki-aether"; diff --git a/modules/acme.nix b/modules/acme.nix deleted file mode 100644 index c26c468..0000000 --- a/modules/acme.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ ... }: -{ - security.acme.acceptTerms = true; - security.acme.defaults.email = "kiana.a.sheibani@gmail.com"; -} diff --git a/modules/fail2ban.nix b/modules/fail2ban/default.nix similarity index 100% rename from modules/fail2ban.nix rename to modules/fail2ban/default.nix diff --git a/modules/forgejo.nix b/modules/forgejo.nix deleted file mode 100644 index 8796cdc..0000000 --- a/modules/forgejo.nix +++ /dev/null @@ -1,73 +0,0 @@ -{ config, ... }: -let - cfg = config.services.forgejo; - srv = cfg.settings.server; -in { - services.nginx.enable = true; - services.nginx.virtualHosts.${srv.DOMAIN} = { - forceSSL = true; - enableACME = true; - extraConfig = '' - client_max_body_size 512M; - ''; - locations."/".proxyPass = "http://localhost:${builtins.toString srv.HTTP_PORT}"; - }; - - services.forgejo = { - enable = true; - user = "git"; - group = cfg.user; - database.user = cfg.user; - - settings = { - DEFAULT.APP_NAME = "Code by toki!"; - - server = { - DOMAIN = "git.tokinanpa.dev"; - ROOT_URL = "https://${srv.DOMAIN}/"; - }; - - service.DISABLE_REGISTRATION = true; - - repository = { - DEFAULT_REPO_UNITS = "repo.code,repo.issues,repo.pulls"; - - ENABLE_PUSH_CREATE_USER = true; - DEFAULT_PUSH_CREATE_PRIVATE = false; - - PREFERRED_LICENSES = "MIT,GPL-3.0-or-later"; - }; - mirror.DEFAULT_INTERVAL = "1h"; - - indexer = { - REPO_INDEXER_ENABLED = true; - REPO_INDEXER_EXCLUDE = "**.pdf, **.png, **.jpg, **.jpeg, **.svg, **.web, **.gpg, **.age"; - }; - - ui = { - DEFAULT_THEME = "forgejo-dark"; - GRAPH_MAX_COMMIT_NUM = 250; - }; - "ui.meta" = { - AUTHOR = "Kiana Sheibani"; - DESCRIPTION = "Code by toki! Powered by Forgejo"; - KEYWORDS = "git,forge,forgejo,toki,tokinanpa"; - }; - "service.explore".DISABLE_USERS_PAGE = true; - - federation.ENABLED = true; - }; - }; - - systemd.tmpfiles.rules = [ - "L+ ${cfg.stateDir}/custom/templates - - - - ${./forgejo-templates}" - ]; - - users.users.${cfg.user} = { - home = cfg.stateDir; - useDefaultShell = true; - group = cfg.group; - isSystemUser = true; - }; - users.groups.${cfg.group} = {}; -} diff --git a/modules/forgejo/default.nix b/modules/forgejo/default.nix new file mode 100644 index 0000000..4510bab --- /dev/null +++ b/modules/forgejo/default.nix @@ -0,0 +1,96 @@ +{ config, lib, ... }: +{ + options.aether = { + inherit (import ../options.nix { inherit lib; }) domain acme acmeEmail; + + forgejo = { + subdomain = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = "git"; + description = '' + The subdomain to host the Forgejo instance under. + + If null, then Forgejo is hosted at the domain itself. + ''; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "git"; + description = '' + The user to run Forgejo with. + ''; + }; + + createUser = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to create the Forgejo user automatically. + ''; + }; + + templates = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = '' + A directory of templates for customizing Forgejo's appearance. + ''; + }; + }; + }; + + config = + let + cfg = config.aether.forgejo; + forgejo = config.services.forgejo; + srv = forgejo.settings.server; + in { + # Web server + + services.nginx.enable = true; + services.nginx.virtualHosts.${srv.DOMAIN} = { + forceSSL = config.aether.https; + enableACME = config.aether.https; + extraConfig = '' + client_max_body_size 512M; + ''; + locations."/".proxyPass = "http://localhost:${builtins.toString srv.HTTP_PORT}"; + }; + + security.acme.acceptTerms = config.aether.https; + security.acme.defaults.email = cfg.acmeEmail; + + networking.firewall.allowedTCPPorts = + [ 80 ] ++ lib.optional config.aether.https; + + # Forgejo + + services.forgejo = { + enable = true; + user = cfg.user; + group = forgejo.user; + database.user = forgejo.user; + + settings.server = { + DOMAIN = lib.optionalString !(builtins.isNull cfg.subdomain) "${cfg.subdomain}." + + config.aether.domain; + ROOT_URL = "https://${srv.DOMAIN}/"; + }; + }; + + systemd.tmpfiles.rules = + lib.optional + !(builtins.isNull cfg.templates) + "L+ ${cfg.stateDir}/custom/templates - - - - ${cfg.templates}"; + } + // lib.mkIf cfg.createUser { + users.users.${forgejo.user} = { + home = forgejo.stateDir; + useDefaultShell = true; + group = forgejo.group; + isSystemUser = true; + }; + users.groups.${forgejo.group} = {}; + }; +} diff --git a/modules/options.nix b/modules/options.nix new file mode 100644 index 0000000..944814d --- /dev/null +++ b/modules/options.nix @@ -0,0 +1,19 @@ +{ lib, ... }: +{ + domain = lib.mkOption { + type = lib.types.str; + description = "The domain name the server is hosted on."; + }; + + https = lib.mkOption { + type = lib.types.boolByOr; + default = true; + description = "Whether to force HTTPS connections for websites."; + }; + + acmeEmail = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Email address for ACME."; + }; +} diff --git a/modules/ssh/default.nix b/modules/ssh/default.nix new file mode 100644 index 0000000..2270862 --- /dev/null +++ b/modules/ssh/default.nix @@ -0,0 +1,10 @@ +{ ... }: +{ + services.openssh.enable = true; + services.openssh.settings = { + PasswordAuthentication = false; + PermitRootLogin = "yes"; + }; + + networking.firewall.allowedTCPPorts = [ 22 ]; +} diff --git a/modules/wireless/default.nix b/modules/wireless/default.nix new file mode 100644 index 0000000..e5e951d --- /dev/null +++ b/modules/wireless/default.nix @@ -0,0 +1,9 @@ +{ ... }: +{ + networking.wireless.iwd.enable = true; + networking.wireless.iwd.settings = { + Settings.AutoConnect = true; + Network.EnableIPv6 = false; + General.EnableNetworkConfiguration = true; + }; +}