{ config, pkgs, lib, evalConfig, ...}: { sops.secrets = { "mattermost/env" = {}; }; containers.mattermost = { autoStart = true; privateNetwork = true; hostAddress = "192.168.100.1"; localAddress = "192.168.100.3"; bindMounts = { "/persist" = { hostPath = "/persist/containers/mattermost"; isReadOnly = false; }; "/secrets".hostPath = "/run/secrets/mattermost"; }; path = evalConfig ({ config, lib, pkgs, ... }: { systemd.services.mattermost.serviceConfig.EnvironmentFile = lib.mkForce "/secrets/env"; services.mattermost = { enable = true; siteUrl = "https://mattermost.infra4future.de"; siteName = "Mattermost for Future"; listenAddress = "0.0.0.0:3000"; mutableConfig = false; statePath = "/persist/mattermost"; extraConfig = { ServiceSettings = { TrustedProxyIPHeader = [ "X-Forwarded-For" "X-Real-Ip" ]; ReadTimeout = 300; WriteTimeout = 600; IdleTimeout = 60; MaximumLoginAttempts = 10; AllowCorsFrom = "*.infra4future.de/*"; WebserverMode = "gzip"; EnableCustomEmoji = true; EnableEmojiPicker = true; EnableGifPicker = false; RestrictCustomEmojiCreation = "all"; RestrictPostDelete = "all"; AllowEditPost = "always"; PostEditTimeout = -1; EnableTutorial = false; ExperimentalChannelSidebarOrganization = "default_on"; ExperimentalChannelOrganization = true; ExperimentalDataPrefetch = true; EnableEmailInvitations = true; DisableLegacyMFA = true; EnableSVGs = true; EnableLaTeX = true; ThreadAutoFollow = true; EnableSecurityFixAlert = false; CollapsedThreads = "default_on"; }; TeamSettings = { EnableTeamCreation = true; EnableUserCreation = true; MaxUsersPerTeam = 250; EnableOpenServer = false; EnableUserDeactivation = true; ExperimentalViewArchivedChannels = true; ExperimentalEnableAutomaticReplies = true; }; LogSettings = { EnableConsole = true; # note: for some reason this doesn't work (mattermost still sets it to DEBUG); # it's also set in secrets.env, where for some reason it does ConsoleLevel = "ERROR"; EnableDiagnostics = false; EnableWebhookDebugging = false; }; NotificationLogSettings = { EnableConsole = true; ConsoleLevel = "INFO"; }; PasswordSettings = { MinimumLength = 10; # turn of all the bullshit requirements Lowercase = false; Number = false; Uppercase = false; Symbol = false; }; FileSettings = { EnableFileAttachments = true; MaxFileSize = 52428800; DriverName = "local"; Directory = "/persist/mattermost/upload-storage"; EnablePublicLink = true; PublicLinkSalt = "3k7p3yxdhz6798b3b9openfr9rn3ymwu"; }; EmailSettings = { EnableSignUpWithEmail = false; EnableSignInWithEmail = false; EnableSignInWithUsername = false; SendEmailNotifications = true; FeedbackName = "mattermost"; FeedbackEmail = "mattermost@infra4future.de"; ReplyToAddress = "mattermost@infra4future.de"; FeedbackOrganization = "∆infra4future.de"; EnableSMTPAuth = true; SMTPUsername = "noreply@infra4future.de"; SMTPServer = "mail.hacc.space"; SMTPPort = "465"; SMTPServerTimeout = 10; ConnectionSecurity = "TLS"; }; RateLimitSettings.Enable = false; PrivacySettings = { ShowEmailAddress = false; ShowFullName = true; }; # to disable the extra landing page advertising the app NativeAppSettings = { AppDownloadLink = ""; AndroidAppDownloadLink = ""; IosAppDownloadLink = ""; }; SupportSettings = { TermsOfServiceLink = "https://infra4future.de/nutzungsbedingungen.html"; PrivacyPolicyLink = "https://infra4future.de/nutzungsbedingungen.html"; AboutLink = "https://infra4future.de"; SupportEmail = "info@infra4future.de"; CustomTermsOfServiceEnabled = false; EnableAskCommunityLink = true; }; AnnouncementSettings.EnableBanner = false; GitLabSettings = { Enable = true; Id = "mattermost"; Scope = ""; AuthEndpoint = "https://login.infra4future.de/oauth2/authorize"; TokenEndpoint = "https://login.infra4future.de/oauth2/token"; UserApiEndpoint = "https://login.infra4future.de/oauth2/userinfo"; }; # for some reason, these don't appear to be working; the startup # process complaines and sets these back to en LocalizationSettings = { DefaultServerLocale = "de"; DefaultClientLocale = "de"; AvailableLocales = "de,en"; }; MessageExportSettings.EnableExport = false; # plugins appear to have trouble with the read-only filesystem; it may # be necessary to manually change their paths etc. PluginSettings = { Enable = true; EnableUploads = true; Plugins = { bigbluebutton = { adminonly = false; base_url = "https://bbb.infra4future.de/bigbluebutton/api"; salt = "zKCsNeaEniC115ynHOsZopgA4iTiJjzgeiPNoCEc"; }; "com.github.matterpoll.matterpoll" = { experimentalui = true; trigger = "poll"; }; }; PluginStates = { bigbluebutton.Enable = true; "com.github.matterpoll.matterpoll".Enable = true; }; }; ComplianceSettings.Enable = false; ClusterSettings.Enable = false; MetricsSettings.Enable = false; GuestAccountsSettings.Enable = false; FeatureFlags.CollapsedThreads = true; }; # turn of the weirder parts of this module (which insist on passwords # in nix files, instead of just using socket-based authentication) # # It will still attempt to use its default password, but postgres will # just let it in regardless of that. localDatabaseCreate = false; }; services.mysql = { enable = true; ensureDatabases = [ "mattermost" ]; ensureUsers = [ { name = "mattermost"; ensurePermissions = { "mattermost.*" = "ALL PRIVILEGES"; }; } ]; package = pkgs.mysql80; dataDir = lib.mkForce "/persist/mysql"; }; services.postgresql = { enable = lib.mkForce true; # mattermost sets this to false. wtf. package = pkgs.postgresql_15; ensureDatabases = [ "mattermost" ]; ensureUsers = [ { name = "mattermost"; ensureDBOwnership = true; } ]; authentication = lib.mkForce '' # Generated file; do not edit! local all all trust host mattermost mattermost ::1/128 trust ''; }; services.postgresqlBackup = { enable = true; databases = [ "mattermost" ]; startAt = "*-*-* 23:45:00"; location = "/persist/backups/postgres"; }; networking.firewall.allowedTCPPorts = [ 3000 ]; }); }; services.nginx.virtualHosts."mattermost.infra4future.de" = { locations."/" = { proxyPass = "http://${config.containers.mattermost.localAddress}:3000"; proxyWebsockets = true; extraConfig = '' # Mattermost CSR Patch proxy_hide_header Content-Security-Policy; proxy_hide_header X-Frame-Options; proxy_redirect off; ''; }; forceSSL = true; enableACME = true; }; }