From db8cb61d4a13fa861440379f4788a6524d880467 Mon Sep 17 00:00:00 2001 From: Alexander Foremny Date: Thu, 15 Feb 2024 06:27:47 +0100 Subject: init code.nomath.org --- .envrc | 1 + apps/cgit/appspec.nix | 28 ++++++ apps/cgit/integration.nix | 21 ++++ apps/cgit/module.nix | 16 +++ apps/static-website/appspec.nix | 14 +++ apps/static-website/module.nix | 4 + configs/default.nix | 10 ++ nix/sources.json | 20 ++++ nix/sources.nix | 198 ++++++++++++++++++++++++++++++++++++++ pkgs/nomath-website/default.nix | 1 + secrets | 2 +- shell.nix | 12 +++ systems/system1/configuration.nix | 11 +++ terraform.nix | 25 +++++ 14 files changed, 362 insertions(+), 1 deletion(-) create mode 100644 .envrc create mode 100644 apps/cgit/appspec.nix create mode 100644 apps/cgit/integration.nix create mode 100644 apps/cgit/module.nix create mode 100644 apps/static-website/appspec.nix create mode 100644 apps/static-website/module.nix create mode 100644 nix/sources.json create mode 100644 nix/sources.nix create mode 100644 pkgs/nomath-website/default.nix create mode 100644 shell.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/apps/cgit/appspec.nix b/apps/cgit/appspec.nix new file mode 100644 index 0000000..8ea967c --- /dev/null +++ b/apps/cgit/appspec.nix @@ -0,0 +1,28 @@ +{ fysilib, lib, ... }: { + description = "cgit"; + endOfLife = null; + options = { + domain = lib.mkOption { + description = "Domain of cgit instance"; + type = fysilib.types.fqdn; + }; + repositories = lib.mkOption { + type = fysilib.types.attrsOf (fysilib.types.submodule { + options = { + name = lib.mkOption { + default = null; + type = fysilib.types.pathComponent; + }; + description = lib.mkOption { + default = null; + type = fysilib.types.nullOr fysilib.types.str; + }; + }; + }); + }; + settings = lib.mkOption { + type = lib.types.attrsOf (lib.types.oneOf [ lib.types.bool lib.types.int lib.types.str ]); + default = { }; + }; + }; +} diff --git a/apps/cgit/integration.nix b/apps/cgit/integration.nix new file mode 100644 index 0000000..4107311 --- /dev/null +++ b/apps/cgit/integration.nix @@ -0,0 +1,21 @@ +{ appConfig, lib, pkgs, ... }: +{ + # TODO references ../../public + users.users.git.home = "/var/lib/git"; + users.users.git.createHome = true; + users.users.git.shell = "${pkgs.git}/bin/git-shell"; + users.users.git.openssh.authorizedKeys.keyFiles = [ ../../public/aforemny.id_rsa.pub ]; + + bindMounts."/var/lib/git".isReadOnly = false; + + systemd.services."ensure-git-repositories".wantedBy = [ "multi-user.target" ]; + systemd.services."ensure-git-repositories".script = "${pkgs.writers.writeDashBin "ensure-git-repositories" '' + set -efu + ${lib.concatLines (lib.mapAttrsToList (name: _: '' + test -e /var/lib/git/${lib.escapeShellArg name} || \ + ${pkgs.git}/bin/git init --bare /var/lib/git/${lib.escapeShellArg name} + '') appConfig.repositories)} + ''}/bin/ensure-git-repositories"; + systemd.services."ensure-git-repositories".serviceConfig.User = "git"; + systemd.services."ensure-git-repositories".serviceConfig.Group = "nogroup"; +} diff --git a/apps/cgit/module.nix b/apps/cgit/module.nix new file mode 100644 index 0000000..106764b --- /dev/null +++ b/apps/cgit/module.nix @@ -0,0 +1,16 @@ +{ appConfig, config, lib, pkgs, ... }: +{ + services.cgit.default.enable = true; + services.cgit.default.nginx.virtualHost = appConfig.domain; + services.cgit.default.repos = lib.mapAttrs + (name: attrs: { + desc = attrs.description; + path = "/var/lib/git/${name}"; + }) + appConfig.repositories; + services.cgit.default.settings = appConfig.settings; + + users.users.git.isSystemUser = true; + users.users.git.home = "/var/lib/git"; + users.users.git.group = "nogroup"; +} diff --git a/apps/static-website/appspec.nix b/apps/static-website/appspec.nix new file mode 100644 index 0000000..c7e919e --- /dev/null +++ b/apps/static-website/appspec.nix @@ -0,0 +1,14 @@ +{ fysilib, lib, ... }: { + description = "static website"; + endOfLife = null; + options = { + domain = lib.mkOption { + description = "Domain of the website"; + type = fysilib.types.fqdn; + }; + root = lib.mkOption { + description = "Domain of the website"; + type = fysilib.types.str; + }; + }; +} diff --git a/apps/static-website/module.nix b/apps/static-website/module.nix new file mode 100644 index 0000000..659dfad --- /dev/null +++ b/apps/static-website/module.nix @@ -0,0 +1,4 @@ +{ appConfig, ... }: { + services.nginx.enable = true; + services.nginx.virtualHosts.${appConfig.domain}.locations."/".root = appConfig.root; +} diff --git a/configs/default.nix b/configs/default.nix index 7d65206..4710326 100644 --- a/configs/default.nix +++ b/configs/default.nix @@ -7,4 +7,14 @@ users.users.root.openssh.authorizedKeys.keyFiles = [ ../public/aforemny.id_rsa.pub ]; + + security.acme.acceptTerms = true; + # TODO why do defaults not suffice here? + #security.acme.certs.defaults.email = "aforemny@posteo.de"; + #security.acme.certs.defaults.webroot = "/var/lib/acme/acme-challenge"; + security.acme.certs."code.nomath.org".email = "aforemny@posteo.de"; + security.acme.certs."code.nomath.org".webroot = "/var/lib/acme/acme-challenge"; + security.acme.certs."nomath.org".email = "aforemny@posteo.de"; + security.acme.certs."nomath.org".webroot = "/var/lib/acme/acme-challenge"; + networking.firewall.allowedTCPPorts = [ 80 ]; } diff --git a/nix/sources.json b/nix/sources.json new file mode 100644 index 0000000..71b4a98 --- /dev/null +++ b/nix/sources.json @@ -0,0 +1,20 @@ +{ + "nixpkgs": { + "branch": "nixos-unstable", + "description": "Nix Packages collection", + "homepage": null, + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6c43a3495a11e261e5f41e5d7eda2d71dae1b2fe", + "sha256": "16f329z831bq7l3wn1dfvbkh95l2gcggdwn6rk3cisdmv2aa3189", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/6c43a3495a11e261e5f41e5d7eda2d71dae1b2fe.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "website": { + "branch": "main", + "repo": "git@code.nomath.org:~/website", + "rev": "21b71667e42a2af1ebb22631ce956f2b95971454", + "type": "git" + } +} diff --git a/nix/sources.nix b/nix/sources.nix new file mode 100644 index 0000000..fe3dadf --- /dev/null +++ b/nix/sources.nix @@ -0,0 +1,198 @@ +# This file has been generated by Niv. + +let + + # + # The fetchers. fetch_ fetches specs of type . + # + + fetch_file = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchurl { inherit (spec) url sha256; name = name'; } + else + pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; + + fetch_tarball = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchTarball { name = name'; inherit (spec) url sha256; } + else + pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; + + fetch_git = name: spec: + let + ref = + spec.ref or ( + if spec ? branch then "refs/heads/${spec.branch}" else + if spec ? tag then "refs/tags/${spec.tag}" else + abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!" + ); + submodules = spec.submodules or false; + submoduleArg = + let + nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0; + emptyArgWithWarning = + if submodules + then + builtins.trace + ( + "The niv input \"${name}\" uses submodules " + + "but your nix's (${builtins.nixVersion}) builtins.fetchGit " + + "does not support them" + ) + { } + else { }; + in + if nixSupportsSubmodules + then { inherit submodules; } + else emptyArgWithWarning; + in + builtins.fetchGit + ({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg); + + fetch_local = spec: spec.path; + + fetch_builtin-tarball = name: throw + ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=tarball -a builtin=true''; + + fetch_builtin-url = name: throw + ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=file -a builtin=true''; + + # + # Various helpers + # + + # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 + sanitizeName = name: + ( + concatMapStrings (s: if builtins.isList s then "-" else s) + ( + builtins.split "[^[:alnum:]+._?=-]+" + ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) + ) + ); + + # The set of packages used when specs are fetched using non-builtins. + mkPkgs = sources: system: + let + sourcesNixpkgs = + import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; + hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; + hasThisAsNixpkgsPath = == ./.; + in + if builtins.hasAttr "nixpkgs" sources + then sourcesNixpkgs + else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then + import { } + else + abort + '' + Please specify either (through -I or NIX_PATH=nixpkgs=...) or + add a package called "nixpkgs" to your sources.json. + ''; + + # The actual fetching function. + fetch = pkgs: name: spec: + + if ! builtins.hasAttr "type" spec then + abort "ERROR: niv spec ${name} does not have a 'type' attribute" + else if spec.type == "file" then fetch_file pkgs name spec + else if spec.type == "tarball" then fetch_tarball pkgs name spec + else if spec.type == "git" then fetch_git name spec + else if spec.type == "local" then fetch_local spec + else if spec.type == "builtin-tarball" then fetch_builtin-tarball name + else if spec.type == "builtin-url" then fetch_builtin-url name + else + abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; + + # If the environment variable NIV_OVERRIDE_${name} is set, then use + # the path directly as opposed to the fetched source. + replace = name: drv: + let + saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name; + ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; + in + if ersatz == "" then drv else + # this turns the string into an actual Nix path (for both absolute and + # relative paths) + if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; + + # Ports of functions for older nix versions + + # a Nix version of mapAttrs if the built-in doesn't exist + mapAttrs = builtins.mapAttrs or ( + f: set: with builtins; + listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) + ); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 + range = first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 + stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 + stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); + concatMapStrings = f: list: concatStrings (map f list); + concatStrings = builtins.concatStringsSep ""; + + # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 + optionalAttrs = cond: as: if cond then as else { }; + + # fetchTarball version that is compatible between all the versions of Nix + builtins_fetchTarball = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchTarball; + in + if lessThan nixVersion "1.12" then + fetchTarball ({ inherit url; } // (optionalAttrs (name != null) { inherit name; })) + else + fetchTarball attrs; + + # fetchurl version that is compatible between all the versions of Nix + builtins_fetchurl = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchurl; + in + if lessThan nixVersion "1.12" then + fetchurl ({ inherit url; } // (optionalAttrs (name != null) { inherit name; })) + else + fetchurl attrs; + + # Create the final "sources" from the config + mkSources = config: + mapAttrs + ( + name: spec: + if builtins.hasAttr "outPath" spec + then + abort + "The values in sources.json should not have an 'outPath' attribute" + else + spec // { outPath = replace name (fetch config.pkgs name spec); } + ) + config.sources; + + # The "config" used by the fetchers + mkConfig = + { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null + , sources ? if sourcesFile == null then { } else builtins.fromJSON (builtins.readFile sourcesFile) + , system ? builtins.currentSystem + , pkgs ? mkPkgs sources system + }: rec { + # The sources, i.e. the attribute set of spec name to spec + inherit sources; + + # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers + inherit pkgs; + }; + +in +mkSources (mkConfig { }) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/pkgs/nomath-website/default.nix b/pkgs/nomath-website/default.nix new file mode 100644 index 0000000..197ed4e --- /dev/null +++ b/pkgs/nomath-website/default.nix @@ -0,0 +1 @@ +import "${(import ../../nix/sources.nix).website}/nomath-website.nix" diff --git a/secrets b/secrets index 9086d50..b81ddf0 160000 --- a/secrets +++ b/secrets @@ -1 +1 @@ -Subproject commit 9086d50a88d76a24308406eb2f014dec2e13872a +Subproject commit b81ddf08cbf0b824b01185d14a632f5a503fdae0 diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..1b660a3 --- /dev/null +++ b/shell.nix @@ -0,0 +1,12 @@ +{ pkgs ? import { } }: +let inherit (pkgs) lib; in +pkgs.mkShell { + buildInputs = [ + pkgs.git + pkgs.niv + ]; + shellHook = '' + PASSWORD_STORE_DIR=${lib.escapeShellArg (toString ./.)}/secrets; export PASSWORD_STORE_DIR + HETZNER_DNS_API_TOKEN=$(pass show hetznerdns-api-token); export HETZNER_DNS_API_TOKEN + ''; +} diff --git a/systems/system1/configuration.nix b/systems/system1/configuration.nix index d39af2e..9910511 100644 --- a/systems/system1/configuration.nix +++ b/systems/system1/configuration.nix @@ -1,3 +1,4 @@ +{ pkgs, ... }: { imports = [ @@ -6,4 +7,14 @@ ]; networking.hostName = "system1"; + + fysiweb-apps.public.static-website."nomath-org".domain = "nomath.org"; + fysiweb-apps.public.static-website."nomath-org".root = "${pkgs.nomath-website}"; + + fysiweb-apps.public.cgit."code-nomath-org".domain = "code.nomath.org"; + fysiweb-apps.public.cgit."code-nomath-org".settings.max-stats = "year"; + fysiweb-apps.public.cgit."code-nomath-org".settings.root-desc = ""; + fysiweb-apps.public.cgit."code-nomath-org".settings.root-title = "code.nomath.org"; + + fysiweb-apps.public.cgit."code-nomath-org".repositories."website".description = "nomath.org website"; } diff --git a/terraform.nix b/terraform.nix index 70d4104..e3f1b0d 100644 --- a/terraform.nix +++ b/terraform.nix @@ -2,6 +2,13 @@ let inherit (import ) fysilib lib; in fysilib.terraform.eval (import { + terraform = { + #required_providers = { + # hetznerdns = { + # source = "timohirt/hetznerdns"; + # }; + #}; + }; resource = { hcloud_server.system1 = { name = "system1"; @@ -12,5 +19,23 @@ fysilib.terraform.eval (import { "fysiweb-cli" ]; }; + hcloud_floating_ip.primary_ipv4 = { + type = "ipv4"; + server_id = "\${hcloud_server.system1.id}"; + }; + hcloud_floating_ip.primary_ipv6 = { + type = "ipv6"; + server_id = "\${hcloud_server.system1.id}"; + }; + #hetznerdns_zone."nomath_org" = { + # name = "nomath.org"; + # ttl = 60; + #}; + #hetznerdns_record."all_nomath_org" = { + # zone_id = "\${hetznerdns_zone.nomath_org.id}"; + # name = "@"; + # value = "\${hcloud_server.system1.ipv4_address}"; + # type = "A"; + #}; }; }) -- cgit v1.2.3