]> git.immae.eu Git - perso/Immae/Config/Nix.git/blob - modules/webapps/mastodon.nix
Move mastodon module outside of nixops
[perso/Immae/Config/Nix.git] / modules / webapps / mastodon.nix
1 { lib, pkgs, config, ... }:
2 let
3 name = "mastodon";
4 cfg = config.services.mastodon;
5
6 uid = config.ids.uids.mastodon;
7 gid = config.ids.gids.mastodon;
8 in
9 {
10 options.services.mastodon = {
11 enable = lib.mkEnableOption "Enable Mastodon’s service";
12 user = lib.mkOption {
13 type = lib.types.str;
14 default = name;
15 description = "User account under which Mastodon runs";
16 };
17 group = lib.mkOption {
18 type = lib.types.str;
19 default = name;
20 description = "Group under which Mastodon runs";
21 };
22 dataDir = lib.mkOption {
23 type = lib.types.path;
24 default = "/var/lib/${name}";
25 description = ''
26 The directory where Mastodon stores its data.
27 '';
28 };
29 socketsPrefix = lib.mkOption {
30 type = lib.types.string;
31 default = "live";
32 description = ''
33 The prefix to use for Mastodon sockets.
34 '';
35 };
36 socketsDir = lib.mkOption {
37 type = lib.types.path;
38 default = "/run/${name}";
39 description = ''
40 The directory where Mastodon puts runtime files and sockets.
41 '';
42 };
43 configFile = lib.mkOption {
44 type = lib.types.path;
45 description = ''
46 The configuration file path for Mastodon.
47 '';
48 };
49 package = lib.mkOption {
50 type = lib.types.package;
51 default = pkgs.webapps.mastodon;
52 description = ''
53 Mastodon package to use.
54 '';
55 };
56 # Output variables
57 workdir = lib.mkOption {
58 type = lib.types.package;
59 default = cfg.package.override { varDir = cfg.dataDir; };
60 description = ''
61 Adjusted mastodon package with overriden varDir
62 '';
63 readOnly = true;
64 };
65 sockets = lib.mkOption {
66 type = lib.types.attrsOf lib.types.path;
67 default = {
68 node = "${cfg.socketsDir}/${cfg.socketsPrefix}_node.sock";
69 rails = "${cfg.socketsDir}/${cfg.socketsPrefix}_puma.sock";
70 };
71 readOnly = true;
72 description = ''
73 Mastodon sockets
74 '';
75 };
76 };
77
78 config = lib.mkIf cfg.enable {
79 users.users = lib.optionalAttrs (cfg.user == name) (lib.singleton {
80 inherit name;
81 inherit uid;
82 group = cfg.group;
83 description = "Mastodon user";
84 home = cfg.dataDir;
85 useDefaultShell = true;
86 });
87 users.groups = lib.optionalAttrs (cfg.group == name) (lib.singleton {
88 inherit name;
89 inherit gid;
90 });
91
92 systemd.services.mastodon-streaming = {
93 description = "Mastodon Streaming";
94 wantedBy = [ "multi-user.target" ];
95 after = [ "network.target" "mastodon-web.service" ];
96
97 environment.NODE_ENV = "production";
98 environment.SOCKET = cfg.sockets.node;
99
100 path = [ pkgs.nodejs pkgs.bashInteractive ];
101
102 script = ''
103 exec npm run start
104 '';
105
106 postStart = ''
107 while [ ! -S $SOCKET ]; do
108 sleep 0.5
109 done
110 chmod a+w $SOCKET
111 '';
112
113 postStop = ''
114 rm $SOCKET
115 '';
116
117 serviceConfig = {
118 User = cfg.user;
119 EnvironmentFile = cfg.configFile;
120 PrivateTmp = true;
121 Restart = "always";
122 TimeoutSec = 15;
123 Type = "simple";
124 WorkingDirectory = cfg.workdir;
125 };
126
127 unitConfig.RequiresMountsFor = cfg.dataDir;
128 };
129
130 systemd.services.mastodon-web = {
131 description = "Mastodon Web app";
132 wantedBy = [ "multi-user.target" ];
133 after = [ "network.target" ];
134
135 environment.RAILS_ENV = "production";
136 environment.BUNDLE_PATH = "${cfg.workdir.gems}/${cfg.workdir.gems.ruby.gemPath}";
137 environment.BUNDLE_GEMFILE = "${cfg.workdir.gems.confFiles}/Gemfile";
138 environment.SOCKET = cfg.sockets.rails;
139
140 path = [ cfg.workdir.gems cfg.workdir.gems.ruby pkgs.file ];
141
142 preStart = ''
143 ./bin/bundle exec rails db:migrate
144 '';
145
146 script = ''
147 exec ./bin/bundle exec puma -C config/puma.rb
148 '';
149
150 serviceConfig = {
151 User = cfg.user;
152 EnvironmentFile = cfg.configFile;
153 PrivateTmp = true;
154 Restart = "always";
155 TimeoutSec = 60;
156 Type = "simple";
157 WorkingDirectory = cfg.workdir;
158 };
159
160 unitConfig.RequiresMountsFor = cfg.dataDir;
161 };
162
163 systemd.services.mastodon-sidekiq = {
164 description = "Mastodon Sidekiq";
165 wantedBy = [ "multi-user.target" ];
166 after = [ "network.target" "mastodon-web.service" ];
167
168 environment.RAILS_ENV="production";
169 environment.BUNDLE_PATH = "${cfg.workdir.gems}/${cfg.workdir.gems.ruby.gemPath}";
170 environment.BUNDLE_GEMFILE = "${cfg.workdir.gems.confFiles}/Gemfile";
171 environment.DB_POOL="5";
172
173 path = [ cfg.workdir.gems cfg.workdir.gems.ruby pkgs.imagemagick pkgs.ffmpeg pkgs.file ];
174
175 script = ''
176 exec ./bin/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
177 '';
178
179 serviceConfig = {
180 User = cfg.user;
181 EnvironmentFile = cfg.configFile;
182 PrivateTmp = true;
183 Restart = "always";
184 TimeoutSec = 15;
185 Type = "simple";
186 WorkingDirectory = cfg.workdir;
187 };
188
189 unitConfig.RequiresMountsFor = cfg.dataDir;
190 };
191
192 system.activationScripts.mastodon = {
193 deps = [ "users" ];
194 text = ''
195 install -m 0755 -o ${cfg.user} -g ${cfg.group} -d ${cfg.socketsDir}
196 install -m 0755 -o ${cfg.user} -g ${cfg.group} -d ${cfg.dataDir} ${cfg.dataDir}/tmp/cache
197 '';
198 };
199
200 };
201 }