From 6b447c40aa79a733b8c2d8381ce217004f431b6d Mon Sep 17 00:00:00 2001 From: yuri Date: Tue, 10 Oct 2023 04:14:29 +0200 Subject: [PATCH] Migrate Mastodon to NixOS --- config/hosts/mastodon/configuration.nix | 43 +++++++ config/hosts/mastodon/default.nix | 9 ++ config/hosts/mastodon/mastodon.nix | 51 +++++++++ config/hosts/mastodon/nginx.nix | 48 ++++++++ config/hosts/mastodon/opensearch.nix | 5 + config/hosts/mastodon/secrets.nix | 37 ++++++ config/hosts/web-public-2/nginx.nix | 2 +- .../virtualHosts/acme-challenge.nix | 105 ++++++++++-------- .../web-public-2/virtualHosts/default.nix | 1 - .../virtualHosts/social.nekover.se.nix | 29 ----- hosts.nix | 4 + 11 files changed, 256 insertions(+), 78 deletions(-) create mode 100644 config/hosts/mastodon/configuration.nix create mode 100644 config/hosts/mastodon/default.nix create mode 100644 config/hosts/mastodon/mastodon.nix create mode 100644 config/hosts/mastodon/nginx.nix create mode 100644 config/hosts/mastodon/opensearch.nix create mode 100644 config/hosts/mastodon/secrets.nix delete mode 100644 config/hosts/web-public-2/virtualHosts/social.nekover.se.nix diff --git a/config/hosts/mastodon/configuration.nix b/config/hosts/mastodon/configuration.nix new file mode 100644 index 0000000..aad67b7 --- /dev/null +++ b/config/hosts/mastodon/configuration.nix @@ -0,0 +1,43 @@ +{ ... }: +{ + boot.loader.grub = { + enable = true; + device = "/dev/vda"; + }; + + networking = { + hostName = "mastodon"; + firewall = { + enable = true; + allowedTCPPorts = [ 80 8443 ]; + }; + }; + + fileSystems = { + "/mnt/data" = { + device = "/dev/disk/by-label/data"; + fsType = "ext4"; + autoResize = true; + }; + "/var/lib/mastodon/public-system" = { + depends = [ "/mnt/data" ]; + device = "/mnt/data/mastodon"; + fsType = "none"; + options = [ "bind" "X-mount.owner=mastodon" "X-mount.group=mastodon" ]; + }; + "/var/lib/postgresql" = { + depends = [ "/mnt/data" ]; + device = "/mnt/data/postgresql"; + fsType = "none"; + options = [ "bind" "X-mount.owner=postgres" "X-mount.group=postgres" ]; + }; + "/var/lib/private/opensearch/data" = { + depends = [ "/mnt/data" ]; + device = "/mnt/data/opensearch"; + fsType = "none"; + options = [ "bind" "X-mount.owner=opensearch" "X-mount.group=opensearch" ]; + }; + }; + + system.stateVersion = "23.05"; +} diff --git a/config/hosts/mastodon/default.nix b/config/hosts/mastodon/default.nix new file mode 100644 index 0000000..5651eb8 --- /dev/null +++ b/config/hosts/mastodon/default.nix @@ -0,0 +1,9 @@ +{ ... }: +{ + imports = [ + ./configuration.nix + ./mastodon.nix + ./opensearch.nix + ./nginx.nix + ]; +} diff --git a/config/hosts/mastodon/mastodon.nix b/config/hosts/mastodon/mastodon.nix new file mode 100644 index 0000000..620e6c2 --- /dev/null +++ b/config/hosts/mastodon/mastodon.nix @@ -0,0 +1,51 @@ +{ pkgs, ... }: +let + mastodonNekoversePatches = pkgs.fetchgit { + url = "https://github.com/yuri-qq/nekoverse-mastodon-patches.git"; + hash = "sha256-+HoE3rXiJUpAUYiXj4BaOL68cCG1tN8p+TI7vRxrA1Y="; + }; + mastodonNekoverseOverlay = final: prev: { + mastodon = (prev.mastodon.override rec { + version = "4.1.9"; + srcOverride = final.applyPatches { + src = final.fetchgit { + url = "https://github.com/mastodon/mastodon.git"; + rev = "v${version}"; + sha256 = "sha256-xpE/mg2AeioW6NThUjLS+SBxGavG4w1xtp3BOMADfYo="; + }; + patches = [ + "${mastodonNekoversePatches}/patches/001_increase_image_dimensions_limit.patch" + "${mastodonNekoversePatches}/patches/002_disable_image_reprocessing.patch" + "${mastodonNekoversePatches}/patches/003_make_toot_cute.patch" + "${mastodonNekoversePatches}/patches/005_improve_custom_emoji_support.patch" + "${mastodonNekoversePatches}/patches/006_increase_display_name_character_limit.patch" + "${mastodonNekoversePatches}/patches/007_increase_toot_character_limit.patch" + ]; + }; + }); + }; + pkgs-overlay = pkgs.extend mastodonNekoverseOverlay; +in +{ + services.mastodon = { + enable = true; + package = pkgs-overlay.mastodon; + localDomain = "social.nekover.se"; + secretKeyBaseFile = "/secrets/mastodon-secret-key-base.secret"; + otpSecretFile = "/secrets/mastodon-otp-secret.secret"; + vapidPrivateKeyFile = "/secrets/mastodon-vapid-private-key.secret"; + smtp = { + authenticate = true; + host = "mail-1.grzb.de"; + port = 465; + user = "social@nekover.se"; + passwordFile = "/secrets/mastodon-email-smtp-pass.secret"; + fromAddress = "Nekoverse "; + }; + extraConfig = { + SMTP_TLS = "true"; + ES_PRESET = "single_node_cluster"; + }; + elasticsearch.host = "127.0.0.1"; + }; +} diff --git a/config/hosts/mastodon/nginx.nix b/config/hosts/mastodon/nginx.nix new file mode 100644 index 0000000..f9d541f --- /dev/null +++ b/config/hosts/mastodon/nginx.nix @@ -0,0 +1,48 @@ +{ config, ... }: +{ + services.nginx = { + enable = true; + group = "mastodon"; + virtualHosts."social.nekover.se" = { + forceSSL = true; + enableACME = true; + listen = [ + { + addr = "0.0.0.0"; + port = 80; + } + { + addr = "0.0.0.0"; + port = 8443; + ssl = true; + extraParameters = [ "proxy_protocol" ]; + } + ]; + + root = "${config.services.mastodon.package}/public/"; + + locations = { + "/" = { + tryFiles = "$uri @proxy"; + }; + + "/system/".alias = "/var/lib/mastodon/public-system/"; + + "^~ /api/v1/streaming" = { + proxyPass = "http://unix:/run/mastodon-streaming/streaming.socket"; + proxyWebsockets = true; + }; + + "@proxy" = { + proxyPass = "http://unix:/run/mastodon-web/web.socket"; + proxyWebsockets = true; + }; + }; + + extraConfig = '' + set_real_ip_from 10.202.41.100; + real_ip_header proxy_protocol; + ''; + }; + }; +} diff --git a/config/hosts/mastodon/opensearch.nix b/config/hosts/mastodon/opensearch.nix new file mode 100644 index 0000000..b787d77 --- /dev/null +++ b/config/hosts/mastodon/opensearch.nix @@ -0,0 +1,5 @@ +{ ... }: { + services.opensearch = { + enable = true; + }; +} diff --git a/config/hosts/mastodon/secrets.nix b/config/hosts/mastodon/secrets.nix new file mode 100644 index 0000000..b6a827c --- /dev/null +++ b/config/hosts/mastodon/secrets.nix @@ -0,0 +1,37 @@ +{ ... }: +{ + deployment.keys = { + "mastodon-secret-key-base.secret" = { + keyCommand = [ "env" "GNUPGHOME=/home/yuri/.passinfra_gnupg" "PASSWORD_STORE_DIR=/home/yuri/pass/infra" "pass" "mastodon/secret-key-base" ]; + destDir = "/secrets"; + user = "mastodon"; + group = "mastodon"; + permissions = "0640"; + uploadAt = "pre-activation"; + }; + "mastodon-otp-secret.secret" = { + keyCommand = [ "env" "GNUPGHOME=/home/yuri/.passinfra_gnupg" "PASSWORD_STORE_DIR=/home/yuri/pass/infra" "pass" "mastodon/otp-secret" ]; + destDir = "/secrets"; + user = "mastodon"; + group = "mastodon"; + permissions = "0640"; + uploadAt = "pre-activation"; + }; + "mastodon-vapid-private-key.secret" = { + keyCommand = [ "env" "GNUPGHOME=/home/yuri/.passinfra_gnupg" "PASSWORD_STORE_DIR=/home/yuri/pass/infra" "pass" "mastodon/vapid-private-key" ]; + destDir = "/secrets"; + user = "mastodon"; + group = "mastodon"; + permissions = "0640"; + uploadAt = "pre-activation"; + }; + "mastodon-email-smtp-pass.secret" = { + keyCommand = [ "env" "GNUPGHOME=/home/yuri/.passinfra_gnupg" "PASSWORD_STORE_DIR=/home/yuri/pass/infra" "pass" "mastodon/email-smtp-pass" ]; + destDir = "/secrets"; + user = "mastodon"; + group = "mastodon"; + permissions = "0640"; + uploadAt = "pre-activation"; + }; + }; +} diff --git a/config/hosts/web-public-2/nginx.nix b/config/hosts/web-public-2/nginx.nix index 82c4b8f..ea0732c 100644 --- a/config/hosts/web-public-2/nginx.nix +++ b/config/hosts/web-public-2/nginx.nix @@ -25,7 +25,7 @@ nekover.se 127.0.0.1:8443; nextcloud.grzb.de 127.0.0.1:8443; nix-cache.nekover.se 10.202.41.121:8443; - social.nekover.se 127.0.0.1:8443; + social.nekover.se 10.202.41.104:8443; } server { diff --git a/config/hosts/web-public-2/virtualHosts/acme-challenge.nix b/config/hosts/web-public-2/virtualHosts/acme-challenge.nix index f5adeea..7e0190e 100644 --- a/config/hosts/web-public-2/virtualHosts/acme-challenge.nix +++ b/config/hosts/web-public-2/virtualHosts/acme-challenge.nix @@ -1,57 +1,68 @@ { ... }: { - services.nginx.virtualHosts."jellyfin.grzb.de" = { - listen = [{ - addr = "0.0.0.0"; - port = 80; - }]; - locations."^~ /.well-known/acme-challenge/" = { - proxyPass = "http://jellyfin.vs.grzb.de:80"; + services.nginx.virtualHosts = { + "jellyfin.grzb.de" = { + listen = [{ + addr = "0.0.0.0"; + port = 80; + }]; + locations."^~ /.well-known/acme-challenge/" = { + proxyPass = "http://jellyfin.vs.grzb.de:80"; + }; }; - }; - services.nginx.virtualHosts."mail-1.grzb.de" = { - listen = [{ - addr = "0.0.0.0"; - port = 80; - }]; - locations."^~ /.well-known/acme-challenge/" = { - proxyPass = "http://mail-1.vs.grzb.de:80"; + "mail-1.grzb.de" = { + listen = [{ + addr = "0.0.0.0"; + port = 80; + }]; + locations."^~ /.well-known/acme-challenge/" = { + proxyPass = "http://mail-1.vs.grzb.de:80"; + }; }; - }; - services.nginx.virtualHosts."matrix.nekover.se" = { - listen = [{ - addr = "0.0.0.0"; - port = 80; - }]; - locations."^~ /.well-known/acme-challenge/" = { - proxyPass = "http://matrix.vs.grzb.de:80"; + "mastodon.nekover.se" = { + listen = [{ + addr = "0.0.0.0"; + port = 80; + }]; + locations."^~ /.well-known/acme-challenge/" = { + proxyPass = "http://mastodon.vs.grzb.de:80"; + }; }; - }; - services.nginx.virtualHosts."netbox.grzb.de" = { - listen = [{ - addr = "0.0.0.0"; - port = 80; - }]; - locations."^~ /.well-known/acme-challenge/" = { - proxyPass = "http://netbox.vs.grzb.de:80"; + "matrix.nekover.se" = { + listen = [{ + addr = "0.0.0.0"; + port = 80; + }]; + locations."^~ /.well-known/acme-challenge/" = { + proxyPass = "http://matrix.vs.grzb.de:80"; + }; }; - }; - services.nginx.virtualHosts."grafana.grzb.de" = { - listen = [{ - addr = "0.0.0.0"; - port = 80; - }]; - locations."^~ /.well-known/acme-challenge/" = { - proxyPass = "http://metrics.vs.grzb.de:80"; + "netbox.grzb.de" = { + listen = [{ + addr = "0.0.0.0"; + port = 80; + }]; + locations."^~ /.well-known/acme-challenge/" = { + proxyPass = "http://netbox.vs.grzb.de:80"; + }; }; - }; - services.nginx.virtualHosts."turn.nekover.se" = { - listen = [{ - addr = "0.0.0.0"; - port = 80; - }]; - locations."^~ /.well-known/acme-challenge/" = { - proxyPass = "http://coturn.vs.grzb.de:80"; + "grafana.grzb.de" = { + listen = [{ + addr = "0.0.0.0"; + port = 80; + }]; + locations."^~ /.well-known/acme-challenge/" = { + proxyPass = "http://metrics.vs.grzb.de:80"; + }; + }; + "turn.nekover.se" = { + listen = [{ + addr = "0.0.0.0"; + port = 80; + }]; + locations."^~ /.well-known/acme-challenge/" = { + proxyPass = "http://coturn.vs.grzb.de:80"; + }; }; }; } diff --git a/config/hosts/web-public-2/virtualHosts/default.nix b/config/hosts/web-public-2/virtualHosts/default.nix index 6a5c3bb..53294f7 100644 --- a/config/hosts/web-public-2/virtualHosts/default.nix +++ b/config/hosts/web-public-2/virtualHosts/default.nix @@ -8,7 +8,6 @@ ./git.grzb.de.nix ./mewtube.nekover.se.nix ./nekover.se.nix - ./social.nekover.se.nix ]; services.nginx.virtualHosts."_" = { diff --git a/config/hosts/web-public-2/virtualHosts/social.nekover.se.nix b/config/hosts/web-public-2/virtualHosts/social.nekover.se.nix deleted file mode 100644 index 174e360..0000000 --- a/config/hosts/web-public-2/virtualHosts/social.nekover.se.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ ... }: -{ - services.nginx.virtualHosts."social.nekover.se" = { - forceSSL = true; - enableACME = true; - listen = [ - { - addr = "localhost"; - port = 1234; - } # workaround for enableACME check - { - addr = "localhost"; - port = 8443; - ssl = true; - proxyProtocol = true; - } - ]; - locations."/" = { - proxyPass = "http://mastodon.vs.grzb.de:80"; - proxyWebsockets = true; - }; - extraConfig = '' - client_max_body_size 80m; - - set_real_ip_from 127.0.0.1; - real_ip_header proxy_protocol; - ''; - }; -} diff --git a/hosts.nix b/hosts.nix index ab78a2d..fc2716d 100644 --- a/hosts.nix +++ b/hosts.nix @@ -57,6 +57,10 @@ in site = "wg"; environment = "proxmox"; }; + mastodon = { + site = "vs"; + environment = "proxmox"; + }; matrix = { site = "vs"; environment = "proxmox";