]> git.immae.eu Git - perso/Immae/Config/Nix.git/blob - nixops/modules/websites/tools/mastodon.nix
Move secrets module outside of nixops
[perso/Immae/Config/Nix.git] / nixops / modules / websites / tools / mastodon.nix
1 { lib, pkgs, config, myconfig, mylibs, ... }:
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;
11 root = "/run/current-system/webapps/tools_mastodon";
12 cfg = config.services.myWebsites.tools.mastodon;
13 in {
14 options.services.myWebsites.tools.mastodon = {
15 enable = lib.mkEnableOption "enable mastodon's website";
16 };
17
18 config = lib.mkIf cfg.enable {
19 secrets.keys = [{
20 dest = "webapps/tools-mastodon";
21 user = "mastodon";
22 group = "mastodon";
23 permissions = "0400";
24 text = ''
25 REDIS_HOST=${env.redis.host}
26 REDIS_PORT=${env.redis.port}
27 REDIS_DB=${env.redis.db}
28 DB_HOST=${env.postgresql.socket}
29 DB_USER=${env.postgresql.user}
30 DB_NAME=${env.postgresql.database}
31 DB_PASS=${env.postgresql.password}
32 DB_PORT=${env.postgresql.port}
33
34 LOCAL_DOMAIN=mastodon.immae.eu
35 LOCAL_HTTPS=true
36 ALTERNATE_DOMAINS=immae.eu
37
38 PAPERCLIP_SECRET=${env.paperclip_secret}
39 SECRET_KEY_BASE=${env.secret_key_base}
40 OTP_SECRET=${env.otp_secret}
41
42 VAPID_PRIVATE_KEY=${env.vapid.private}
43 VAPID_PUBLIC_KEY=${env.vapid.public}
44
45 SMTP_DELIVERY_METHOD=sendmail
46 SMTP_FROM_ADDRESS=mastodon@tools.immae.eu
47 SENDMAIL_LOCATION="/run/wrappers/bin/sendmail"
48 PAPERCLIP_ROOT_PATH=${varDir}
49
50 STREAMING_CLUSTER_NUM=1
51
52 RAILS_LOG_LEVEL=warn
53
54 # LDAP authentication (optional)
55 LDAP_ENABLED=true
56 LDAP_HOST=ldap.immae.eu
57 LDAP_PORT=636
58 LDAP_METHOD=simple_tls
59 LDAP_BASE="dc=immae,dc=eu"
60 LDAP_BIND_DN="cn=mastodon,ou=services,dc=immae,dc=eu"
61 LDAP_PASSWORD="${env.ldap.password}"
62 LDAP_UID="uid"
63 LDAP_SEARCH_FILTER="(&(%{uid}=%{email})(memberOf=cn=users,cn=mastodon,ou=services,dc=immae,dc=eu))"
64 '';
65 }];
66 ids.uids.mastodon = env.user.uid;
67 ids.gids.mastodon = env.user.gid;
68
69 users.users.mastodon = {
70 name = "mastodon";
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 };
187
188 services.myWebsites.tools.modules = [
189 "headers" "proxy" "proxy_wstunnel" "proxy_http"
190 ];
191 security.acme.certs."eldiron".extraDomains."mastodon.immae.eu" = null;
192 system.extraSystemBuilderCmds = ''
193 mkdir -p $out/webapps
194 ln -s ${mastodon}/public/ $out/webapps/tools_mastodon
195 '';
196 services.myWebsites.tools.vhostConfs.mastodon = {
197 certName = "eldiron";
198 hosts = ["mastodon.immae.eu" ];
199 root = root;
200 extraConfig = [ ''
201 Header always set Referrer-Policy "strict-origin-when-cross-origin"
202 Header always set Strict-Transport-Security "max-age=31536000"
203
204 <LocationMatch "^/(assets|avatars|emoji|headers|packs|sounds|system)>
205 Header always set Cache-Control "public, max-age=31536000, immutable"
206 Require all granted
207 </LocationMatch>
208
209 ProxyPreserveHost On
210 RequestHeader set X-Forwarded-Proto "https"
211
212 RewriteEngine On
213
214 ProxyPass /500.html !
215 ProxyPass /sw.js !
216 ProxyPass /embed.js !
217 ProxyPass /robots.txt !
218 ProxyPass /manifest.json !
219 ProxyPass /browserconfig.xml !
220 ProxyPass /mask-icon.svg !
221 ProxyPassMatch ^(/.*\.(png|ico|gif)$) !
222 ProxyPassMatch ^/(assets|avatars|emoji|headers|packs|sounds|system|.well-known/acme-challenge) !
223
224 RewriteRule ^/api/v1/streaming/(.+)$ unix://${nodeSocket}|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]
226 ProxyPass / unix://${railsSocket}|http://mastodon.immae.eu/
227 ProxyPassReverse / unix://${railsSocket}|http://mastodon.immae.eu/
228
229 Alias /system ${varDir}
230
231 <Directory ${varDir}>
232 Require all granted
233 Options -MultiViews
234 </Directory>
235
236 <Directory ${root}>
237 Require all granted
238 Options -MultiViews +FollowSymlinks
239 </Directory>
240
241 ErrorDocument 500 /500.html
242 ErrorDocument 501 /500.html
243 ErrorDocument 502 /500.html
244 ErrorDocument 503 /500.html
245 ErrorDocument 504 /500.html
246 '' ];
247 };
248 };
249 }