]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Add mastodon service
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Sun, 13 Jan 2019 12:57:55 +0000 (13:57 +0100)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Sun, 13 Jan 2019 13:11:20 +0000 (14:11 +0100)
default.nix
virtual/modules/databases/default.nix
virtual/modules/websites/default.nix
virtual/modules/websites/tools/mastodon/default.nix [new file with mode: 0644]
virtual/modules/websites/tools/mastodon/mastodon.json [moved from fetched/mastodon.json with 100% similarity]
virtual/modules/websites/tools/mastodon/mastodon.nix [new file with mode: 0644]

index c2776023bf5627eb12a4cab6bdd2afd1dff180a8..9e79550e8f941e64d1edbfbe20fb871deb23678d 100644 (file)
@@ -252,25 +252,6 @@ let
     buildInputs = old.buildInputs ++ [ tokyocabinet bzip2 ];
   });
 
-  mastodon = stdenv.mkDerivation (fetchedGithub ./fetched/mastodon.json // rec {
-    buildPhase = ''
-      export GIT_SSL_CAINFO=${cacert}/etc/ssl/certs/ca-bundle.crt
-      export SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
-
-      bundle install --deployment --without development test
-      yarn install --pure-lockfile
-    '';
-    installPhase = ''
-      cp -a . $out
-    '';
-    propagatedBuildInputs = [
-      zlib icu libchardet git bundler yarn
-      protobuf protobufc libidn libpqxx nodejs
-      imagemagick ffmpeg libxml2 libxslt pkgconfig
-      autoconf bison libyaml readline ncurses libffi gdbm
-      jemalloc which postgresql python3 cacert
-    ];
-  });
 # https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh
 # https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks
 in
@@ -311,7 +292,6 @@ in
     inherit mtr;
     inherit nixops;
     stgit = gitAndTools.stgit;
-    #inherit mastodon;
     # todo: lx* ?, unrar, unzip, zeromq?
     #inherit nextcloud-client;
     #inherit nixos;
index de4ace64f228b22439b178cb8a7669c58f82956c..db85f3c4a6acb49f573658170df199fcf07d7841 100644 (file)
@@ -163,6 +163,7 @@ in {
 
     # FIXME: backup
     # Nextcloud: 14
+    # Mastodon: 13
     services.redis = rec {
       enable = config.services.myDatabases.redis.enable;
       bind = "127.0.0.1";
index 6b313811edc46f88004e645ee0fd0bac25f2b7f9..d88f57149f138c18e6ba47e89ccb14c711336b2e 100644 (file)
@@ -96,6 +96,7 @@ in
     ./tools/dav
     ./tools/cloud
     ./tools/git
+    ./tools/mastodon
     # built using:
     # sed -e "s/services\.httpd/services\.httpdProd/g" .nix-defexpr/channels/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
     # And removed users / groups
@@ -167,6 +168,7 @@ in
     services.myWebsites.tools.dav.enable = true;
     services.myWebsites.tools.cloud.enable = true;
     services.myWebsites.tools.git.enable = true;
+    services.myWebsites.tools.mastodon.enable = true;
 
     services.myWebsites.Chloe.production.enable = cfg.production.enable;
     services.myWebsites.Ludivine.production.enable = cfg.production.enable;
diff --git a/virtual/modules/websites/tools/mastodon/default.nix b/virtual/modules/websites/tools/mastodon/default.nix
new file mode 100644 (file)
index 0000000..1549ca9
--- /dev/null
@@ -0,0 +1,207 @@
+{ lib, pkgs, config, mylibs, ... }:
+let
+  mastodon = pkgs.callPackage ./mastodon.nix {
+    inherit (mylibs) fetchedGithub checkEnv;
+  };
+
+  cfg = config.services.myWebsites.tools.mastodon;
+in {
+  options.services.myWebsites.tools.mastodon = {
+    enable = lib.mkEnableOption "enable mastodon's website";
+  };
+
+  config = lib.mkIf cfg.enable {
+    # FIXME: Can we use dynamic users from systemd?
+    # nixos/modules/misc/ids.nix
+    ids.uids.mastodon = 399;
+    ids.gids.mastodon = 399;
+
+    users.users.mastodon = {
+      name = "mastodon";
+      uid = config.ids.uids.mastodon;
+      group = "mastodon";
+      description = "Mastodon user";
+      home = "${mastodon.railsRoot}";
+      useDefaultShell = true;
+    };
+
+    users.groups.mastodon.gid = config.ids.gids.mastodon;
+
+    systemd.services.mastodon-streaming = {
+      description = "Mastodon Streaming";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "mastodon-web.service" ];
+
+      environment.NODE_ENV = "production";
+      environment.SOCKET = mastodon.nodeSocket;
+
+      path = [ pkgs.nodejs pkgs.bashInteractive ];
+
+      script = ''
+        exec npm run start
+      '';
+
+      postStart = ''
+        while [ ! -S $SOCKET ]; do
+          sleep 0.5
+        done
+        chmod a+w $SOCKET
+      '';
+
+      postStop = ''
+        rm $SOCKET
+      '';
+
+      serviceConfig = {
+        User = "mastodon";
+        EnvironmentFile = mastodon.config;
+        PrivateTmp = true;
+        Restart = "always";
+        TimeoutSec = 15;
+        Type = "simple";
+        WorkingDirectory = mastodon.railsRoot;
+      };
+
+      unitConfig.RequiresMountsFor = mastodon.varDir;
+    };
+
+    systemd.services.mastodon-web = {
+      description = "Mastodon Web app";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      environment.RAILS_ENV = "production";
+      environment.SOCKET = mastodon.railsSocket;
+
+      path = [ pkgs.bundler ];
+
+      preStart = ''
+        bundle exec rails db:migrate
+      '';
+
+      script = ''
+        exec bundle exec puma -C config/puma.rb
+      '';
+
+      serviceConfig = {
+        User = "mastodon";
+        EnvironmentFile = mastodon.config;
+        PrivateTmp = true;
+        Restart = "always";
+        TimeoutSec = 15;
+        Type = "simple";
+        WorkingDirectory = mastodon.railsRoot;
+      };
+
+      unitConfig.RequiresMountsFor = mastodon.varDir;
+    };
+
+    systemd.services.mastodon-sidekiq = {
+      description = "Mastodon Sidekiq";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "mastodon-web.service" ];
+
+      environment.RAILS_ENV="production";
+      environment.DB_POOL="5";
+
+      path = [ pkgs.bundler ];
+
+      script = ''
+        exec bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
+      '';
+
+      serviceConfig = {
+        User = "mastodon";
+        EnvironmentFile = mastodon.config;
+        PrivateTmp = true;
+        Restart = "always";
+        TimeoutSec = 15;
+        Type = "simple";
+        WorkingDirectory = mastodon.railsRoot;
+      };
+
+      unitConfig.RequiresMountsFor = mastodon.varDir;
+    };
+
+    # FIXME: initial sync
+    system.activationScripts.mastodon = {
+      deps = [ "users" ];
+      text = ''
+      install -m 0755 -o mastodon -g mastodon -d ${mastodon.socketsDir}
+      install -m 0755 -o mastodon -g mastodon -d ${mastodon.varDir}
+      '';
+    };
+
+    services.myWebsites.tools.modules = [
+      "headers" "proxy" "proxy_wstunnel" "proxy_http" "proxy_balancer"
+      # FIXME: probably only one balancer method is needed:
+      "lbmethod_byrequests" "lbmethod_bytraffic" "lbmethod_bybusyness" "lbmethod_heartbeat"
+    ];
+    security.acme.certs."eldiron".extraDomains."mastodon.immae.eu" = null;
+    services.myWebsites.tools.vhostConfs.mastodon = {
+      certName    = "eldiron";
+      hosts       = ["mastodon.immae.eu" ];
+      root        = "${mastodon.railsRoot}/public/";
+      extraConfig = [ ''
+        Header always set Referrer-Policy "strict-origin-when-cross-origin"
+        Header always set Strict-Transport-Security "max-age=31536000"
+
+        <LocationMatch "^/(assets|avatars|emoji|headers|packs|sounds|system)>
+          Header always set Cache-Control "public, max-age=31536000, immutable"
+          Require all granted
+        </LocationMatch>
+
+        ProxyPreserveHost On
+        RequestHeader set X-Forwarded-Proto "https"
+
+        RewriteEngine On
+
+        ProxyPass /500.html !
+        ProxyPass /sw.js !
+        ProxyPass /embed.js !
+        ProxyPass /robots.txt !
+        ProxyPass /manifest.json !
+        ProxyPass /browserconfig.xml !
+        ProxyPass /mask-icon.svg !
+        ProxyPassMatch ^(/.*\.(png|ico|gif)$) !
+        ProxyPassMatch ^/(assets|avatars|emoji|headers|packs|sounds|system|.well-known/acme-challenge) !
+
+        ProxyPassMatch /api/v1/streaming/(.+)$ balancer://node_servers_http/api/v1/streaming/$1
+        ProxyPass /api/v1/streaming/ balancer://node_servers/
+        ProxyPassReverse /api/v1/streaming/ balancer://node_servers/
+        ProxyPass / balancer://puma_servers/
+        ProxyPassReverse / balancer://puma_servers/
+
+        <Proxy balancer://puma_servers>
+            BalancerMember unix://${mastodon.railsSocket}|http://
+        </Proxy>
+
+        <Proxy balancer://node_servers>
+            BalancerMember unix://${mastodon.nodeSocket}|ws://localhost
+        </Proxy>
+
+        <Proxy balancer://node_servers_http>
+            BalancerMember unix://${mastodon.nodeSocket}|http://localhost
+        </Proxy>
+
+        Alias /system ${mastodon.varDir}
+
+        <Directory ${mastodon.varDir}>
+          Require all granted
+          Options -MultiViews
+        </Directory>
+
+        <Directory ${mastodon.railsRoot}/public/>
+          Require all granted
+          Options -MultiViews +FollowSymlinks
+        </Directory>
+
+        ErrorDocument 500 /500.html
+        ErrorDocument 501 /500.html
+        ErrorDocument 502 /500.html
+        ErrorDocument 503 /500.html
+        ErrorDocument 504 /500.html
+      '' ];
+    };
+  };
+}
diff --git a/virtual/modules/websites/tools/mastodon/mastodon.nix b/virtual/modules/websites/tools/mastodon/mastodon.nix
new file mode 100644 (file)
index 0000000..e948852
--- /dev/null
@@ -0,0 +1,100 @@
+{ checkEnv, fetchedGithub, stdenv, writeText, pkgs, cacert }:
+let
+  varDir = "/var/lib/mastodon_immae";
+  socketsDir = "/run/mastodon";
+  mastodon = stdenv.mkDerivation (fetchedGithub ./mastodon.json // rec {
+    buildPhase = ''
+      export GIT_SSL_CAINFO=${cacert}/etc/ssl/certs/ca-bundle.crt
+      export SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
+
+      bundle install --deployment --without development test
+      yarn install --pure-lockfile
+    '';
+    installPhase = ''
+      cp -a . $out
+    '';
+    propagatedBuildInputs = with pkgs; [
+      zlib icu libchardet git bundler yarn
+      protobuf protobufc libidn libpqxx nodejs
+      imagemagick ffmpeg libxml2 libxslt pkgconfig
+      autoconf bison libyaml readline ncurses libffi gdbm
+      jemalloc which postgresql python3 cacert
+    ];
+  });
+  config =
+      assert checkEnv "NIXOPS_MASTODON_DB_PASS";
+      assert checkEnv "NIXOPS_MASTODON_PAPERCLIP_SECRET";
+      assert checkEnv "NIXOPS_MASTODON_SECRET_KEY_BASE";
+      assert checkEnv "NIXOPS_MASTODON_OTP_SECRET";
+      assert checkEnv "NIXOPS_MASTODON_VAPID_PRIVATE_KEY";
+      assert checkEnv "NIXOPS_MASTODON_VAPID_PUBLIC_KEY";
+      assert checkEnv "NIXOPS_MASTODON_OTP_SECRET";
+      assert checkEnv "NIXOPS_MASTODON_LDAP_PASSWORD";
+      writeText "mastodon_environment" ''
+    REDIS_HOST=localhost
+    REDIS_PORT=6379
+    REDIS_DB=13
+    DB_HOST=/run/postgresql
+    DB_USER=mastodon
+    DB_NAME=mastodon
+    DB_PASS=${builtins.getEnv "NIXOPS_MASTODON_DB_PASS"}
+    DB_PORT=5432
+
+    LOCAL_DOMAIN=mastodon.immae.eu
+    LOCAL_HTTPS=true
+    ALTERNATE_DOMAINS=immae.eu
+
+    PAPERCLIP_SECRET=${builtins.getEnv "NIXOPS_MASTODON_PAPERCLIP_SECRET"}
+    SECRET_KEY_BASE=${builtins.getEnv "NIXOPS_MASTODON_SECRET_KEY_BASE"}
+    OTP_SECRET=${builtins.getEnv "NIXOPS_MASTODON_OTP_SECRET"}
+
+    VAPID_PRIVATE_KEY=${builtins.getEnv "NIXOPS_MASTODON_VAPID_PRIVATE_KEY"}
+    VAPID_PUBLIC_KEY=${builtins.getEnv "NIXOPS_MASTODON_VAPID_PUBLIC_KEY"}
+
+    SMTP_SERVER=mail.immae.eu
+    SMTP_PORT=587
+    SMTP_FROM_ADDRESS=notifications@mastodon.immae.eu
+    SMTP_DELIVERY_METHOD=smtp
+    PAPERCLIP_ROOT_PATH=${varDir}
+
+    STREAMING_CLUSTER_NUM=1
+
+    # LDAP authentication (optional)
+    LDAP_ENABLED=true
+    LDAP_HOST=ldap.immae.eu
+    LDAP_PORT=636
+    LDAP_METHOD=simple_tls
+    LDAP_BASE="dc=immae,dc=eu"
+    LDAP_BIND_DN="cn=mastodon,ou=services,dc=immae,dc=eu"
+    LDAP_PASSWORD="${builtins.getEnv "NIXOPS_MASTODON_LDAP_PASSWORD"}"
+    LDAP_UID="uid"
+    LDAP_SEARCH_FILTER="(&(%{uid}=%{email})(memberOf=cn=users,cn=mastodon,ou=services,dc=immae,dc=eu))"
+    '';
+
+    railsRoot = stdenv.mkDerivation {
+      name = "mastodon_immae";
+      inherit config mastodon;
+      builder = writeText "build_mastodon_immae" ''
+        source $stdenv/setup
+        set -a
+        source $config
+        set +a
+        cp -a $mastodon $out
+        cd $out
+        chmod u+rwX . node_modules public
+        RAILS_ENV=production bundle exec rails assets:precompile
+        '';
+      propagatedBuildInputs = with pkgs; [
+        zlib icu libchardet git bundler yarn
+        protobuf protobufc libidn libpqxx nodejs
+        imagemagick ffmpeg libxml2 libxslt pkgconfig
+        autoconf bison libyaml readline ncurses libffi gdbm
+        jemalloc which postgresql python3 cacert
+      ];
+    };
+in
+  {
+    inherit railsRoot config varDir socketsDir;
+    nodeSocket = "${socketsDir}/live_immae_node.sock";
+    railsSocket = "${socketsDir}/live_immae_puma.sock";
+  }