diff options
-rw-r--r-- | modules/default.nix | 1 | ||||
-rw-r--r-- | modules/myids.nix | 2 | ||||
-rw-r--r-- | modules/webapps/mastodon.nix | 201 | ||||
-rw-r--r-- | nixops/modules/websites/tools/mastodon.nix | 149 |
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, ... }: | ||
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 | } | ||
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, ... }: |
2 | let | 2 | let |
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; | ||
13 | in { | 7 | in { |
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> |