diff options
Diffstat (limited to 'nixops/modules/websites/tools/mastodon.nix')
-rw-r--r-- | nixops/modules/websites/tools/mastodon.nix | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/nixops/modules/websites/tools/mastodon.nix b/nixops/modules/websites/tools/mastodon.nix new file mode 100644 index 0000000..3279cf8 --- /dev/null +++ b/nixops/modules/websites/tools/mastodon.nix | |||
@@ -0,0 +1,249 @@ | |||
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 | mySecrets.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 | } | ||