1 { lib, pkgs, config, ... }:
4 cfg = config.services.mastodon;
6 uid = config.ids.uids.mastodon;
7 gid = config.ids.gids.mastodon;
10 options.services.mastodon = {
11 enable = lib.mkEnableOption "Enable Mastodon’s service";
15 description = "User account under which Mastodon runs";
17 group = lib.mkOption {
20 description = "Group under which Mastodon runs";
22 dataDir = lib.mkOption {
23 type = lib.types.path;
24 default = "/var/lib/${name}";
26 The directory where Mastodon stores its data.
29 socketsPrefix = lib.mkOption {
30 type = lib.types.string;
33 The prefix to use for Mastodon sockets.
36 socketsDir = lib.mkOption {
37 type = lib.types.path;
38 default = "/run/${name}";
40 The directory where Mastodon puts runtime files and sockets.
43 configFile = lib.mkOption {
44 type = lib.types.path;
46 The configuration file path for Mastodon.
49 package = lib.mkOption {
50 type = lib.types.package;
51 default = pkgs.webapps.mastodon;
53 Mastodon package to use.
57 workdir = lib.mkOption {
58 type = lib.types.package;
59 default = cfg.package.override { varDir = cfg.dataDir; };
61 Adjusted mastodon package with overriden varDir
65 systemdStateDirectory = lib.mkOption {
67 # Use ReadWritePaths= instead if varDir is outside of /var/lib
68 default = assert lib.strings.hasPrefix "/var/lib/" cfg.dataDir;
69 lib.strings.removePrefix "/var/lib/" cfg.dataDir;
71 Adjusted Mastodon data directory for systemd
75 systemdRuntimeDirectory = lib.mkOption {
77 # Use ReadWritePaths= instead if socketsDir is outside of /run
78 default = assert lib.strings.hasPrefix "/run/" cfg.socketsDir;
79 lib.strings.removePrefix "/run/" cfg.socketsDir;
81 Adjusted Mastodon sockets directory for systemd
85 sockets = lib.mkOption {
86 type = lib.types.attrsOf lib.types.path;
88 node = "${cfg.socketsDir}/${cfg.socketsPrefix}_node.sock";
89 rails = "${cfg.socketsDir}/${cfg.socketsPrefix}_puma.sock";
98 config = lib.mkIf cfg.enable {
99 users.users = lib.optionalAttrs (cfg.user == name) (lib.singleton {
103 description = "Mastodon user";
105 useDefaultShell = true;
107 users.groups = lib.optionalAttrs (cfg.group == name) (lib.singleton {
112 systemd.services.mastodon-streaming = {
113 description = "Mastodon Streaming";
114 wantedBy = [ "multi-user.target" ];
115 after = [ "network.target" "mastodon-web.service" ];
117 environment.NODE_ENV = "production";
118 environment.SOCKET = cfg.sockets.node;
120 path = [ pkgs.nodejs pkgs.bashInteractive ];
127 while [ ! -S $SOCKET ]; do
139 EnvironmentFile = cfg.configFile;
144 WorkingDirectory = cfg.workdir;
145 StateDirectory = cfg.systemdStateDirectory;
146 RuntimeDirectory = cfg.systemdRuntimeDirectory;
147 RuntimeDirectoryPreserve = "yes";
150 unitConfig.RequiresMountsFor = cfg.dataDir;
153 systemd.services.mastodon-web = {
154 description = "Mastodon Web app";
155 wantedBy = [ "multi-user.target" ];
156 after = [ "network.target" ];
158 environment.RAILS_ENV = "production";
159 environment.BUNDLE_PATH = "${cfg.workdir.gems}/${cfg.workdir.gems.ruby.gemPath}";
160 environment.BUNDLE_GEMFILE = "${cfg.workdir.gems.confFiles}/Gemfile";
161 environment.SOCKET = cfg.sockets.rails;
163 path = [ cfg.workdir.gems cfg.workdir.gems.ruby pkgs.file ];
166 install -m 0755 -d ${cfg.dataDir}/tmp/cache
167 ./bin/bundle exec rails db:migrate
171 exec ./bin/bundle exec puma -C config/puma.rb
176 EnvironmentFile = cfg.configFile;
181 WorkingDirectory = cfg.workdir;
182 StateDirectory = cfg.systemdStateDirectory;
183 RuntimeDirectory = cfg.systemdRuntimeDirectory;
184 RuntimeDirectoryPreserve = "yes";
187 unitConfig.RequiresMountsFor = cfg.dataDir;
190 systemd.services.mastodon-sidekiq = {
191 description = "Mastodon Sidekiq";
192 wantedBy = [ "multi-user.target" ];
193 after = [ "network.target" "mastodon-web.service" ];
195 environment.RAILS_ENV="production";
196 environment.BUNDLE_PATH = "${cfg.workdir.gems}/${cfg.workdir.gems.ruby.gemPath}";
197 environment.BUNDLE_GEMFILE = "${cfg.workdir.gems.confFiles}/Gemfile";
198 environment.DB_POOL="5";
200 path = [ cfg.workdir.gems cfg.workdir.gems.ruby pkgs.imagemagick pkgs.ffmpeg pkgs.file ];
203 exec ./bin/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
208 EnvironmentFile = cfg.configFile;
213 WorkingDirectory = cfg.workdir;
214 StateDirectory = cfg.systemdStateDirectory;
215 RuntimeDirectory = cfg.systemdRuntimeDirectory;
216 RuntimeDirectoryPreserve = "yes";
219 unitConfig.RequiresMountsFor = cfg.dataDir;