2024-11-04 21:19:57 +01:00
|
|
|
|
{ config, inputs, lib, pkgs, ... }: {
|
|
|
|
|
sops.secrets."services/akkoma/mailerPassword" = {
|
2024-10-31 19:44:04 +01:00
|
|
|
|
sopsFile = ../../../secrets/services/akkoma.yaml;
|
|
|
|
|
};
|
|
|
|
|
sops.secrets."services/akkoma/deepl" = {
|
|
|
|
|
sopsFile = ../../../secrets/services/akkoma.yaml;
|
|
|
|
|
};
|
2024-11-04 21:19:57 +01:00
|
|
|
|
|
2024-10-31 19:44:04 +01:00
|
|
|
|
services.akkoma = {
|
|
|
|
|
enable = true;
|
2024-11-02 15:59:22 +01:00
|
|
|
|
extraPackages = with pkgs; [ exiftool ffmpeg-headless imagemagick ];
|
2024-10-31 19:44:04 +01:00
|
|
|
|
extraStatic."emoji/blobs.gg" = pkgs.akkoma-emoji.blobs_gg;
|
|
|
|
|
|
2024-11-04 21:19:57 +01:00
|
|
|
|
extraStatic."emoji/florp" = pkgs.runCommandNoCC "florp" {
|
|
|
|
|
src = inputs.florp-branding.packages.${config.nixpkgs.hostPlatform.system}.favicon;
|
|
|
|
|
} ''
|
|
|
|
|
mkdir $out
|
|
|
|
|
cp $src $out/florp.png
|
|
|
|
|
'';
|
|
|
|
|
|
|
|
|
|
extraStatic."static/styles.json" = pkgs.writeText "styles.json" (builtins.toJSON (
|
|
|
|
|
builtins.fromJSON (builtins.readFile "${pkgs.akkoma-fe-domi}/static/styles.json") // {
|
|
|
|
|
elly-mod = "/static/themes/elly-mod.json";
|
|
|
|
|
}
|
|
|
|
|
));
|
2024-10-31 19:44:04 +01:00
|
|
|
|
|
|
|
|
|
extraStatic."static/themes/elly-mod.json" = pkgs.writeText "elly-mod.json" (builtins.readFile ./elly-mod.json);
|
|
|
|
|
|
2024-11-09 22:43:58 +01:00
|
|
|
|
extraStatic."static/custom.css" = pkgs.writeText "custom.css" ''
|
|
|
|
|
.tos-content img { max-width: 100%; }
|
|
|
|
|
'';
|
|
|
|
|
|
2024-11-09 20:20:55 +01:00
|
|
|
|
extraStatic."static/terms-of-service.html" = inputs.florp-about.packages.${pkgs.system}.default;
|
|
|
|
|
extraStatic."images/sylvia-ritter-15012323.avif" = inputs.florp-branding.packages.${pkgs.system}.wallpaper;
|
|
|
|
|
extraStatic."images/florp_banner.avif" = inputs.florp-branding.packages.${pkgs.system}.banner;
|
|
|
|
|
extraStatic."favicon.png" = inputs.florp-branding.packages.${pkgs.system}.favicon;
|
2024-10-31 19:44:04 +01:00
|
|
|
|
|
|
|
|
|
frontends = {
|
|
|
|
|
primary = {
|
|
|
|
|
package = pkgs.akkoma-fe-domi;
|
|
|
|
|
name = "akkoma-fe";
|
|
|
|
|
ref = "5f0339ce00";
|
|
|
|
|
};
|
|
|
|
|
admin = {
|
|
|
|
|
package = pkgs.akkoma-frontends.admin-fe;
|
|
|
|
|
name = "admin-fe";
|
|
|
|
|
ref = "stable";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
services.akkoma.config = let
|
2024-11-04 21:19:57 +01:00
|
|
|
|
inherit ((pkgs.formats.elixirConf { }).lib) mkRaw mkAtom mkTuple;
|
|
|
|
|
|
|
|
|
|
mapAttrsToListOfTuple = attr: lib.mapAttrsToList (name: value: mkTuple [ name value ]) attr;
|
|
|
|
|
|
|
|
|
|
mkMapOfPredefinedKeys = set: let
|
|
|
|
|
string = value: "\"${(lib.escape [ "\\" "#" "\"" ]) value}\"";
|
|
|
|
|
|
|
|
|
|
toElixir = value:
|
|
|
|
|
if value == null then "nil" else
|
|
|
|
|
if lib.isString value then string value else
|
|
|
|
|
if builtins.isBool value then lib.boolToString value else
|
|
|
|
|
if lib.isInt value || lib.isFloat value then toString value else
|
|
|
|
|
abort "Not a elixir value ${value}";
|
|
|
|
|
|
|
|
|
|
entries = attrs: lib.concatStringsSep ", " (lib.mapAttrsToList (name: value:
|
|
|
|
|
"${toElixir name}: ${toElixir value}"
|
|
|
|
|
) attrs);
|
|
|
|
|
in mkRaw "%{${entries set}}";
|
|
|
|
|
|
2024-10-31 19:44:04 +01:00
|
|
|
|
in {
|
|
|
|
|
":pleroma" = {
|
|
|
|
|
":instance" = {
|
|
|
|
|
name = "florp.social";
|
|
|
|
|
email = "contact@florp.social";
|
2024-11-04 21:19:57 +01:00
|
|
|
|
notify_email = "noreply@florp.social";
|
2024-10-31 19:44:04 +01:00
|
|
|
|
description = "Likes are now florps. The timeline goes sideways.";
|
|
|
|
|
instance_thumbnail = "/instance/thumbnail.avif";
|
|
|
|
|
limit = 69420;
|
|
|
|
|
description_limit = 69420;
|
|
|
|
|
remote_limit = 131072;
|
|
|
|
|
upload_limit = 160 * 1024 * 1024;
|
|
|
|
|
avatar_upload_limit = 16 * 1024 * 1024;
|
|
|
|
|
background_upload_limit = 32 * 1024 * 1024;
|
|
|
|
|
banner_upload_limit = 32 * 1024 * 1024;
|
|
|
|
|
registrations_open = true;
|
|
|
|
|
registration_reason_length = 2048;
|
|
|
|
|
account_approval_required = true;
|
|
|
|
|
account_activation_required = true;
|
2024-11-04 21:19:57 +01:00
|
|
|
|
federating = true;
|
2024-10-31 19:44:04 +01:00
|
|
|
|
federation_incoming_replies_max_depth = 1024;
|
2024-11-04 21:19:57 +01:00
|
|
|
|
federation_reachability_timeout_days = 14;
|
|
|
|
|
allow_relay = true;
|
2024-10-31 19:44:04 +01:00
|
|
|
|
max_pinned_statuses = 10;
|
2024-11-04 21:19:57 +01:00
|
|
|
|
max_report_comment_size = 2048;
|
2024-10-31 19:44:04 +01:00
|
|
|
|
safe_dm_mentions = true;
|
|
|
|
|
remote_post_retention_days = 365;
|
|
|
|
|
user_bio_length = 8192;
|
|
|
|
|
user_name_length = 64;
|
|
|
|
|
cleanup_attachments = true;
|
|
|
|
|
local_bubble = [
|
|
|
|
|
"solitary.social"
|
|
|
|
|
"donotsta.re"
|
|
|
|
|
"chaos.social"
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
"Pleroma.Captcha".method = mkRaw "Pleroma.Captcha.Kocaptcha";
|
|
|
|
|
|
|
|
|
|
"Pleroma.Web.Endpoint".url.host = "florp.social";
|
|
|
|
|
|
2024-11-04 21:19:57 +01:00
|
|
|
|
"Pleroma.Web.Metadata.Providers.Theme".theme_color = "#070F1C";
|
|
|
|
|
|
2024-10-31 19:44:04 +01:00
|
|
|
|
"Pleroma.Emails.Mailer" = {
|
|
|
|
|
enabled = true;
|
|
|
|
|
adapter = mkRaw "Swoosh.Adapters.SMTP";
|
|
|
|
|
relay = "mail.kyouma.net";
|
2024-11-04 21:19:57 +01:00
|
|
|
|
username = "noreply@florp.social";
|
2024-10-31 19:44:04 +01:00
|
|
|
|
password._secret = config.sops.secrets."services/akkoma/mailerPassword".path;
|
|
|
|
|
port = 465;
|
|
|
|
|
ssl = true;
|
|
|
|
|
auth = mkRaw ":always";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
":database".rum_enabled = true;
|
|
|
|
|
|
|
|
|
|
":media_proxy" = {
|
|
|
|
|
enabled = true;
|
|
|
|
|
base_url = "https://cache.florp.social";
|
|
|
|
|
proxy_opts.redirect_on_failure = true;
|
|
|
|
|
proxy_opts.max_body_length = 64 * 1024 * 1024;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
":media_preview_proxy" = {
|
2024-11-02 15:59:22 +01:00
|
|
|
|
enabled = true;
|
2024-10-31 19:44:04 +01:00
|
|
|
|
thumbnail_max_width = 1920;
|
|
|
|
|
thumbnail_max_height = 1080;
|
|
|
|
|
min_content_length = 128 * 1024;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
"Pleroma.Upload".base_url = "https://media.florp.social";
|
|
|
|
|
|
|
|
|
|
"Pleroma.Upload".filters = map mkRaw [
|
|
|
|
|
"Pleroma.Upload.Filter.Exiftool.ReadDescription"
|
|
|
|
|
"Pleroma.Upload.Filter.Exiftool.StripMetadata"
|
|
|
|
|
"Pleroma.Upload.Filter.Dedupe"
|
|
|
|
|
"Pleroma.Upload.Filter.AnonymizeFilename"
|
|
|
|
|
];
|
|
|
|
|
|
2024-11-04 21:19:57 +01:00
|
|
|
|
":mrf".policies = map mkRaw [
|
|
|
|
|
"Pleroma.Web.ActivityPub.MRF.SimplePolicy"
|
|
|
|
|
"Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy"
|
|
|
|
|
"Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy"
|
|
|
|
|
];
|
2024-10-31 19:44:04 +01:00
|
|
|
|
|
|
|
|
|
":mrf_simple" = {
|
2024-11-04 21:19:57 +01:00
|
|
|
|
reject = mapAttrsToListOfTuple {
|
2024-11-09 21:43:27 +01:00
|
|
|
|
"bae.st" = "transphobia, queerphobia";
|
|
|
|
|
"brighteon.social" = "transphobia, right‐wing extremism";
|
|
|
|
|
"detroitriotcity.com" = "transphobia, queerphobia";
|
2024-11-04 21:19:57 +01:00
|
|
|
|
"freeatlantis.com" = "harassment";
|
|
|
|
|
"freespeechextremist.com" = "N/A";
|
|
|
|
|
"gab.com" = "N/A";
|
|
|
|
|
"gleasonator.com" = "transphobia";
|
|
|
|
|
"kitsunemimi.club" = "transphobia";
|
2024-11-09 21:43:27 +01:00
|
|
|
|
"kiwifarms.*" = "harassment";
|
|
|
|
|
"poa.st" = "queerphobia, racism, right‐wing extremism";
|
2024-11-04 21:19:57 +01:00
|
|
|
|
"seal.cafe" = "transphobia";
|
|
|
|
|
"social.quodverum.com" = "N/A";
|
|
|
|
|
"spinster.xyz" = "transphobia";
|
|
|
|
|
"truthsocial.co.in" = "N/A";
|
|
|
|
|
"varishangout.net" = "transphobia";
|
|
|
|
|
"activitypub-troll.cf" = "N/A";
|
2024-11-09 21:43:27 +01:00
|
|
|
|
"misskey-forkbomb.cf" = "security";
|
2024-11-04 21:19:57 +01:00
|
|
|
|
"repl.co" = "N/A";
|
2024-11-09 21:43:27 +01:00
|
|
|
|
"rape.pet" = "CSAM";
|
|
|
|
|
"childlove.space" = "CSAM";
|
|
|
|
|
"pedo.school" = "CSAM";
|
2024-11-04 21:19:57 +01:00
|
|
|
|
"loli.church" = "transphobia";
|
|
|
|
|
"usasa.ky" = "spam";
|
|
|
|
|
"tickler.cc" = "spam";
|
|
|
|
|
"shitposter.club" = "transphobia";
|
2024-10-31 19:44:04 +01:00
|
|
|
|
};
|
|
|
|
|
|
2024-11-04 21:19:57 +01:00
|
|
|
|
followers_only = mapAttrsToListOfTuple {
|
2024-10-31 19:44:04 +01:00
|
|
|
|
"bitcoinhackers.org" = "annoying";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2024-11-02 15:59:22 +01:00
|
|
|
|
":mrf_object_age".threshold = 180 * 24 * 3600;
|
2024-10-31 19:44:04 +01:00
|
|
|
|
|
|
|
|
|
":frontend_configurations" = {
|
2024-11-04 21:19:57 +01:00
|
|
|
|
pleroma_fe = mkMapOfPredefinedKeys {
|
2024-11-01 15:11:59 +01:00
|
|
|
|
background = "/images/sylvia-ritter-15012323.avif";
|
2024-11-04 21:19:57 +01:00
|
|
|
|
nsfwCensorImage = "/static/blurhash-overlay.png";
|
2024-10-31 19:44:04 +01:00
|
|
|
|
collapseMessageWithSubject = true;
|
|
|
|
|
streaming = true;
|
|
|
|
|
webPushNotifications = true;
|
|
|
|
|
useStreamingApi = true;
|
|
|
|
|
scopeCopy = true;
|
|
|
|
|
showFeaturesPanel = false;
|
|
|
|
|
subjectLineBehavior = "masto";
|
|
|
|
|
alwaysShowSubjectInput = true;
|
|
|
|
|
postContentType = "text/markdown";
|
|
|
|
|
modalOnRepeat = true;
|
|
|
|
|
minimalScopesMode = true;
|
|
|
|
|
redirectRootNoLogin = "/about";
|
2024-11-02 15:59:22 +01:00
|
|
|
|
translationLanguage = "en";
|
2024-10-31 19:44:04 +01:00
|
|
|
|
theme = "elly-mod";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
":restrict_unauthenticated" = {
|
2024-11-04 21:19:57 +01:00
|
|
|
|
timelines = mkMapOfPredefinedKeys {
|
2024-10-31 19:44:04 +01:00
|
|
|
|
local = false;
|
2024-11-04 21:19:57 +01:00
|
|
|
|
federated = false;
|
|
|
|
|
bubble = true;
|
2024-10-31 19:44:04 +01:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
":translator" = {
|
|
|
|
|
enabled = true;
|
|
|
|
|
module = mkRaw "Pleroma.Akkoma.Translators.DeepL";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
":deepl" = {
|
|
|
|
|
tier = mkAtom ":free";
|
|
|
|
|
api_key._secret = config.sops.secrets."services/akkoma/deepl".path;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
":web_push_encryption".":vapid_details" = {
|
|
|
|
|
subject = "mailto:contact@florp.social";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
":joken".":default_signer"._secret = "/var/lib/secrets/akkoma/jwt-signer";
|
|
|
|
|
};
|
2024-11-04 21:19:57 +01:00
|
|
|
|
services.postgresql.enable = true;
|
2024-10-31 19:44:04 +01:00
|
|
|
|
services.postgresql.extraPlugins = [
|
2024-11-04 21:19:57 +01:00
|
|
|
|
pkgs.postgresql16Packages.rum
|
2024-10-31 19:44:04 +01:00
|
|
|
|
];
|
|
|
|
|
services.nginx = {
|
|
|
|
|
clientMaxBodySize = "256m";
|
|
|
|
|
commonHttpConfig = ''
|
2024-11-09 22:05:02 +01:00
|
|
|
|
access_log off;
|
2024-11-08 14:49:21 +01:00
|
|
|
|
|
2024-11-04 21:19:57 +01:00
|
|
|
|
proxy_cache_path /var/cache/nginx/akkoma-media-cache
|
2024-11-09 22:05:02 +01:00
|
|
|
|
levels= keys_zone=akkoma_media_cache:64m max_size=64g
|
2024-10-31 19:44:04 +01:00
|
|
|
|
inactive=1y use_temp_path=off;
|
|
|
|
|
'';
|
|
|
|
|
};
|
2024-11-04 21:19:57 +01:00
|
|
|
|
kyouma.nginx.virtualHosts = let
|
|
|
|
|
proxyCache = ''
|
|
|
|
|
proxy_cache akkoma_media_cache;
|
|
|
|
|
|
|
|
|
|
# Cache objects in slices of 1 MiB
|
|
|
|
|
slice 1m;
|
|
|
|
|
proxy_cache_key $host$uri$is_args$args$slice_range;
|
|
|
|
|
proxy_set_header Range $slice_range;
|
|
|
|
|
|
|
|
|
|
# Decouple proxy and upstream responses
|
|
|
|
|
proxy_buffering on;
|
|
|
|
|
proxy_cache_lock on;
|
|
|
|
|
proxy_ignore_client_abort on;
|
|
|
|
|
|
|
|
|
|
# Default cache times for various responses
|
|
|
|
|
proxy_cache_valid 200 1y;
|
|
|
|
|
proxy_cache_valid 206 301 304 1h;
|
|
|
|
|
|
|
|
|
|
# Allow serving of stale items
|
|
|
|
|
proxy_cache_use_stale error timeout invalid_header updating;
|
|
|
|
|
'';
|
|
|
|
|
in {
|
2024-11-02 15:59:22 +01:00
|
|
|
|
"florp.social" = {
|
2024-11-04 21:19:57 +01:00
|
|
|
|
serverAliases = map (x: "${x}.florp.social") [ "a" "b" "c" ];
|
2024-11-02 15:59:22 +01:00
|
|
|
|
locations."/" = {
|
|
|
|
|
proxyPass = "http://unix:/run/akkoma/socket";
|
|
|
|
|
proxyWebsockets = true;
|
|
|
|
|
};
|
|
|
|
|
locations."^/media(/.*)$".return = "308 https://media.florp.social$1";
|
|
|
|
|
locations."^/proxy(/.*)$".return = "308 https://cache.florp.social$1";
|
|
|
|
|
};
|
2024-10-31 19:44:04 +01:00
|
|
|
|
|
|
|
|
|
"media.florp.social" = {
|
|
|
|
|
useACMEHost = "florp.social";
|
2024-11-02 15:59:22 +01:00
|
|
|
|
locations."/" = {
|
|
|
|
|
proxyPass = "http://unix:/run/akkoma/socket";
|
2024-11-04 21:19:57 +01:00
|
|
|
|
extraConfig = ''
|
|
|
|
|
rewrite ^(?!/media)(.*)$ /media$1;
|
|
|
|
|
'' + proxyCache;
|
2024-11-02 15:59:22 +01:00
|
|
|
|
};
|
2024-10-31 19:44:04 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
"cache.florp.social" = {
|
|
|
|
|
useACMEHost = "florp.social";
|
|
|
|
|
locations."/" = {
|
|
|
|
|
proxyPass = "http://unix:/run/akkoma/socket";
|
|
|
|
|
extraConfig = ''
|
2024-11-02 15:59:22 +01:00
|
|
|
|
rewrite ^(?!/proxy)(.*)$ /proxy$1;
|
2024-11-04 21:19:57 +01:00
|
|
|
|
'' + proxyCache;
|
2024-10-31 19:44:04 +01:00
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
2024-11-04 21:19:57 +01:00
|
|
|
|
security.acme.certs."florp.social".extraDomainNames = [
|
|
|
|
|
"cache.florp.social"
|
|
|
|
|
"media.florp.social"
|
|
|
|
|
] ++ map (x: "${x}.florp.social") [ "a" "b" "c" ];
|
2024-10-31 19:44:04 +01:00
|
|
|
|
}
|