Compare commits

...

13 commits

Author SHA1 Message Date
f575e8cdea
add qemu import 2025-07-02 15:12:51 +02:00
479e8c21f9
fix imports 2025-07-02 15:12:44 +02:00
dfabfef0b8
upgrade memory to resolve oom 2025-07-02 15:09:53 +02:00
4551c12ff2
[wip] handling env file (still fails) 2025-07-02 15:09:53 +02:00
37f7d97867
use templating fork 2025-07-02 15:09:53 +02:00
919e1d43de
add tests, fix some things 2025-07-02 15:09:53 +02:00
d173df7831
unrelated improvements 2025-07-02 15:09:24 +02:00
3b09f27c81
move from dev to operator 2025-07-02 15:09:24 +02:00
57451bf094
WIP: add attic cache, see #92
flesh out attic

TODO keys nginx-port testing

fix key

fix key
2025-07-02 15:05:20 +02:00
8df70a2ff0 classify recent flake-parts files 2025-07-02 13:25:23 +02:00
5a92c2c0bc docs: fix links to machines (#426)
Reviewed-on: Fediversity/Fediversity#426
Reviewed-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Co-authored-by: Kiara Grouwstra <kiara@procolix.eu>
Co-committed-by: Kiara Grouwstra <kiara@procolix.eu>
2025-07-02 13:16:38 +02:00
1c92009879
Do not force QEMU options onto machines 2025-07-01 23:55:33 +02:00
a791ad41ec Inject sources, secrets and keys via module system - avoid import ../ (#421)
Co-authored-by: Nicolas “Niols” Jeannerod <nicolas.jeannerod@moduscreate.com>
Reviewed-on: Fediversity/Fediversity#421
Reviewed-by: Nicolas Jeannerod <nicolas.jeannerod@moduscreate.com>
Reviewed-by: Valentin Gagarin <valentin.gagarin@tweag.io>
Co-authored-by: Kiara Grouwstra <kiara@procolix.eu>
Co-committed-by: Kiara Grouwstra <kiara@procolix.eu>
2025-07-01 21:08:15 +02:00
29 changed files with 525 additions and 47 deletions

View file

@ -2,6 +2,7 @@
self,
inputs,
lib,
sources,
...
}:
@ -27,7 +28,7 @@ in
../common/nixosTest.nix
./nixosTest.nix
];
_module.args.inputs = inputs;
_module.args = { inherit inputs sources; };
inherit targetMachines pathToRoot pathFromRoot;
};
};
@ -44,7 +45,7 @@ in
inputs.nixops4-nixos.modules.nixops4Resource.nixos
../common/targetResource.nix
];
_module.args.inputs = inputs;
_module.args = { inherit inputs sources; };
inherit nodeName pathToRoot pathFromRoot;
nixos.module =
{ pkgs, ... }:

View file

@ -2,6 +2,7 @@
self,
inputs,
lib,
sources,
...
}:
@ -13,6 +14,7 @@ let
"mastodon"
"peertube"
"pixelfed"
"attic"
];
pathToRoot = /. + (builtins.unsafeDiscardStringContext self);
pathFromRoot = ./.;
@ -30,7 +32,7 @@ in
../common/nixosTest.nix
./nixosTest.nix
];
_module.args.inputs = inputs;
_module.args = { inherit inputs sources; };
inherit
targetMachines
pathToRoot
@ -44,7 +46,7 @@ in
let
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args.inputs = inputs;
_module.args = { inherit inputs sources; };
inherit
nodeName
pathToRoot

View file

@ -48,6 +48,11 @@ in
s3AccessKeyFile = dummyFile;
s3SecretKeyFile = dummyFile;
};
attic = {
enable = true;
s3AccessKeyFile = dummyFile;
s3SecretKeyFile = dummyFile;
};
temp.cores = 1;
temp.initialUser = {
username = "dummy";
@ -72,6 +77,7 @@ in
nodes.mastodon.virtualisation.memorySize = 4 * 1024;
nodes.pixelfed.virtualisation.memorySize = 4 * 1024;
nodes.peertube.virtualisation.memorySize = 5 * 1024;
nodes.attic.virtualisation.memorySize = 2 * 1024;
## FIXME: The test of presence of the services are very simple: we only
## check that there is a systemd service of the expected name on the
@ -86,6 +92,7 @@ in
mastodon.fail("systemctl status mastodon-web.service")
peertube.fail("systemctl status peertube.service")
pixelfed.fail("systemctl status phpfpm-pixelfed.service")
attic.fail("systemctl status atticd.service")
with subtest("Run deployment with no services enabled"):
deployer.succeed("nixops4 apply check-deployment-cli-nothing --show-trace --no-interactive 1>&2")
@ -95,6 +102,7 @@ in
mastodon.fail("systemctl status mastodon-web.service")
peertube.fail("systemctl status peertube.service")
pixelfed.fail("systemctl status phpfpm-pixelfed.service")
attic.fail("systemctl status atticd.service")
with subtest("Run deployment with Mastodon and Pixelfed enabled"):
deployer.succeed("nixops4 apply check-deployment-cli-mastodon-pixelfed --show-trace --no-interactive 1>&2")
@ -104,6 +112,7 @@ in
mastodon.succeed("systemctl status mastodon-web.service")
peertube.fail("systemctl status peertube.service")
pixelfed.succeed("systemctl status phpfpm-pixelfed.service")
attic.fail("systemctl status atticd.service")
with subtest("Run deployment with only Peertube enabled"):
deployer.succeed("nixops4 apply check-deployment-cli-peertube --show-trace --no-interactive 1>&2")
@ -113,5 +122,6 @@ in
mastodon.fail("systemctl status mastodon-web.service")
peertube.succeed("systemctl status peertube.service")
pixelfed.fail("systemctl status phpfpm-pixelfed.service")
attic.fail("systemctl status atticd.service")
'';
}

View file

@ -3,6 +3,7 @@
lib,
pkgs,
config,
sources,
...
}:
@ -14,8 +15,6 @@ let
types
;
sources = import ../../../npins;
in
{
_class = "nixos";
@ -41,7 +40,7 @@ in
## default. These values have been trimmed down to the gigabyte.
## Memory use is expected to be dominated by the NixOS evaluation,
## which happens on the deployer.
memorySize = 4 * 1024;
memorySize = 5 * 1024;
diskSize = 4 * 1024;
cores = 2;
};
@ -55,13 +54,15 @@ in
system.extraDependencies =
[
"${inputs.flake-parts}"
"${inputs.flake-parts.inputs.nixpkgs-lib}"
"${inputs.nixops4}"
"${inputs.nixops4-nixos}"
"${inputs.nixpkgs}"
"${sources.flake-inputs}"
inputs.flake-parts
inputs.flake-parts.inputs.nixpkgs-lib
inputs.nixops4
inputs.nixops4-nixos
inputs.nixpkgs
sources.nixpkgs
sources.flake-inputs
sources.vars
sources.nix-templating
pkgs.stdenv
pkgs.stdenvNoCC
@ -78,7 +79,7 @@ in
config.system.extraDependenciesFromModule
{
nixpkgs.hostPlatform = "x86_64-linux";
_module.args.inputs = inputs;
_module.args = { inherit inputs sources; };
enableAcme = config.enableAcme;
acmeNodeIP = config.acmeNodeIP;
}

View file

@ -3,6 +3,7 @@
lib,
config,
hostPkgs,
sources,
...
}:
@ -61,7 +62,7 @@ in
{
deployer = {
imports = [ ./deployerNode.nix ];
_module.args.inputs = inputs;
_module.args = { inherit inputs sources; };
enableAcme = config.enableAcme;
acmeNodeIP = config.nodes.acme.networking.primaryIPAddress;
};
@ -88,7 +89,7 @@ in
genAttrs config.targetMachines (_: {
imports = [ ./targetNode.nix ];
_module.args.inputs = inputs;
_module.args = { inherit inputs sources; };
enableAcme = config.enableAcme;
acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null;
});

View file

@ -2,6 +2,7 @@
inputs,
lib,
config,
sources,
...
}:
@ -40,7 +41,7 @@ in
(lib.modules.importJSON (config.pathToCwd + "/${config.nodeName}-network.json"))
];
_module.args.inputs = inputs;
_module.args = { inherit inputs sources; };
enableAcme = config.enableAcme;
acmeNodeIP = trim (readFile (config.pathToCwd + "/acme_server_ip"));

View file

@ -2,6 +2,7 @@
self,
inputs,
lib,
sources,
...
}:
@ -16,6 +17,7 @@ let
"mastodon"
"peertube"
"pixelfed"
"attic"
];
pathToRoot = /. + (builtins.unsafeDiscardStringContext self);
pathFromRoot = ./.;
@ -33,7 +35,7 @@ in
../common/nixosTest.nix
./nixosTest.nix
];
_module.args.inputs = inputs;
_module.args = { inherit inputs sources; };
inherit
targetMachines
pathToRoot
@ -47,7 +49,7 @@ in
let
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args.inputs = inputs;
_module.args = { inherit inputs sources; };
inherit
nodeName
pathToRoot

View file

@ -33,6 +33,7 @@ let
enableMastodon,
enablePeertube,
enablePixelfed,
enableAttic,
}:
hostPkgs.writers.writePython3Bin "interact-with-panel"
{
@ -94,6 +95,7 @@ let
checkbox_set(driver.find_element(By.XPATH, "//input[@name = 'mastodon.enable']"), ${toPythonBool enableMastodon})
checkbox_set(driver.find_element(By.XPATH, "//input[@name = 'peertube.enable']"), ${toPythonBool enablePeertube})
checkbox_set(driver.find_element(By.XPATH, "//input[@name = 'pixelfed.enable']"), ${toPythonBool enablePixelfed})
checkbox_set(driver.find_element(By.XPATH, "//input[@name = 'attic.enable']"), ${toPythonBool enableAttic})
print("Start deployment...")
driver.find_element(By.XPATH, "//button[@id = 'deploy-button']").click()
@ -194,6 +196,11 @@ in
s3AccessKeyFile = dummyFile;
s3SecretKeyFile = dummyFile;
};
attic = {
enable = true;
s3AccessKeyFile = dummyFile;
s3SecretKeyFile = dummyFile;
};
temp.cores = 1;
temp.initialUser = {
username = "dummy";
@ -239,6 +246,7 @@ in
nodes.mastodon.virtualisation.memorySize = 4 * 1024;
nodes.pixelfed.virtualisation.memorySize = 4 * 1024;
nodes.peertube.virtualisation.memorySize = 5 * 1024;
nodes.attic.virtualisation.memorySize = 4 * 1024;
## FIXME: The test of presence of the services are very simple: we only
## check that there is a systemd service of the expected name on the
@ -311,6 +319,7 @@ in
mastodon.fail("systemctl status mastodon-web.service")
peertube.fail("systemctl status peertube.service")
pixelfed.fail("systemctl status phpfpm-pixelfed.service")
attic.fail("systemctl status atticd.service")
with subtest("Run deployment with no services enabled"):
client.succeed("${
@ -319,6 +328,7 @@ in
enableMastodon = false;
enablePeertube = false;
enablePixelfed = false;
enableAttic = false;
}
}/bin/interact-with-panel >&2")
@ -327,6 +337,7 @@ in
mastodon.fail("systemctl status mastodon-web.service")
peertube.fail("systemctl status peertube.service")
pixelfed.fail("systemctl status phpfpm-pixelfed.service")
attic.fail("systemctl status atticd.service")
with subtest("Run deployment with Mastodon and Pixelfed enabled"):
client.succeed("${
@ -335,6 +346,7 @@ in
enableMastodon = true;
enablePeertube = false;
enablePixelfed = true;
enableAttic = false;
}
}/bin/interact-with-panel >&2")
@ -343,6 +355,7 @@ in
mastodon.succeed("systemctl status mastodon-web.service")
peertube.fail("systemctl status peertube.service")
pixelfed.succeed("systemctl status phpfpm-pixelfed.service")
attic.fail("systemctl status atticd.service")
with subtest("Run deployment with only Peertube enabled"):
client.succeed("${
@ -351,6 +364,7 @@ in
enableMastodon = false;
enablePeertube = true;
enablePixelfed = false;
enableAttic = false;
}
}/bin/interact-with-panel >&2")
@ -359,5 +373,6 @@ in
mastodon.fail("systemctl status mastodon-web.service")
peertube.succeed("systemctl status peertube.service")
pixelfed.fail("systemctl status phpfpm-pixelfed.service")
attic.fail("systemctl status atticd.service")
'';
}

View file

@ -1,8 +1,9 @@
{
"domain": "fediversity.net",
"mastodon": { "enable": false },
"peertube": { "enable": false },
"pixelfed": { "enable": false },
"mastodon": { "enable": true },
"peertube": { "enable": true },
"pixelfed": { "enable": true },
"attic": { "enable": true },
"initialUser": {
"displayName": "Testy McTestface",
"username": "test",

View file

@ -24,6 +24,7 @@
mastodonConfigurationResource,
peertubeConfigurationResource,
pixelfedConfigurationResource,
atticConfigurationResource,
}:
## From the hosting provider's perspective, the function is meant to be
@ -55,6 +56,7 @@ let
mastodon = nonNull panelConfigNullable.mastodon { enable = false; };
peertube = nonNull panelConfigNullable.peertube { enable = false; };
pixelfed = nonNull panelConfigNullable.pixelfed { enable = false; };
attic = nonNull panelConfigNullable.attic { enable = false; };
};
in
@ -107,6 +109,13 @@ in
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GKb5615457d44214411e673b7b";
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "5be6799a88ca9b9d813d1a806b64f15efa49482dbe15339ddfaf7f19cf434987";
};
atticS3KeyConfig =
{ pkgs, ... }:
{
# REVIEW: how were these generated above? how do i add one?
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GKaaaaaaaaaaaaaaaaaaaaaaaa";
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
};
makeConfigurationResource = resourceModule: config: {
type = providers.local.exec;
@ -140,13 +149,14 @@ in
{
garage-configuration = makeConfigurationResource garageConfigurationResource (
{ pkgs, ... }:
mkIf (cfg.mastodon.enable || cfg.peertube.enable || cfg.pixelfed.enable) {
mkIf (cfg.mastodon.enable || cfg.peertube.enable || cfg.pixelfed.enable || cfg.attic.enable) {
fediversity = {
inherit (cfg) domain;
garage.enable = true;
pixelfed = pixelfedS3KeyConfig { inherit pkgs; };
mastodon = mastodonS3KeyConfig { inherit pkgs; };
peertube = peertubeS3KeyConfig { inherit pkgs; };
attic = atticS3KeyConfig { inherit pkgs; };
};
}
);
@ -213,6 +223,25 @@ in
};
}
);
attic-configuration = makeConfigurationResource atticConfigurationResource (
{ pkgs, ... }:
mkIf cfg.attic.enable {
fediversity = {
inherit (cfg) domain;
temp.initialUser = {
inherit (cfg.initialUser) username email displayName;
# FIXME: disgusting, but nvm, this is going to be replaced by
# proper central authentication at some point
passwordFile = pkgs.writeText "password" cfg.initialUser.password;
};
attic = atticS3KeyConfig { inherit pkgs; } // {
enable = true;
};
};
}
);
};
};
}

View file

@ -71,6 +71,19 @@ in
});
default = null;
};
attic = mkOption {
description = ''
Configuration for the Attic service
'';
type =
with types;
nullOr (submodule {
options = {
enable = lib.mkEnableOption "Attic";
};
});
default = null;
};
initialUser = mkOption {
description = ''
Some services require an initial user to access them.

View file

@ -31,6 +31,9 @@
inherit nixpkgs;
};
self = self';
specialArgs = {
inherit sources;
};
}
(
{ inputs, ... }:
@ -48,6 +51,8 @@
./deployment/flake-part.nix
./infra/flake-part.nix
./keys/flake-part.nix
./secrets/flake-part.nix
];
perSystem =

View file

@ -8,7 +8,6 @@ in
_class = "nixos";
imports = [
./hardware.nix
./networking.nix
./users.nix
];

View file

@ -15,8 +15,6 @@
availableKernelModules = [
"ata_piix"
"uhci_hcd"
"virtio_pci"
"virtio_scsi"
"sd_mod"
"sr_mod"
];

View file

@ -2,6 +2,9 @@
inputs,
lib,
config,
sources,
keys,
secrets,
...
}:
@ -9,12 +12,6 @@ let
inherit (lib) attrValues elem mkDefault;
inherit (lib.attrsets) concatMapAttrs optionalAttrs;
inherit (lib.strings) removeSuffix;
sources = import ../../npins;
inherit (sources) agenix disko;
secretsPrefix = ../../secrets;
secrets = import (secretsPrefix + "/secrets.nix");
keys = import ../../keys;
in
{
@ -35,9 +32,11 @@ in
## options that really need to be injected from the resource. Everything else
## should go into the `./nixos` subdirectory.
nixos.module = {
imports = [
imports = with sources; [
"${agenix}/modules/age.nix"
"${disko}/module.nix"
"${vars}/options.nix"
"${vars}/backends/on-machine.nix"
./options.nix
./nixos
];
@ -46,15 +45,15 @@ in
## configuration.
fediversityVm = config.fediversityVm;
## Read all the secrets, filter the ones that are supposed to be readable
## with this host's public key, and add them correctly to the configuration
## as `age.secrets.<name>.file`.
## Read all the secrets, filter the ones that are supposed to be readable with
## public key, and create a mapping from `<name>.file` to the absolute path of
## the secret's file.
age.secrets = concatMapAttrs (
name: secret:
optionalAttrs (elem config.fediversityVm.hostPublicKey secret.publicKeys) ({
${removeSuffix ".age" name}.file = secretsPrefix + "/${name}";
${removeSuffix ".age" name}.file = secrets.rootPath + "/${name}";
})
) secrets;
) secrets.mapping;
## FIXME: Remove direct root authentication once the NixOps4 NixOS provider
## supports users with password-less sudo.

View file

@ -1,6 +1,9 @@
{
inputs,
lib,
sources,
keys,
secrets,
...
}:
@ -13,7 +16,6 @@ let
filterAttrs
;
inherit (lib.attrsets) genAttrs;
sources = import ../../npins;
## Given a machine's name and whether it is a test VM, make a resource module,
## except for its missing provider. (Depending on the use of that resource, we
@ -22,7 +24,14 @@ let
{ vmName, isTestVm }:
{
# TODO(@fricklerhandwerk): this is terrible but IMO we should just ditch flake-parts and have our own data model for how the project is organised internally
_module.args = { inherit inputs; };
_module.args = {
inherit
inputs
sources
keys
secrets
;
};
imports =
[
@ -31,11 +40,12 @@ let
++ (
if isTestVm then
[
./common/proxmox-qemu-vm.nix
../machines/operator/${vmName}
{
nixos.module.users.users.root.openssh.authorizedKeys.keys = [
# allow our panel vm access to the test machines
(import ../keys).panel
keys.panel
];
}
]
@ -94,6 +104,10 @@ let
vmName = "test04";
isTestVm = true;
};
atticConfigurationResource = makeResourceModule {
vmName = "test12";
isTestVm = true;
};
};
nixops4ResourceNixosMockOptions = {

5
keys/flake-part.nix Normal file
View file

@ -0,0 +1,5 @@
{
_class = "flake";
_module.args.keys = import ./.;
}

View file

@ -19,6 +19,7 @@
nixos.module = {
imports = [
../../../infra/common/proxmox-qemu-vm.nix
./fedipanel.nix
];
};

View file

@ -14,6 +14,7 @@
{ lib, ... }:
{
imports = [
../../../infra/common/proxmox-qemu-vm.nix
./forgejo.nix
];

View file

@ -14,6 +14,7 @@
{ lib, ... }:
{
imports = [
../../../infra/common/proxmox-qemu-vm.nix
./wiki.nix
];

View file

@ -7,9 +7,9 @@ Currently, this repository keeps track of the following VMs:
Machine | Proxmox | Description
--------|---------|-------------
[`fedi200`](./fedi200) | fediversity | Testing machine for Hans
[`fedi201`](./fedi201) | fediversity | FediPanel
[`vm02116`](./vm02116) | procolix | Forgejo
[`vm02187`](./vm02187) | procolix | Wiki
[`fedi200`](./dev/fedi200) | fediversity | Testing machine for Hans
[`fedi201`](./dev/fedi201) | fediversity | FediPanel
[`vm02116`](./dev/vm02116) | procolix | Forgejo
[`vm02187`](./dev/vm02187) | procolix | Wiki
This table excludes all machines with names starting with `test`.

View file

@ -32,7 +32,7 @@ for machine in $(echo "$vmOptions" | jq -r 'keys[]'); do
description=$(echo "$vmOptions" | jq -r ".$machine.description" | head -n 1)
# shellcheck disable=SC2016
printf '[`%s`](./%s) | %s | %s\n' "$machine" "$machine" "$proxmox" "$description"
printf '[`%s`](./dev/%s) | %s | %s\n' "$machine" "$machine" "$proxmox" "$description"
fi
done

View file

@ -18,4 +18,11 @@
gateway = "2a00:51c0:13:1305::1";
};
};
nixos.module = {
imports = [
../../../infra/common/proxmox-qemu-vm.nix
../../../services/fediversity/attic
];
};
}

View file

@ -112,6 +112,19 @@
"url": "https://api.github.com/repos/bigskysoftware/htmx/tarball/v2.0.4",
"hash": "1c4zm3b7ym01ijydiss4amd14mv5fbgp1n71vqjk4alc35jlnqy2"
},
"nix-templating": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "KiaraGrouwstra",
"repo": "nix-templating"
},
"branch": "lib-default-arg",
"submodules": false,
"revision": "e1ff247d508b4efd057a4d6bb13cf45b62c2512f",
"url": "https://github.com/KiaraGrouwstra/nix-templating/archive/e1ff247d508b4efd057a4d6bb13cf45b62c2512f.tar.gz",
"hash": "0g59h4r029jw8vlvn8da62fk9m737s80fg2qk57322iv9lkqlvp0"
},
"nix-unit": {
"type": "Git",
"repository": {
@ -137,6 +150,19 @@
"revision": "f33a4d26226c05d501b9d4d3e5e60a3a59991921",
"url": "https://github.com/nixos/nixpkgs/archive/f33a4d26226c05d501b9d4d3e5e60a3a59991921.tar.gz",
"hash": "1b6dm1sn0bdpcsmxna0zzspjaixa2dald08005fry5jrbjvwafdj"
},
"vars": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "kiaragrouwstra",
"repo": "vars"
},
"branch": "templates",
"submodules": false,
"revision": "6ff942bf2b514edaa1022a92edb6552ac32a09d1",
"url": "https://github.com/kiaragrouwstra/vars/archive/6ff942bf2b514edaa1022a92edb6552ac32a09d1.tar.gz",
"hash": "1h1q3l1l1c1j4ak5lcj2yh85jwqww74ildiak2dkd4h1js9v6cvw"
}
},
"version": 5

4
secrets/default.nix Normal file
View file

@ -0,0 +1,4 @@
{
mapping = import ./secrets.nix;
rootPath = ./.;
}

5
secrets/flake-part.nix Normal file
View file

@ -0,0 +1,5 @@
{
_class = "flake";
_module.args.secrets = import ./.;
}

View file

@ -0,0 +1,322 @@
{
lib,
pkgs,
config,
...
}:
let
inherit (lib) mkIf mkMerge;
sources = import ../../../npins;
in
{
imports = with sources; [
./options.nix
"${vars}/options.nix"
"${vars}/backends/on-machine.nix"
];
config = mkMerge [
(mkIf
(
config.fediversity.garage.enable
&& config.fediversity.attic.s3AccessKeyFile != null
&& config.fediversity.attic.s3SecretKeyFile != null
)
{
fediversity.garage = {
ensureBuckets = {
attic = {
website = true;
# TODO: these are too broad, after getting everything to work narrow it down to the domain we actually want
corsRules = {
enable = true;
allowedHeaders = [ "*" ];
allowedMethods = [ "GET" ];
allowedOrigins = [ "*" ];
};
};
};
ensureKeys = {
attic = {
inherit (config.fediversity.attic) s3AccessKeyFile s3SecretKeyFile;
ensureAccess = {
attic = {
read = true;
write = true;
owner = true;
};
};
};
};
};
}
)
(mkIf config.fediversity.attic.enable {
services.postgresql = {
enable = true;
authentication = lib.mkForce ''
local all all trust
'';
ensureDatabases = [
"atticd"
];
ensureUsers = [
{
name = "atticd";
ensureDBOwnership = true;
}
];
};
# open up access to the mastodon web interface. 80 is necessary if only for ACME
networking.firewall.allowedTCPPorts = [
80
443
8080
];
vars.settings.on-machine.enable = true;
vars.generators."templates" = rec {
dependencies = [ "attic" ];
runtimeInputs = [
pkgs.coreutils
pkgs.gnused
];
script = lib.concatStringsSep "\n" (
lib.mapAttrsToList (template: _: ''
cp "$templates/${template}" "$out/${template}"
echo "filling placeholders in template ${template}..."
${lib.concatStringsSep "\n" (
lib.mapAttrsToList (
parent:
{ placeholder, ... }:
''
sed -i "s/${placeholder}/$(cat "$in/attic/${parent}")/g" "$out/${template}"
echo "- substituted ${parent}"
''
) config.vars.generators."attic".files
)}
'') files
);
files."attic.env" = {
secret = true;
template = pkgs.writeText "attic.env" ''
ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64=${config.vars.generators.attic.files.token.placeholder}
AWS_ACCESS_KEY_ID=$(cat ${config.fediversity.attic.s3AccessKeyFile})
AWS_SECRET_ACCESS_KEY=$(cat ${config.fediversity.attic.s3SecretKeyFile})
'';
};
};
vars.generators.attic = {
runtimeInputs = [ pkgs.openssl ];
files.token.secret = true;
script = ''
genrsa -traditional 4096 | base64 -w0 > "$out"/token
'';
};
services.atticd = {
enable = true;
# one `monolithic` and any number of `api-server` nodes
mode = "monolithic";
environmentFile = config.vars.generators."templates".files."attic.env".path;
# https://github.com/zhaofengli/attic/blob/main/server/src/config-template.toml
settings = {
# Socket address to listen on
# listen = "[::]:8080";
listen = "0.0.0.0:8080";
# listen = "127.0.0.1:8080";
# Allowed `Host` headers
#
# This _must_ be configured for production use. If unconfigured or the
# list is empty, all `Host` headers are allowed.
allowed-hosts = [ ];
# The canonical API endpoint of this server
#
# This is the endpoint exposed to clients in `cache-config` responses.
#
# This _must_ be configured for production use. If not configured, the
# API endpoint is synthesized from the client's `Host` header which may
# be insecure.
#
# The API endpoint _must_ end with a slash (e.g., `https://domain.tld/attic/`
# not `https://domain.tld/attic`).
api-endpoint = "https://${config.fediversity.attic.domain}/";
# Whether to soft-delete caches
#
# If this is enabled, caches are soft-deleted instead of actually
# removed from the database. Note that soft-deleted caches cannot
# have their names reused as long as the original database records
# are there.
#soft-delete-caches = false;
# Whether to require fully uploading a NAR if it exists in the global cache.
#
# If set to false, simply knowing the NAR hash is enough for
# an uploader to gain access to an existing NAR in the global
# cache.
#require-proof-of-possession = true;
# Database connection
database = {
# Connection URL
#
# For production use it's recommended to use PostgreSQL.
# url = "postgresql:///atticd:password@127.0.0.1:5432/atticd";
url = "postgresql:///atticd?host=/run/postgresql";
# Whether to enable sending on periodic heartbeat queries
#
# If enabled, a heartbeat query will be sent every minute
#heartbeat = false;
};
# File storage configuration
storage = {
# Storage type
#
# Can be "local" or "s3".
type = "s3";
# ## Local storage
# The directory to store all files under
# path = "%storage_path%";
# ## S3 Storage (set type to "s3" and uncomment below)
# The AWS region
region = "garage";
# The name of the bucket
bucket = "attic";
# Custom S3 endpoint
#
# Set this if you are using an S3-compatible object storage (e.g., Minio).
endpoint = config.fediversity.garage.api.url;
# Credentials
#
# If unset, the credentials are read from the `AWS_ACCESS_KEY_ID` and
# `AWS_SECRET_ACCESS_KEY` environment variables.
# storage.credentials = {
# access_key_id = "";
# secret_access_key = "";
# };
};
# Data chunking
#
# Warning: If you change any of the values here, it will be
# difficult to reuse existing chunks for newly-uploaded NARs
# since the cutpoints will be different. As a result, the
# deduplication ratio will suffer for a while after the change.
chunking = {
# The minimum NAR size to trigger chunking
#
# If 0, chunking is disabled entirely for newly-uploaded NARs.
# If 1, all NARs are chunked.
nar-size-threshold = 65536; # chunk files that are 64 KiB or larger
# The preferred minimum size of a chunk, in bytes
min-size = 16384; # 16 KiB
# The preferred average size of a chunk, in bytes
avg-size = 65536; # 64 KiB
# The preferred maximum size of a chunk, in bytes
max-size = 262144; # 256 KiB
};
# Compression
compression = {
# Compression type
#
# Can be "none", "brotli", "zstd", or "xz"
type = "zstd";
# Compression level
#level = 8;
};
# Garbage collection
garbage-collection = {
# The frequency to run garbage collection at
#
# By default it's 12 hours. You can use natural language
# to specify the interval, like "1 day".
#
# If zero, automatic garbage collection is disabled, but
# it can still be run manually with `atticd --mode garbage-collector-once`.
interval = "12 hours";
# Default retention period
#
# Zero (default) means time-based garbage-collection is
# disabled by default. You can enable it on a per-cache basis.
#default-retention-period = "6 months";
};
# jwt = {
# WARNING: Changing _anything_ in this section will break any existing
# tokens. If you need to regenerate them, ensure that you use the the
# correct secret and include the `iss` and `aud` claims.
# JWT `iss` claim
#
# Set this to the JWT issuer that you want to validate.
# If this is set, all received JWTs will validate that the `iss` claim
# matches this value.
#token-bound-issuer = "some-issuer";
# JWT `aud` claim
#
# Set this to the JWT audience(s) that you want to validate.
# If this is set, all received JWTs will validate that the `aud` claim
# contains at least one of these values.
#token-bound-audiences = ["some-audience1", "some-audience2"];
# };
# jwt.signing = {
# You must configure JWT signing and verification inside your TOML configuration by setting one of the following options in the [jwt.signing] block:
# * token-rs256-pubkey-base64
# * token-rs256-secret-base64
# * token-hs256-secret-base64
# or by setting one of the following environment variables:
# * ATTIC_SERVER_TOKEN_RS256_PUBKEY_BASE64
# * ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64
# * ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64
# Options will be tried in that same order (configuration options first, then environment options if none of the configuration options were set, starting with the respective RSA pubkey option, the RSA secret option, and finally the HMAC secret option). The first option that is found will be used.
# If an RS256 pubkey (asymmetric RSA PEM PKCS1 public key) is provided, it will only be possible to verify received JWTs, and not sign new JWTs.
# If an RS256 secret (asymmetric RSA PEM PKCS1 private key) is provided, it will be used for both signing new JWTs and verifying received JWTs.
# If an HS256 secret (symmetric HMAC secret) is provided, it will be used for both signing new JWTs and verifying received JWTs.
# JWT RS256 secret key
#
# Set this to the base64-encoded private half of an RSA PEM PKCS1 key.
# TODO
# You can also set it via the `ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64`
# environment variable.
# token-rs256-secret-base64 = "%token_rs256_secret_base64%";
# JWT HS256 secret key
#
# Set this to the base64-encoded HMAC secret key.
# You can also set it via the `ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64`
# environment variable.
#token-hs256-secret-base64 = "";
# };
};
};
})
];
}

View file

@ -0,0 +1,14 @@
{ config, lib, ... }:
{
options.fediversity.attic =
(import ../sharedOptions.nix {
inherit config lib;
serviceName = "attic";
serviceDocName = "Attic Nix Cache server";
})
//
{
};
}

View file

@ -13,6 +13,7 @@ in
./mastodon
./pixelfed
./peertube
./attic
];
options = {