{ config, pkgs, nestedContainerExtras, ... }: let mastodonContainerFactory = import ../modules/mastodon_container.nix { }; prodConfig = { containerName = "mastodon"; hostAddress = "192.168.42.11"; domain = "snoot.tube"; localAddress = "192.168.42.12"; useElasticsearch = true; mastodonPackage = pkgs.mastodonFork; forwardPorts = [ { containerPort = 443; hostPort = 443; protocol = "tcp"; } { containerPort = 80; hostPort = 80; protocol = "tcp"; } ]; imports = nestedContainerExtras.imports; disabledModules = nestedContainerExtras.disabledModules; acme = { acceptTerms = true; defaults.email = "vivlim@pm.me"; defaults.server = "https://localhost"; # try to use localhost as acme server. this request *will* fail, and we'll fall back to self-signed #defaults.enableDebugLogs = true; }; smtp = { createLocally = false; authenticate = false; fromAddress = "snoot-tube-mastodon@vvn.space"; host = "192.168.1.7"; # ts ip isn't reachable from the container. maybe need a mail relay on the host? use lan ip for now "100.109.126.18"; # sky-reflected-in-mirrors ts ip port = 25; }; mastodonExtraConfig = { ALTERNATE_DOMAINS = "dev.snoot.tube,awake.snoot.tube"; #EMAIL_DOMAIN_ALLOWLIST = "vvn.space"; SMTP_AUTH_METHOD = "none"; SMTP_OPENSSL_VERIFY_MODE = "none"; MAX_TOOT_CHARS = "42069"; AUTHORIZED_FETCH = "true"; USER_ACTIVE_DAYS = "14"; STATSD_ADDR = "outer:9125"; MAX_REACTIONS = "8"; SEARCH_SCOPE = "public"; }; oauth2ProxyUsers = '' viv itsonlythee lifning Skirmisher ''; oauth2ProxyKeys = config.sops.secrets.oauth2_proxy_keys.path; }; prodContainer = (mastodonContainerFactory prodConfig); in { config.networking.hostName = "mastodon-snoottube"; config.networking.firewall.enable = true; config.networking.firewall.allowedTCPPorts = [ 80 443 22 19999 19998 19980 19981 9102 4040 ]; config.networking.firewall.interfaces."ve-+".allowedTCPPorts = [ 3128 ]; # ssh forwarded http proxy config.networking.firewall.interfaces."ve-+".allowedUDPPorts = [ 9125 ]; # statsd config.networking.firewall.checkReversePath = "loose"; config.networking.extraHosts = '' 192.168.42.11 outer 192.168.42.12 mastodon-container ''; config.services.tailscale.enable = true; # enable containers to reach network config.networking.nat.enable = true; config.networking.nat.internalInterfaces = [ "ve-+" ]; config.networking.nat.externalInterface = "ens18"; config.services.prometheus_exporters = { enable = true; nodePort = 19982; systemdPort = 19983; combinedPort = 19980; }; config.services.autossh = { sessions = [{ name = "snoot.tube_ingress"; user = "root"; monitoringPort = 0; extraArguments = "-o ExitOnForwardFailure=yes -o ConnectTimeout=10 -o ServerAliveInterval=15 -o ServerAliveCountMax=4 -N -R 4433:${prodConfig.localAddress}:443 -L 3128:localhost:3128 -L 19981:localhost:19980 -L 19998:localhost:19999 -L 4040:localhost:4040 -g -i /root/.ssh/id_ed25519_to_ingress snoot.tube -p 6922"; }]; }; config.containers = { mastodon = prodContainer.containerConfig; }; config.system.activationScripts.createMastodonContainerPaths = pkgs.lib.stringAfter [ "setupSecrets" "var" ] prodContainer.activationScript; config.sops.secrets.oauth2_proxy_keys = { }; config.environment.systemPackages = [ (let script = pkgs.writeShellScriptBin "tootctl" '' echo "untested! check if this works and remove this echo if it does" sudo nixos-container "run mastodon -- tootctl $@\"" ''; in pkgs.stdenv.mkDerivation { name = "mastodon-container-tootctl-wrapper"; version = "1.0.0"; phases = "installPhase"; installPhase = '' mkdir -p $out/bin cp ${script}/bin/* $out/bin/ ''; }) ]; config.sops.defaultSopsFile = ../secrets/backend.yaml; config.sops.secrets.borg_backup_repo_passphrase = { }; config.sops.secrets.borgbase_ssh_private_key = { }; # it is extremely important for this to have a trailing newline, or connecting will fail config.services.borgbackup.jobs."borgbase" = { paths = [ "/var/lib/mastodon-container" "/var/backup" ]; exclude = [ ]; repo = "h5g87o5w@h5g87o5w.repo.borgbase.com:repo"; encryption = { mode = "repokey-blake2"; passCommand = "cat ${config.sops.secrets.borg_backup_repo_passphrase.path}"; }; environment.BORG_RSH = "ssh -i ${config.sops.secrets.borgbase_ssh_private_key.path}"; compression = "auto,lzma"; startAt = "daily"; }; config.systemd.services.statsd-exporter = { description = "StatsD Exporter"; wantedBy = [ "multi-user.target" ]; after = [ "container@mastodon.service" ]; serviceConfig = let mappingFile = pkgs.writeText "statsd-mapping.yaml" '' ## Prometheus Statsd Exporter mapping for Mastodon 4.0+ ## ## Version 1.0, November 2022 ## ## Documentation: https://ipng.ch/s/articles/2022/11/27/mastodon-3.html mappings: ## Web collector - match: Mastodon\.production\.web\.(.+)\.(.+)\.(.+)\.status\.(.+) match_type: regex name: "mastodon_controller_status" labels: controller: $1 action: $2 format: $3 status: $4 mastodon: "web" - match: Mastodon\.production\.web\.(.+)\.(.+)\.(.+)\.db_time match_type: regex name: "mastodon_controller_db_time" labels: controller: $1 action: $2 format: $3 mastodon: "web" - match: Mastodon\.production\.web\.(.+)\.(.+)\.(.+)\.view_time match_type: regex name: "mastodon_controller_view_time" labels: controller: $1 action: $2 format: $3 mastodon: "web" - match: Mastodon\.production\.web\.(.+)\.(.+)\.(.+)\.total_duration match_type: regex name: "mastodon_controller_duration" labels: controller: $1 action: $2 format: $3 mastodon: "web" ## Database collector - match: Mastodon\.production\.db\.tables\.(.+)\.queries\.(.+)\.duration match_type: regex name: "mastodon_db_operation" labels: table: "$1" operation: "$2" mastodon: "db" ## Cache collector - match: Mastodon\.production\.cache\.(.+)\.duration match_type: regex name: "mastodon_cache_duration" labels: operation: "$1" mastodon: "cache" ## Sidekiq collector - match: Mastodon\.production\.sidekiq\.(.+)\.processing_time match_type: regex name: "mastodon_sidekiq_worker_processing_time" labels: worker: "$1" mastodon: "sidekiq" - match: Mastodon\.production\.sidekiq\.(.+)\.success match_type: regex name: "mastodon_sidekiq_worker_success_total" labels: worker: "$1" mastodon: "sidekiq" - match: Mastodon\.production\.sidekiq\.(.+)\.failure match_type: regex name: "mastodon_sidekiq_worker_failure_total" labels: worker: "$1" mastodon: "sidekiq" - match: Mastodon\.production\.sidekiq\.queues\.(.+)\.enqueued match_type: regex name: "mastodon_sidekiq_queue_enqueued" labels: queue: "$1" mastodon: "sidekiq" - match: Mastodon\.production\.sidekiq\.queues\.(.+)\.latency match_type: regex name: "mastodon_sidekiq_queue_latency" labels: queue: "$1" mastodon: "sidekiq" - match: Mastodon\.production\.sidekiq\.(.+) match_type: regex name: "mastodon_sidekiq_$1" labels: mastodon: "sidekiq" ''; in { ExecStart = "${pkgs.prometheus-statsd-exporter}/bin/statsd_exporter --web.listen-address=':9102' --statsd.listen-udp=':9125' --statsd.mapping-config=${mappingFile}"; }; }; }