diff options
Diffstat (limited to 'nixos/modules/services/web-apps/mastodon.nix')
-rw-r--r-- | nixos/modules/services/web-apps/mastodon.nix | 138 |
1 files changed, 92 insertions, 46 deletions
diff --git a/nixos/modules/services/web-apps/mastodon.nix b/nixos/modules/services/web-apps/mastodon.nix index 2aab97438b7..8686506b1c2 100644 --- a/nixos/modules/services/web-apps/mastodon.nix +++ b/nixos/modules/services/web-apps/mastodon.nix @@ -17,9 +17,6 @@ let WEB_CONCURRENCY = toString cfg.webProcesses; MAX_THREADS = toString cfg.webThreads; - # mastodon-streaming concurrency. - STREAMING_CLUSTER_NUM = toString cfg.streamingProcesses; - DB_USER = cfg.database.user; REDIS_HOST = cfg.redis.host; @@ -33,13 +30,15 @@ let PAPERCLIP_ROOT_PATH = "/var/lib/mastodon/public-system"; PAPERCLIP_ROOT_URL = "/system"; ES_ENABLED = if (cfg.elasticsearch.host != null) then "true" else "false"; - ES_HOST = cfg.elasticsearch.host; - ES_PORT = toString(cfg.elasticsearch.port); TRUSTED_PROXY_IP = cfg.trustedProxy; } // lib.optionalAttrs (cfg.database.host != "/run/postgresql" && cfg.database.port != null) { DB_PORT = toString cfg.database.port; } // lib.optionalAttrs cfg.smtp.authenticate { SMTP_LOGIN = cfg.smtp.user; } + // lib.optionalAttrs (cfg.elasticsearch.host != null) { ES_HOST = cfg.elasticsearch.host; } + // lib.optionalAttrs (cfg.elasticsearch.host != null) { ES_PORT = toString(cfg.elasticsearch.port); } + // lib.optionalAttrs (cfg.elasticsearch.host != null) { ES_PRESET = cfg.elasticsearch.preset; } + // lib.optionalAttrs (cfg.elasticsearch.user != null) { ES_USER = cfg.elasticsearch.user; } // cfg.extraConfig; systemCallsList = [ "@cpu-emulation" "@debug" "@keyring" "@ipc" "@mount" "@obsolete" "@privileged" "@setuid" ]; @@ -141,8 +140,44 @@ let }) ) cfg.sidekiqProcesses; + streamingUnits = builtins.listToAttrs + (map (i: { + name = "mastodon-streaming-${toString i}"; + value = { + after = [ "network.target" "mastodon-init-dirs.service" ] + ++ lib.optional databaseActuallyCreateLocally "postgresql.service" + ++ lib.optional cfg.automaticMigrations "mastodon-init-db.service"; + requires = [ "mastodon-init-dirs.service" ] + ++ lib.optional databaseActuallyCreateLocally "postgresql.service" + ++ lib.optional cfg.automaticMigrations "mastodon-init-db.service"; + wantedBy = [ "mastodon.target" "mastodon-streaming.target" ]; + description = "Mastodon streaming ${toString i}"; + environment = env // { SOCKET = "/run/mastodon-streaming/streaming-${toString i}.socket"; }; + serviceConfig = { + ExecStart = "${cfg.package}/run-streaming.sh"; + Restart = "always"; + RestartSec = 20; + EnvironmentFile = [ "/var/lib/mastodon/.secrets_env" ] ++ cfg.extraEnvFiles; + WorkingDirectory = cfg.package; + # Runtime directory and mode + RuntimeDirectory = "mastodon-streaming"; + RuntimeDirectoryMode = "0750"; + # System Call Filtering + SystemCallFilter = [ ("~" + lib.concatStringsSep " " (systemCallsList ++ [ "@memlock" "@resources" ])) "pipe" "pipe2" ]; + } // cfgService; + }; + }) + (lib.range 1 cfg.streamingProcesses)); + in { + imports = [ + (lib.mkRemovedOptionModule + [ "services" "mastodon" "streamingPort" ] + "Mastodon currently doesn't support streaming via TCP ports. Please open a PR if you need this." + ) + ]; + options = { services.mastodon = { enable = lib.mkEnableOption (lib.mdDoc "Mastodon, a federated social network server"); @@ -191,18 +226,13 @@ in { default = "mastodon"; }; - streamingPort = lib.mkOption { - description = lib.mdDoc "TCP port used by the mastodon-streaming service."; - type = lib.types.port; - default = 55000; - }; streamingProcesses = lib.mkOption { description = lib.mdDoc '' - Processes used by the mastodon-streaming service. - Defaults to the number of CPU cores minus one. + Number of processes used by the mastodon-streaming service. + Recommended is the amount of your CPU cores minus one. ''; - type = lib.types.nullOr lib.types.int; - default = null; + type = lib.types.ints.positive; + example = 3; }; webPort = lib.mkOption { @@ -485,6 +515,31 @@ in { type = lib.types.port; default = 9200; }; + + preset = lib.mkOption { + description = lib.mdDoc '' + It controls the ElasticSearch indices configuration (number of shards and replica). + ''; + type = lib.types.enum [ "single_node_cluster" "small_cluster" "large_cluster" ]; + default = "single_node_cluster"; + example = "large_cluster"; + }; + + user = lib.mkOption { + description = lib.mdDoc "Used for optionally authenticating with Elasticsearch."; + type = lib.types.nullOr lib.types.str; + default = null; + example = "elasticsearch-mastodon"; + }; + + passwordFile = lib.mkOption { + description = lib.mdDoc '' + Path to file containing password for optionally authenticating with Elasticsearch. + ''; + type = lib.types.nullOr lib.types.path; + default = null; + example = "/var/lib/mastodon/secrets/elasticsearch-password"; + }; }; package = lib.mkOption { @@ -557,7 +612,7 @@ in { config = lib.mkIf cfg.enable (lib.mkMerge [{ assertions = [ { - assertion = databaseActuallyCreateLocally -> (cfg.user == cfg.database.user); + assertion = databaseActuallyCreateLocally -> (cfg.user == cfg.database.user && cfg.database.user == cfg.database.name); message = '' For local automatic database provisioning (services.mastodon.database.createLocally == true) with peer authentication (services.mastodon.database.host == "/run/postgresql") to work services.mastodon.user @@ -603,6 +658,12 @@ in { after = [ "network.target" ]; }; + systemd.targets.mastodon-streaming = { + description = "Target for all Mastodon streaming services"; + wantedBy = [ "multi-user.target" "mastodon.target" ]; + after = [ "network.target" ]; + }; + systemd.services.mastodon-init-dirs = { script = '' umask 077 @@ -631,6 +692,8 @@ in { DB_PASS="$(cat ${cfg.database.passwordFile})" '' + lib.optionalString cfg.smtp.authenticate '' SMTP_PASSWORD="$(cat ${cfg.smtp.passwordFile})" + '' + lib.optionalString (cfg.elasticsearch.passwordFile != null) '' + ES_PASS="$(cat ${cfg.elasticsearch.passwordFile})" '' + '' EOF ''; @@ -688,33 +751,6 @@ in { ++ lib.optional databaseActuallyCreateLocally "postgresql.service"; }; - systemd.services.mastodon-streaming = { - after = [ "network.target" "mastodon-init-dirs.service" ] - ++ lib.optional databaseActuallyCreateLocally "postgresql.service" - ++ lib.optional cfg.automaticMigrations "mastodon-init-db.service"; - requires = [ "mastodon-init-dirs.service" ] - ++ lib.optional databaseActuallyCreateLocally "postgresql.service" - ++ lib.optional cfg.automaticMigrations "mastodon-init-db.service"; - wantedBy = [ "mastodon.target" ]; - description = "Mastodon streaming"; - environment = env // (if cfg.enableUnixSocket - then { SOCKET = "/run/mastodon-streaming/streaming.socket"; } - else { PORT = toString(cfg.streamingPort); } - ); - serviceConfig = { - ExecStart = "${cfg.package}/run-streaming.sh"; - Restart = "always"; - RestartSec = 20; - EnvironmentFile = [ "/var/lib/mastodon/.secrets_env" ] ++ cfg.extraEnvFiles; - WorkingDirectory = cfg.package; - # Runtime directory and mode - RuntimeDirectory = "mastodon-streaming"; - RuntimeDirectoryMode = "0750"; - # System Call Filtering - SystemCallFilter = [ ("~" + lib.concatStringsSep " " (systemCallsList ++ [ "@memlock" "@resources" ])) "pipe" "pipe2" ]; - } // cfgService; - }; - systemd.services.mastodon-web = { after = [ "network.target" "mastodon-init-dirs.service" ] ++ lib.optional databaseActuallyCreateLocally "postgresql.service" @@ -780,10 +816,20 @@ in { }; locations."/api/v1/streaming/" = { - proxyPass = (if cfg.enableUnixSocket then "http://unix:/run/mastodon-streaming/streaming.socket" else "http://127.0.0.1:${toString(cfg.streamingPort)}/"); + proxyPass = "http://mastodon-streaming"; proxyWebsockets = true; }; }; + upstreams.mastodon-streaming = { + extraConfig = '' + least_conn; + ''; + servers = builtins.listToAttrs + (map (i: { + name = "unix:/run/mastodon-streaming/streaming-${toString i}.socket"; + value = { }; + }) (lib.range 1 cfg.streamingProcesses)); + }; }; services.postfix = lib.mkIf (cfg.smtp.createLocally && cfg.smtp.host == "127.0.0.1") { @@ -799,8 +845,8 @@ in { enable = true; ensureUsers = [ { - name = cfg.database.user; - ensurePermissions."DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; + name = cfg.database.name; + ensureDBOwnership = true; } ]; ensureDatabases = [ cfg.database.name ]; @@ -819,7 +865,7 @@ in { users.groups.${cfg.group}.members = lib.optional cfg.configureNginx config.services.nginx.user; } - { systemd.services = sidekiqUnits; } + { systemd.services = lib.mkMerge [ sidekiqUnits streamingUnits ]; } ]); meta.maintainers = with lib.maintainers; [ happy-river erictapen ]; |