aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2019-05-10 19:05:02 +0200
committerIsmaël Bouya <ismael.bouya@normalesup.org>2019-05-10 19:05:02 +0200
commit613aea5685ad4c698386c374474d8853bb736503 (patch)
tree687d0d244891d3d51b647d339f23533ec654ea98
parent1a7188052f235fb632700478fad0108e4306107d (diff)
downloadNix-613aea5685ad4c698386c374474d8853bb736503.tar.gz
Nix-613aea5685ad4c698386c374474d8853bb736503.tar.zst
Nix-613aea5685ad4c698386c374474d8853bb736503.zip
Move mastodon module outside of nixops
-rw-r--r--modules/default.nix1
-rw-r--r--modules/myids.nix2
-rw-r--r--modules/webapps/mastodon.nix201
-rw-r--r--nixops/modules/websites/tools/mastodon.nix149
4 files changed, 218 insertions, 135 deletions
diff --git a/modules/default.nix b/modules/default.nix
index 4445c55..7db0cc2 100644
--- a/modules/default.nix
+++ b/modules/default.nix
@@ -2,6 +2,7 @@
2 myids = ./myids.nix; 2 myids = ./myids.nix;
3 secrets = ./secrets.nix; 3 secrets = ./secrets.nix;
4 4
5 mastodon = ./webapps/mastodon.nix;
5 mediagoblin = ./webapps/mediagoblin.nix; 6 mediagoblin = ./webapps/mediagoblin.nix;
6 peertube = ./webapps/peertube.nix; 7 peertube = ./webapps/peertube.nix;
7} 8}
diff --git a/modules/myids.nix b/modules/myids.nix
index 8f74425..24d853b 100644
--- a/modules/myids.nix
+++ b/modules/myids.nix
@@ -6,11 +6,13 @@
6 peertube = 394; 6 peertube = 394;
7 nullmailer = 396; 7 nullmailer = 396;
8 mediagoblin = 397; 8 mediagoblin = 397;
9 mastodon = 399;
9 }; 10 };
10 ids.gids = { 11 ids.gids = {
11 peertube = 394; 12 peertube = 394;
12 nullmailer = 396; 13 nullmailer = 396;
13 mediagoblin = 397; 14 mediagoblin = 397;
15 mastodon = 399;
14 }; 16 };
15 }; 17 };
16} 18}
diff --git a/modules/webapps/mastodon.nix b/modules/webapps/mastodon.nix
new file mode 100644
index 0000000..ad6d0c3
--- /dev/null
+++ b/modules/webapps/mastodon.nix
@@ -0,0 +1,201 @@
1{ lib, pkgs, config, ... }:
2let
3 name = "mastodon";
4 cfg = config.services.mastodon;
5
6 uid = config.ids.uids.mastodon;
7 gid = config.ids.gids.mastodon;
8in
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}
diff --git a/nixops/modules/websites/tools/mastodon.nix b/nixops/modules/websites/tools/mastodon.nix
index c461bec..4b9b73e 100644
--- a/nixops/modules/websites/tools/mastodon.nix
+++ b/nixops/modules/websites/tools/mastodon.nix
@@ -1,15 +1,9 @@
1{ lib, pkgs, config, myconfig, mylibs, ... }: 1{ lib, pkgs, config, myconfig, mylibs, ... }:
2let 2let
3 varDir = "/var/lib/mastodon_immae";
4 socketsDir = "/run/mastodon";
5 nodeSocket = "${socketsDir}/live_immae_node.sock";
6 railsSocket = "${socketsDir}/live_immae_puma.sock";
7
8 mastodon = pkgs.webapps.mastodon.override { inherit varDir; };
9
10 env = myconfig.env.tools.mastodon; 3 env = myconfig.env.tools.mastodon;
11 root = "/run/current-system/webapps/tools_mastodon"; 4 root = "/run/current-system/webapps/tools_mastodon";
12 cfg = config.services.myWebsites.tools.mastodon; 5 cfg = config.services.myWebsites.tools.mastodon;
6 mcfg = config.services.mastodon;
13in { 7in {
14 options.services.myWebsites.tools.mastodon = { 8 options.services.myWebsites.tools.mastodon = {
15 enable = lib.mkEnableOption "enable mastodon's website"; 9 enable = lib.mkEnableOption "enable mastodon's website";
@@ -45,7 +39,7 @@ in {
45 SMTP_DELIVERY_METHOD=sendmail 39 SMTP_DELIVERY_METHOD=sendmail
46 SMTP_FROM_ADDRESS=mastodon@tools.immae.eu 40 SMTP_FROM_ADDRESS=mastodon@tools.immae.eu
47 SENDMAIL_LOCATION="/run/wrappers/bin/sendmail" 41 SENDMAIL_LOCATION="/run/wrappers/bin/sendmail"
48 PAPERCLIP_ROOT_PATH=${varDir} 42 PAPERCLIP_ROOT_PATH=${mcfg.dataDir}
49 43
50 STREAMING_CLUSTER_NUM=1 44 STREAMING_CLUSTER_NUM=1
51 45
@@ -63,126 +57,11 @@ in {
63 LDAP_SEARCH_FILTER="(&(%{uid}=%{email})(memberOf=cn=users,cn=mastodon,ou=services,dc=immae,dc=eu))" 57 LDAP_SEARCH_FILTER="(&(%{uid}=%{email})(memberOf=cn=users,cn=mastodon,ou=services,dc=immae,dc=eu))"
64 ''; 58 '';
65 }]; 59 }];
66 ids.uids.mastodon = env.user.uid; 60 services.mastodon = {
67 ids.gids.mastodon = env.user.gid; 61 enable = true;
68 62 configFile = "/var/secrets/webapps/tools-mastodon";
69 users.users.mastodon = { 63 socketsPrefix = "live_immae";
70 name = "mastodon"; 64 dataDir = "/var/lib/mastodon_immae";
71 uid = config.ids.uids.mastodon;
72 group = "mastodon";
73 description = "Mastodon user";
74 home = varDir;
75 useDefaultShell = true;
76 };
77
78 users.groups.mastodon.gid = config.ids.gids.mastodon;
79
80 systemd.services.mastodon-streaming = {
81 description = "Mastodon Streaming";
82 wantedBy = [ "multi-user.target" ];
83 after = [ "network.target" "mastodon-web.service" ];
84
85 environment.NODE_ENV = "production";
86 environment.SOCKET = nodeSocket;
87
88 path = [ pkgs.nodejs pkgs.bashInteractive ];
89
90 script = ''
91 exec npm run start
92 '';
93
94 postStart = ''
95 while [ ! -S $SOCKET ]; do
96 sleep 0.5
97 done
98 chmod a+w $SOCKET
99 '';
100
101 postStop = ''
102 rm $SOCKET
103 '';
104
105 serviceConfig = {
106 User = "mastodon";
107 EnvironmentFile = "/var/secrets/webapps/tools-mastodon";
108 PrivateTmp = true;
109 Restart = "always";
110 TimeoutSec = 15;
111 Type = "simple";
112 WorkingDirectory = mastodon;
113 };
114
115 unitConfig.RequiresMountsFor = varDir;
116 };
117
118 systemd.services.mastodon-web = {
119 description = "Mastodon Web app";
120 wantedBy = [ "multi-user.target" ];
121 after = [ "network.target" ];
122
123 environment.RAILS_ENV = "production";
124 environment.BUNDLE_PATH = "${mastodon.gems}/${mastodon.gems.ruby.gemPath}";
125 environment.BUNDLE_GEMFILE = "${mastodon.gems.confFiles}/Gemfile";
126 environment.SOCKET = railsSocket;
127
128 path = [ mastodon.gems mastodon.gems.ruby pkgs.file ];
129
130 preStart = ''
131 ./bin/bundle exec rails db:migrate
132 '';
133
134 script = ''
135 exec ./bin/bundle exec puma -C config/puma.rb
136 '';
137
138 serviceConfig = {
139 User = "mastodon";
140 EnvironmentFile = "/var/secrets/webapps/tools-mastodon";
141 PrivateTmp = true;
142 Restart = "always";
143 TimeoutSec = 60;
144 Type = "simple";
145 WorkingDirectory = mastodon;
146 };
147
148 unitConfig.RequiresMountsFor = varDir;
149 };
150
151 systemd.services.mastodon-sidekiq = {
152 description = "Mastodon Sidekiq";
153 wantedBy = [ "multi-user.target" ];
154 after = [ "network.target" "mastodon-web.service" ];
155
156 environment.RAILS_ENV="production";
157 environment.BUNDLE_PATH = "${mastodon.gems}/${mastodon.gems.ruby.gemPath}";
158 environment.BUNDLE_GEMFILE = "${mastodon.gems.confFiles}/Gemfile";
159 environment.DB_POOL="5";
160
161 path = [ mastodon.gems mastodon.gems.ruby pkgs.imagemagick pkgs.ffmpeg pkgs.file ];
162
163 script = ''
164 exec ./bin/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
165 '';
166
167 serviceConfig = {
168 User = "mastodon";
169 EnvironmentFile = "/var/secrets/webapps/tools-mastodon";
170 PrivateTmp = true;
171 Restart = "always";
172 TimeoutSec = 15;
173 Type = "simple";
174 WorkingDirectory = mastodon;
175 };
176
177 unitConfig.RequiresMountsFor = varDir;
178 };
179
180 system.activationScripts.mastodon = {
181 deps = [ "users" ];
182 text = ''
183 install -m 0755 -o mastodon -g mastodon -d ${socketsDir}
184 install -m 0755 -o mastodon -g mastodon -d ${varDir} ${varDir}/tmp/cache
185 '';
186 }; 65 };
187 66
188 services.myWebsites.tools.modules = [ 67 services.myWebsites.tools.modules = [
@@ -191,7 +70,7 @@ in {
191 security.acme.certs."eldiron".extraDomains."mastodon.immae.eu" = null; 70 security.acme.certs."eldiron".extraDomains."mastodon.immae.eu" = null;
192 system.extraSystemBuilderCmds = '' 71 system.extraSystemBuilderCmds = ''
193 mkdir -p $out/webapps 72 mkdir -p $out/webapps
194 ln -s ${mastodon}/public/ $out/webapps/tools_mastodon 73 ln -s ${mcfg.workdir}/public/ $out/webapps/tools_mastodon
195 ''; 74 '';
196 services.myWebsites.tools.vhostConfs.mastodon = { 75 services.myWebsites.tools.vhostConfs.mastodon = {
197 certName = "eldiron"; 76 certName = "eldiron";
@@ -221,14 +100,14 @@ in {
221 ProxyPassMatch ^(/.*\.(png|ico|gif)$) ! 100 ProxyPassMatch ^(/.*\.(png|ico|gif)$) !
222 ProxyPassMatch ^/(assets|avatars|emoji|headers|packs|sounds|system|.well-known/acme-challenge) ! 101 ProxyPassMatch ^/(assets|avatars|emoji|headers|packs|sounds|system|.well-known/acme-challenge) !
223 102
224 RewriteRule ^/api/v1/streaming/(.+)$ unix://${nodeSocket}|http://mastodon.immae.eu/api/v1/streaming/$1 [P,NE,QSA,L] 103 RewriteRule ^/api/v1/streaming/(.+)$ unix://${mcfg.sockets.node}|http://mastodon.immae.eu/api/v1/streaming/$1 [P,NE,QSA,L]
225 RewriteRule ^/api/v1/streaming/$ unix://${nodeSocket}|ws://mastodon.immae.eu/ [P,NE,QSA,L] 104 RewriteRule ^/api/v1/streaming/$ unix://${mcfg.sockets.node}|ws://mastodon.immae.eu/ [P,NE,QSA,L]
226 ProxyPass / unix://${railsSocket}|http://mastodon.immae.eu/ 105 ProxyPass / unix://${mcfg.sockets.rails}|http://mastodon.immae.eu/
227 ProxyPassReverse / unix://${railsSocket}|http://mastodon.immae.eu/ 106 ProxyPassReverse / unix://${mcfg.sockets.rails}|http://mastodon.immae.eu/
228 107
229 Alias /system ${varDir} 108 Alias /system ${mcfg.dataDir}
230 109
231 <Directory ${varDir}> 110 <Directory ${mcfg.dataDir}>
232 Require all granted 111 Require all granted
233 Options -MultiViews 112 Options -MultiViews
234 </Directory> 113 </Directory>