{ lib, pkgs, ... }: let inherit (lib) escapeShellArg readFile; inherit (pkgs) writeText; in { applications.pixelfed = { description = '' Photo Sharing. For Everyone. ''; module.options = import ../sharedOptions.nix { inherit pkgs lib; serviceDocName = "Pixelfed"; defaults = { domain = "pixelfed.fediversity.net"; s3AccessKeyFile = writeText "s3AccessKey" "GKb5615457d44214411e673b7b"; s3SecretKeyFile = writeText "s3SecretKey" "5be6799a88ca9b9d813d1a806b64f15efa49482dbe15339"; }; }; implementation = cfg: lib.optionalAttrs cfg.enable { "pixelfed-bucket".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 (cfg) s3AccessKeyFile s3SecretKeyFile; ensureAccess = { pixelfed = { read = true; write = true; owner = true; }; }; }; nixos-configuration = garage: { services.pixelfed = { settings = { FILESYSTEM_CLOUD = "s3"; PF_ENABLE_CLOUD = true; AWS_DEFAULT_REGION = "garage"; AWS_URL = garage.web.urlForBucket "pixelfed"; AWS_BUCKET = "pixelfed"; AWS_ENDPOINT = garage.api.url; AWS_USE_PATH_STYLE_ENDPOINT = false; }; ## 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 = "${garage.web.urlForBucket "pixelfed"}/public/"; }; }; }; }; "codez".nixos-module.module = { config, ... }: { users.groups.nginx = { }; users.users.nginx = { isSystemUser = true; group = "nginx"; extraGroups = [ "pixelfed" ]; }; services.pixelfed = { enable = true; domain = cfg.domain; 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; }; ## 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 = writeText "secrets.env" '' APP_KEY=adKK9EcY8Hcj3PLU7rzG9rJ6KKTOtYfA AWS_ACCESS_KEY_ID=${readFile cfg.s3AccessKeyFile} AWS_SECRET_ACCESS_KEY=${readFile cfg.s3SecretKeyFile} ''; }; ## 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 cfg.initialUser.displayName} \ --username=${escapeShellArg cfg.initialUser.username} \ --email=${escapeShellArg cfg.initialUser.email} \ --password="$(cat ${escapeShellArg cfg.initialUser.passwordFile})" \ --confirm_email=1 ''; # --name=${escapeShellArg cfg.initialUser.displayName} \ # --username=${escapeShellArg cfg.initialUser.username} \ # --email=${escapeShellArg cfg.initialUser.email} \ # --password="$(cat ${escapeShellArg cfg.initialUser.passwordFile})" \ # --name=${escapeShellArg config.initialUser.displayName} \ # --username=${escapeShellArg config.initialUser.username} \ # --email=${escapeShellArg config.initialUser.email} \ # --password="$(cat ${escapeShellArg config.initialUser.passwordFile})" \ }; # Set the service to automatically start wantedBy = [ "multi-user.target" ]; }; }; }; }; }