{ config, lib, pkgs, ... }: let inherit (lib) mkIf mkMerge readFile escapeShellArg ; in { imports = [ ./options.nix ]; config = mkMerge [ (mkIf ( config.fediversity.garage.enable && config.fediversity.pixelfed.s3AccessKeyFile != null && config.fediversity.pixelfed.s3SecretKeyFile != null ) { fediversity.garage = { ensureBuckets = { pixelfed = { website = true; # TODO: these are too broad, after getting everything works narrow it down to the domain we actually want corsRules = { enable = true; allowedHeaders = [ "*" ]; allowedMethods = [ "GET" ]; allowedOrigins = [ "*" ]; }; }; }; ensureKeys = { pixelfed = { inherit (config.fediversity.pixelfed) s3AccessKeyFile s3SecretKeyFile; ensureAccess = { pixelfed = { read = true; write = true; owner = true; }; }; }; }; }; } ) (mkIf config.fediversity.pixelfed.enable { ## NOTE: Pixelfed as packaged in nixpkgs has a permission issue that prevents Nginx ## from being able to serving the images. We fix it here, but this should be ## upstreamed. See https://github.com/NixOS/nixpkgs/issues/235147 services.pixelfed.package = pkgs.pixelfed.overrideAttrs (old: { patches = (old.patches or [ ]) ++ [ ./group-permissions.patch ]; }); users.users.nginx.extraGroups = [ "pixelfed" ]; services.pixelfed = { enable = true; domain = config.fediversity.pixelfed.domain; ## FIXME: secrets management; we should have a service that writes the ## `.env` file based on all the secrets that we need to put there. secretFile = pkgs.writeText "secrets.env" '' APP_KEY=adKK9EcY8Hcj3PLU7rzG9rJ6KKTOtYfA AWS_ACCESS_KEY_ID=${readFile config.fediversity.pixelfed.s3AccessKeyFile} AWS_SECRET_ACCESS_KEY=${readFile config.fediversity.pixelfed.s3SecretKeyFile} ''; ## Taeer feels like this way of configuring Nginx is odd; there should ## instead be a `services.pixefed.nginx.enable` option and the actual Nginx ## configuration should be in `services.nginx`. See eg. `pretix`. ## ## TODO: If that indeed makes sense, upstream. nginx = { forceSSL = true; enableACME = true; # locations."/public/".proxyPass = "${config.fediversity.garage.web.urlForBucket "pixelfed"}/public/"; }; }; services.pixelfed.settings = { ## NOTE: This depends on the targets, eg. universities might want control ## over who has an account. We probably want a universal ## `fediversity.openRegistration` option. OPEN_REGISTRATION = true; FILESYSTEM_CLOUD = "s3"; PF_ENABLE_CLOUD = true; AWS_DEFAULT_REGION = "garage"; AWS_URL = config.fediversity.garage.web.urlForBucket "pixelfed"; AWS_BUCKET = "pixelfed"; AWS_ENDPOINT = config.fediversity.garage.api.url; AWS_USE_PATH_STYLE_ENDPOINT = false; }; ## Only ever run `pixelfed-data-setup` after `ensure-garage` has done its job. ## Otherwise, everything crashed dramatically. systemd.services.pixelfed-data-setup = { after = [ "ensure-garage.service" ]; }; networking.firewall.allowedTCPPorts = [ 80 443 ]; systemd.services.inject-initial-pixelfed-user = { ## Make this service start after pixelfed has started successfully after = [ "phpfpm-pixelfed.service" ]; requires = [ "phpfpm-pixelfed.service" ]; serviceConfig = { Type = "simple"; Restart = "on-failure"; RestartSec = "10s"; ExecStart = pkgs.writeShellScript "inject-initial-pixelfed-user.sh" '' #!/bin/sh set -euC ## NOTE: The packaging for Pixelfed provides a 'pixelfed-manage' ## command that is added to the environment but isn't easily ## grabable otherwise, so we go the ugly route and extract it from ## the Horizon service that runs 'pixelfed-manage horizon'. pixelfed-manage () { local f=${escapeShellArg config.systemd.services.pixelfed-horizon.serviceConfig.ExecStart} "''${f% horizon}" "$@" } ## NOTE: The 'user:table' command prints headers: ## ## +----+----------+------+------------+ ## | ID | Username | Name | Registered | ## +----+----------+------+------------+ ## ## so we check whether that is all we got to know if there are any ## users yet. users_table=$(pixelfed-manage user:table) if [ "$(echo "$users_table" | wc -l)" -ne 3 ]; then printf 'There are already users; nothing to do:\n\n%s' "$users_table" exit 0 fi ## No user so far; let's go! pixelfed-manage user:create \ --name=${escapeShellArg config.fediversity.temp.initialUser.displayName} \ --username=${escapeShellArg config.fediversity.temp.initialUser.username} \ --email=${escapeShellArg config.fediversity.temp.initialUser.email} \ --password="$(cat ${escapeShellArg config.fediversity.temp.initialUser.passwordFile})" \ --confirm_email=1 ''; }; # Set the service to automatically start wantedBy = [ "multi-user.target" ]; }; }) ]; }