I want to have a private copy of the wiki on umber and a public copy on teal. It would be good to share configs between them, so we should use an ingredient for this
+2
packetmix/systems/default.nix
+2
packetmix/systems/default.nix
+6
packetmix/systems/teal/headscale.nix
+6
packetmix/systems/teal/headscale.nix
+6
-348
packetmix/systems/teal/wiki.nix
+6
-348
packetmix/systems/teal/wiki.nix
···
1
1
# SPDX-FileCopyrightText: 2025 FreshlyBakedCake
2
+
# SPDX-FileCopyrightText: 2026 Collabora Productivity Limited
2
3
#
3
4
# SPDX-License-Identifier: MIT
4
5
5
6
{
6
-
project,
7
-
system,
8
-
config,
9
-
pkgs,
10
-
lib,
11
-
...
12
-
}:
13
-
{
14
-
clicks.storage.impermanence.persist.directories = [
15
-
{
16
-
directory = "/var/lib/mediawiki";
17
-
mode = "0700";
18
-
user = "mediawiki";
19
-
defaultPerms.mode = "0700";
20
-
}
21
-
{
22
-
directory = "/var/lib/private/opensearch";
23
-
mode = "0700";
24
-
user = "opensearch";
25
-
defaultPerms.mode = "0700";
26
-
}
27
-
];
28
-
29
-
services.mediawiki = {
30
-
enable = true;
31
-
package = project.inputs.nixos-unstable.result.${system}.mediawiki; # header auth master requires mediawiki unstable - header auth stable is broken on missing Hooks (recently removed in stable MW version)
32
-
phpPackage = pkgs.php83.withExtensions ({ enabled, all }: enabled ++ [ all.luasandbox ]);
33
-
database.type = "postgres";
34
-
path = [
35
-
pkgs.diffutils
36
-
pkgs.imagemagick
37
-
pkgs.python3Packages.pygments
38
-
];
39
-
extensions = {
40
-
AdvancedSearch = project.inputs.AdvancedSearch.src;
41
-
Auth_remoteuser = project.inputs.Auth_remoteuser.src; # header auth
42
-
AutoCreateCategoryPages = project.inputs.AutoCreateCategoryPages.src;
43
-
Cargo = project.inputs.Cargo.src; # queries and soforth
44
-
CategoryTree = null;
45
-
CheckUser = null;
46
-
Cite = null;
47
-
CiteThisPage = null;
48
-
CirrusSearch = "${
49
-
pkgs.php.buildComposerProject {
50
-
pname = "CirrusSearch";
51
-
version = "0.0.3665";
52
-
src = project.inputs.CirrusSearch.src;
53
-
vendorHash = "sha256-MLD/3hvzX1aqR4knajJ1amb6K5SVtxlfy+UZWoSi1Bk=";
54
-
composerLock = ./wiki/CirrusSearch.composer.lock;
55
-
}
56
-
}/share/php/CirrusSearch"; # needed for advancedsearch
57
-
CodeEditor = null;
58
-
DiscussionTools = null;
59
-
Echo = null;
60
-
EditNotify = project.inputs.EditNotify.src;
61
-
Elastica = "${
62
-
pkgs.php.buildComposerProject {
63
-
pname = "Elastica";
64
-
version = "0.0.3665";
65
-
src = project.inputs.Elastica.src;
66
-
vendorHash = "sha256-4kp8njLTqPeFCREnGharCB/pmYBnXLJR4TdD6EH6WCI=";
67
-
composerLock = ./wiki/Elastica.composer.lock;
68
-
}
69
-
}/share/php/Elastica"; # needed for cirrussearch
70
-
Linter = null;
71
-
Math = null;
72
-
MobileFrontend = project.inputs.MobileFrontend.src;
73
-
NamespacePreload = project.inputs.NamespacePreload.src;
74
-
Network = "${
75
-
config.services.phpfpm.pools.mediawiki.phpPackage.buildComposerProject {
76
-
pname = "Network";
77
-
version = "0.0.3665";
78
-
src = project.inputs.Network.src;
79
-
vendorHash = "sha256-JHa6PW5xO3pcwn/2jbGXM0wGhr6UmtqFdxaGCgpaYb0=";
80
-
composerLock = ./wiki/Network.composer.lock;
81
-
}
82
-
}/share/php/Network"; # for page connection graphs
83
-
OpenIDConnect = "${
84
-
pkgs.php.buildComposerProject {
85
-
pname = "OpenIDConnect";
86
-
version = "0.0.3665";
87
-
src = project.inputs.OpenIDConnect.src;
88
-
vendorHash = "sha256-DjxyOK21tbBEj6hFfhVNDxeNu4a26hvMRHgD/u24ZT0=";
89
-
composerLock = ./wiki/OpenIDConnect.composer.lock;
90
-
91
-
postInstall = ''
92
-
cat sql/postgres/ChangePrimaryKey.sql | sed 's/DROP INDEX "primary"/ALTER TABLE openid_connect DROP CONSTRAINT openid_connect_pkey/' > $out/share/php/OpenIDConnect/sql/postgres/ChangePrimaryKey.sql
93
-
'';
94
-
}
95
-
}/share/php/OpenIDConnect";
96
-
ParserFunctions = null;
97
-
PluggableAuth = project.inputs.PluggableAuth.src; # needed for OIDC
98
-
Poem = null;
99
-
ReplaceText = null;
100
-
Scribunto = null;
101
-
SecureLinkFixer = null;
102
-
SimpleTooltip = project.inputs.SimpleTooltip.src;
103
-
SyntaxHighlight_GeSHi = null;
104
-
TemplateData = null;
105
-
TemplateStyles = null;
106
-
Thanks = null;
107
-
UserMerge = project.inputs.UserMerge.src;
108
-
VisualEditor = null;
109
-
WikiEditor = null;
110
-
};
111
-
extraConfig = ''
112
-
$wgMaxUploadSize = 1024*1024*1024*8;
113
-
$wgGroupPermissions['autoconfirmed']['upload_by_url'] = true;
114
-
$wgGroupPermissions['autoconfirmed']['interwiki'] = true; // https://wiki.freshly.space/wiki/Special:Interwiki - edit shortlink prefixes, crazy-strong permission but we trust our friends
115
-
$wgAllowCopyUploads = true;
116
-
$wgCopyUploadsFromSpecialUpload = true;
117
-
118
-
$wgSMTP = [
119
-
'host' => 'ssl://mail.freshly.space',
120
-
'IDHost' => 'wiki.freshly.space',
121
-
'localhost' => 'wiki.freshly.space',
122
-
'port' => 465,
123
-
'auth' => true,
124
-
'username' => 'automated@freshly.space',
125
-
'password' => trim(file_get_contents('/secrets/mediawiki/mail_password.txt'))
126
-
];
127
-
$wgLocalInterwikis = [
128
-
'fbc'
129
-
];
130
-
131
-
$wgWhitelistReadRegexp = [
132
-
'/^Main Page$/',
133
-
'/^Public:/',
134
-
'/^User:/'
135
-
];
136
-
$wgGroupPermissions['*']['read'] = false;
137
-
$wgGroupPermissions['*']['edit'] = false;
138
-
$wgGroupPermissions['*']['createaccount'] = false;
139
-
$wgGroupPermissions['*']['autocreateaccount'] = true;
140
-
141
-
$wgGroupPermissions['bureaucrat']['usermerge'] = true;
142
-
143
-
$wgAuthRemoteuserUserName = function () {
144
-
if (!isset($_SERVER['HTTP_X_WEBAUTH_LOGIN'])) {
145
-
return "";
146
-
}
147
-
148
-
if ($_SERVER['HTTP_X_WEBAUTH_LOGIN'] === 'hyperneutrino') {
149
-
return 'HyperNeutrino';
150
-
}
151
-
152
-
return $_SERVER['HTTP_X_WEBAUTH_LOGIN'];
153
-
};
154
-
$wgAuthRemoteuserPriority = MediaWiki\Session\SessionInfo::MAX_PRIORITY;
155
-
156
-
$wgUseCdn = true;
157
-
$wgCdnServersNoPurge = [
158
-
'127.0.0.1'
159
-
];
160
-
$wgUsePrivateIPs = true;
161
-
162
-
$wgUseInstantCommons = true;
163
-
$wgPingback = false;
164
-
165
-
$wgPluggableAuth_Config = [
166
-
'Freshly Baked Cake Kanidm' => [
167
-
'plugin' => 'OpenIDConnect',
168
-
'data' => [
169
-
'providerURL' => 'https://idm.freshly.space/oauth2/openid/mediawiki',
170
-
'clientID' => 'mediawiki',
171
-
'clientsecret' => trim(file_get_contents('/secrets/mediawiki/oidc_client_secret.txt')),
172
-
'codeChallengeMethod' => 'S256'
173
-
]
174
-
]
175
-
];
176
-
177
-
$wgOpenIDConnect_MigrateUsersByUserName = true;
178
-
179
-
$wgLogos = [
180
-
'icon' => '/icon.svg',
181
-
'svg' => '/icon.svg'
182
-
];
183
-
184
-
$wgPygmentizePath = '${pkgs.python3Packages.pygments}/bin/pygmentize';
185
-
186
-
$wgScribuntoDefaultEngine = 'luasandbox';
187
-
188
-
$wgNamespacesWithSubpages[NS_MAIN] = true;
189
-
190
-
$wgNamespacePreloadDoExpansion = false; // This can't expand {{PAGENAME}} (or like) correctly, making it very nearly useless
191
-
192
-
$wgCirrusSearchServers = [
193
-
[
194
-
"host" => '127.0.0.1',
195
-
"port" => 1037
196
-
]
197
-
];
198
-
$wgSearchType = 'CirrusSearch';
199
-
$wgNamespacesToBeSearchedDefault[NS_CATEGORY] = true;
200
-
201
-
$wgUrlProtocols[] = "rad:";
202
-
203
-
$wgSVGNativeRendering = true;
204
-
205
-
$wgRCWatchCategoryMembership = true;
206
-
207
-
$wgCargoPageDataColumns[] = 'creationDate';
208
-
$wgCargoPageDataColumns[] = 'modificationDate';
209
-
$wgCargoPageDataColumns[] = 'creator';
210
-
$wgCargoPageDataColumns[] = 'lastEditor';
211
-
$wgCargoPageDataColumns[] = 'displayTitle';
212
-
$wgCargoPageDataColumns[] = 'categories';
213
-
$wgCargoPageDataColumns[] = 'numRevisions';
214
-
$wgCargoPageDataColumns[] = 'outgoingLinks';
215
-
$wgCargoPageDataColumns[] = 'isRedirect';
216
-
$wgCargoPageDataColumns[] = 'pageNameOrRedirect';
217
-
$wgCargoPageDataColumns[] = 'pageIDOrRedirect';
218
-
219
-
$wgCargoFileDataColumns[] = 'mediaType';
220
-
$wgCargoFileDataColumns[] = 'path';
221
-
$wgCargoFileDataColumns[] = 'lastUploadDate';
222
-
223
-
$wgFixDoubleRedirects = true;
224
-
225
-
$wgMFAutodetectMobileView = true;
226
-
$wgMFEnableMobilePreferences = true;
227
-
wfLoadSkin( 'MinervaNeue' );
228
-
229
-
$wgShowExceptionDetails = true;
230
-
$wgDevelopmentWarnings = true;
231
-
'';
232
-
webserver = "nginx";
233
-
url = "https://wiki.freshly.space";
234
-
nginx.hostName = "wiki.freshly.space";
235
-
name = "Freshly Wiki";
236
-
database.createLocally = true;
237
-
238
-
passwordSender = "wiki@freshly.space";
239
-
240
-
passwordFile = "/secrets/mediawiki/initial_admin_password.txt";
241
-
};
242
-
243
-
systemd.timers.mediawiki-maintenance = {
244
-
wantedBy = [ "timers.target" ];
245
-
timerConfig = {
246
-
OnUnitActiveSec = "30";
247
-
OnBootSec = "30";
248
-
Persistent = false;
249
-
Unit = "mediawiki-maintenance.service";
250
-
};
251
-
};
252
-
253
-
systemd.services.mediawiki-maintenance = {
254
-
script = ''
255
-
${config.services.phpfpm.pools.mediawiki.phpPackage}/bin/php ${config.services.mediawiki.finalPackage}/share/mediawiki/maintenance/run.php runJobs --memory-limit 1G --maxtime 30
256
-
'';
257
-
serviceConfig = {
258
-
Type = "oneshot";
259
-
RemainAfterExit = false;
260
-
User = "mediawiki";
261
-
Group = "nginx";
262
-
PrivateTmp = true;
263
-
Environment = "MEDIAWIKI_CONFIG=${config.services.phpfpm.pools.mediawiki.phpEnv.MEDIAWIKI_CONFIG}";
264
-
};
265
-
};
266
-
267
-
services.opensearch = {
268
-
# needed for cirrussearch
269
-
enable = true;
270
-
package = project.packages.opensearch.result.${system};
271
-
settings = {
272
-
"http.port" = 1037;
273
-
"path.data" = "/var/lib/private/opensearch/data";
274
-
"path.logs" = "/var/lib/private/opensearch/logs";
275
-
};
276
-
};
277
-
278
-
services.nginx.enable = true;
279
7
services.headscale.settings.dns.extra_records = [
280
8
{
281
9
# wiki.freshly.space -> teal
···
284
12
value = "100.64.0.5";
285
13
}
286
14
];
287
-
services.nginx.virtualHosts."wiki.freshly.space" = {
288
-
listen = [
289
-
{
290
-
addr = "127.0.0.1";
291
-
port = 1036;
292
-
}
293
-
];
294
-
295
-
locations = {
296
-
"= /" = lib.mkForce {
297
-
extraConfig = ''
298
-
return 301 https://wiki.freshly.space/wiki/;
299
-
''; # overriding nixpkgs /wiki/ redirect since as our double-proxy makes it redirect to :1036
300
-
};
301
-
"= /favicon.ico".alias = ./wiki/favicon.ico;
302
-
"= /icon.svg".alias = ./wiki/icon.svg;
303
-
};
304
-
305
-
extraConfig = ''
306
-
client_max_body_size 1024M;
307
-
'';
308
-
};
309
-
services.nginx.virtualHosts."external.wiki.freshly.space" = {
310
-
listenAddresses = [
311
-
"0.0.0.0"
312
-
"[::0]"
313
-
];
314
-
315
-
serverName = "wiki.freshly.space";
316
-
317
-
addSSL = true;
318
-
enableACME = true;
319
-
acmeRoot = null;
320
-
321
-
locations."/" = {
322
-
proxyPass = "http://127.0.0.1:1036";
323
-
recommendedProxySettings = true;
324
-
proxyWebsockets = true;
325
-
326
-
extraConfig = ''
327
-
proxy_set_header X-Webauth-Login "";
328
-
proxy_cache off;
329
-
'';
330
-
};
331
-
332
-
extraConfig = ''
333
-
client_max_body_size 1024M;
334
-
'';
335
-
};
336
-
services.nginx.virtualHosts."internal.wiki.freshly.space" = {
337
-
listenAddresses = [ "localhost.tailscale" ];
338
-
339
-
serverName = "wiki.freshly.space";
340
-
341
-
addSSL = true;
342
-
enableACME = true;
343
-
acmeRoot = null;
344
-
345
-
locations."/" = {
346
-
proxyPass = "http://127.0.0.1:1036";
347
-
recommendedProxySettings = true;
348
-
proxyWebsockets = true;
349
-
350
-
extraConfig = ''
351
-
proxy_cache off;
352
-
'';
353
-
};
354
-
355
-
extraConfig = ''
356
-
client_max_body_size 1024M;
357
-
'';
358
-
};
359
15
360
-
services.nginx.tailscaleAuth = {
361
-
enable = true;
362
-
virtualHosts = [ "internal.wiki.freshly.space" ];
16
+
ingredient.wiki.wiki = {
17
+
hostname = "wiki.freshly.space";
18
+
email = "wiki@freshly.space";
19
+
enablePublicInternet = true;
20
+
enableAutoRegistration = true;
363
21
};
364
22
}
+10
packetmix/systems/umber/wiki.nix
+10
packetmix/systems/umber/wiki.nix
+384
packetmix/systems/wiki/wiki.nix
+384
packetmix/systems/wiki/wiki.nix
···
1
+
# SPDX-FileCopyrightText: 2025 FreshlyBakedCake
2
+
# SPDX-FileCopyrightText: 2026 Collabora Productivity Limited
3
+
#
4
+
# SPDX-License-Identifier: MIT
5
+
6
+
# This ingredient has some default values (including OIDC config/etc.) that make it probably unsuitable for use outside of Freshly Baked. Sorry.
7
+
{
8
+
project,
9
+
system,
10
+
config,
11
+
pkgs,
12
+
lib,
13
+
...
14
+
}:
15
+
{
16
+
options.ingredient.wiki.wiki = {
17
+
hostname = lib.mkOption {
18
+
type = lib.types.str;
19
+
description = "Where your wiki should be hosted";
20
+
};
21
+
email = lib.mkOption {
22
+
type = lib.types.str;
23
+
description = "What email should notifications/password resets/etc. come from";
24
+
};
25
+
enablePublicInternet = lib.mkEnableOption "Allow access from the public internet with authentication via OIDC";
26
+
enableAutoRegistration = lib.mkEnableOption "Allow unregistered users to automatically register via OIDC or Tailscale";
27
+
};
28
+
29
+
config = {
30
+
clicks.storage.impermanence.persist.directories = [
31
+
{
32
+
directory = "/var/lib/mediawiki";
33
+
mode = "0700";
34
+
user = "mediawiki";
35
+
defaultPerms.mode = "0700";
36
+
}
37
+
{
38
+
directory = "/var/lib/private/opensearch";
39
+
mode = "0700";
40
+
user = "opensearch";
41
+
defaultPerms.mode = "0700";
42
+
}
43
+
];
44
+
45
+
services.mediawiki = {
46
+
enable = true;
47
+
package = project.inputs.nixos-unstable.result.${system}.mediawiki; # header auth master requires mediawiki unstable - header auth stable is broken on missing Hooks (recently removed in stable MW version)
48
+
phpPackage = pkgs.php83.withExtensions ({ enabled, all }: enabled ++ [ all.luasandbox ]);
49
+
database.type = "postgres";
50
+
path = [
51
+
pkgs.diffutils
52
+
pkgs.imagemagick
53
+
pkgs.python3Packages.pygments
54
+
];
55
+
extensions = {
56
+
AdvancedSearch = project.inputs.AdvancedSearch.src;
57
+
Auth_remoteuser = project.inputs.Auth_remoteuser.src; # header auth
58
+
AutoCreateCategoryPages = project.inputs.AutoCreateCategoryPages.src;
59
+
Cargo = project.inputs.Cargo.src; # queries and soforth
60
+
CategoryTree = null;
61
+
CheckUser = null;
62
+
Cite = null;
63
+
CiteThisPage = null;
64
+
CirrusSearch = "${
65
+
pkgs.php.buildComposerProject {
66
+
pname = "CirrusSearch";
67
+
version = "0.0.3665";
68
+
src = project.inputs.CirrusSearch.src;
69
+
vendorHash = "sha256-MLD/3hvzX1aqR4knajJ1amb6K5SVtxlfy+UZWoSi1Bk=";
70
+
composerLock = ./wiki/CirrusSearch.composer.lock;
71
+
}
72
+
}/share/php/CirrusSearch"; # needed for advancedsearch
73
+
CodeEditor = null;
74
+
DiscussionTools = null;
75
+
Echo = null;
76
+
EditNotify = project.inputs.EditNotify.src;
77
+
Elastica = "${
78
+
pkgs.php.buildComposerProject {
79
+
pname = "Elastica";
80
+
version = "0.0.3665";
81
+
src = project.inputs.Elastica.src;
82
+
vendorHash = "sha256-4kp8njLTqPeFCREnGharCB/pmYBnXLJR4TdD6EH6WCI=";
83
+
composerLock = ./wiki/Elastica.composer.lock;
84
+
}
85
+
}/share/php/Elastica"; # needed for cirrussearch
86
+
Linter = null;
87
+
Math = null;
88
+
MobileFrontend = project.inputs.MobileFrontend.src;
89
+
NamespacePreload = project.inputs.NamespacePreload.src;
90
+
Network = "${
91
+
config.services.phpfpm.pools.mediawiki.phpPackage.buildComposerProject {
92
+
pname = "Network";
93
+
version = "0.0.3665";
94
+
src = project.inputs.Network.src;
95
+
vendorHash = "sha256-JHa6PW5xO3pcwn/2jbGXM0wGhr6UmtqFdxaGCgpaYb0=";
96
+
composerLock = ./wiki/Network.composer.lock;
97
+
}
98
+
}/share/php/Network"; # for page connection graphs
99
+
OpenIDConnect = lib.mkIf config.ingredient.wiki.wiki.enablePublicInternet "${
100
+
pkgs.php.buildComposerProject {
101
+
pname = "OpenIDConnect";
102
+
version = "0.0.3665";
103
+
src = project.inputs.OpenIDConnect.src;
104
+
vendorHash = "sha256-DjxyOK21tbBEj6hFfhVNDxeNu4a26hvMRHgD/u24ZT0=";
105
+
composerLock = ./wiki/OpenIDConnect.composer.lock;
106
+
107
+
postInstall = ''
108
+
cat sql/postgres/ChangePrimaryKey.sql | sed 's/DROP INDEX "primary"/ALTER TABLE openid_connect DROP CONSTRAINT openid_connect_pkey/' > $out/share/php/OpenIDConnect/sql/postgres/ChangePrimaryKey.sql
109
+
'';
110
+
}
111
+
}/share/php/OpenIDConnect";
112
+
ParserFunctions = null;
113
+
PluggableAuth = lib.mkIf config.ingredient.wiki.wiki.enablePublicInternet project.inputs.PluggableAuth.src; # needed for OIDC
114
+
Poem = null;
115
+
ReplaceText = null;
116
+
Scribunto = null;
117
+
SecureLinkFixer = null;
118
+
SimpleTooltip = project.inputs.SimpleTooltip.src;
119
+
SyntaxHighlight_GeSHi = null;
120
+
TemplateData = null;
121
+
TemplateStyles = null;
122
+
Thanks = null;
123
+
UserMerge = project.inputs.UserMerge.src;
124
+
VisualEditor = null;
125
+
WikiEditor = null;
126
+
};
127
+
extraConfig = ''
128
+
$wgMaxUploadSize = 1024*1024*1024*8;
129
+
$wgGroupPermissions['autoconfirmed']['upload_by_url'] = true;
130
+
$wgGroupPermissions['autoconfirmed']['interwiki'] = true; // Special:Interwiki - edit shortlink prefixes, crazy-strong permission but we trust our friends
131
+
$wgAllowCopyUploads = true;
132
+
$wgCopyUploadsFromSpecialUpload = true;
133
+
134
+
$wgSMTP = [
135
+
'host' => 'ssl://mail.freshly.space',
136
+
'IDHost' => '${config.ingredient.wiki.wiki.hostname}',
137
+
'localhost' => '${config.ingredient.wiki.wiki.hostname}',
138
+
'port' => 465,
139
+
'auth' => true,
140
+
'username' => 'automated@freshly.space',
141
+
'password' => trim(file_get_contents('/secrets/mediawiki/mail_password.txt'))
142
+
];
143
+
$wgLocalInterwikis = [
144
+
'fbc'
145
+
];
146
+
147
+
$wgWhitelistReadRegexp = [
148
+
'/^Main Page$/',
149
+
'/^Public:/',
150
+
'/^User:/'
151
+
];
152
+
$wgGroupPermissions['*']['read'] = false;
153
+
$wgGroupPermissions['*']['edit'] = false;
154
+
$wgGroupPermissions['*']['createaccount'] = false;
155
+
$wgGroupPermissions['*']['autocreateaccount'] = ${
156
+
if config.ingredient.wiki.wiki.enableAutoRegistration then "true" else "false"
157
+
};
158
+
159
+
$wgGroupPermissions['bureaucrat']['usermerge'] = true;
160
+
161
+
$wgAuthRemoteuserUserName = function () {
162
+
if (!isset($_SERVER['HTTP_X_WEBAUTH_LOGIN'])) {
163
+
return "";
164
+
}
165
+
166
+
if ($_SERVER['HTTP_X_WEBAUTH_LOGIN'] === 'hyperneutrino') {
167
+
return 'HyperNeutrino';
168
+
}
169
+
170
+
return $_SERVER['HTTP_X_WEBAUTH_LOGIN'];
171
+
};
172
+
$wgAuthRemoteuserPriority = MediaWiki\Session\SessionInfo::MAX_PRIORITY;
173
+
174
+
$wgUseCdn = true;
175
+
$wgCdnServersNoPurge = [
176
+
'127.0.0.1'
177
+
];
178
+
$wgUsePrivateIPs = true;
179
+
180
+
$wgUseInstantCommons = true;
181
+
$wgPingback = false;
182
+
183
+
${
184
+
if config.ingredient.wiki.wiki.enablePublicInternet then
185
+
''
186
+
$wgPluggableAuth_Config = [
187
+
'Freshly Baked Cake Kanidm' => [
188
+
'plugin' => 'OpenIDConnect',
189
+
'data' => [
190
+
'providerURL' => 'https://idm.freshly.space/oauth2/openid/mediawiki',
191
+
'clientID' => 'mediawiki',
192
+
'clientsecret' => trim(file_get_contents('/secrets/mediawiki/oidc_client_secret.txt')),
193
+
'codeChallengeMethod' => 'S256'
194
+
]
195
+
]
196
+
];
197
+
''
198
+
else
199
+
""
200
+
}
201
+
202
+
$wgOpenIDConnect_MigrateUsersByUserName = true;
203
+
204
+
$wgLogos = [
205
+
'icon' => '/icon.svg',
206
+
'svg' => '/icon.svg'
207
+
];
208
+
209
+
$wgPygmentizePath = '${pkgs.python3Packages.pygments}/bin/pygmentize';
210
+
211
+
$wgScribuntoDefaultEngine = 'luasandbox';
212
+
213
+
$wgNamespacesWithSubpages[NS_MAIN] = true;
214
+
215
+
$wgNamespacePreloadDoExpansion = false; // This can't expand {{PAGENAME}} (or like) correctly, making it very nearly useless
216
+
217
+
$wgCirrusSearchServers = [
218
+
[
219
+
"host" => '127.0.0.1',
220
+
"port" => 1037
221
+
]
222
+
];
223
+
$wgSearchType = 'CirrusSearch';
224
+
$wgNamespacesToBeSearchedDefault[NS_CATEGORY] = true;
225
+
226
+
$wgUrlProtocols[] = "rad:";
227
+
228
+
$wgSVGNativeRendering = true;
229
+
230
+
$wgRCWatchCategoryMembership = true;
231
+
232
+
$wgCargoPageDataColumns[] = 'creationDate';
233
+
$wgCargoPageDataColumns[] = 'modificationDate';
234
+
$wgCargoPageDataColumns[] = 'creator';
235
+
$wgCargoPageDataColumns[] = 'lastEditor';
236
+
$wgCargoPageDataColumns[] = 'displayTitle';
237
+
$wgCargoPageDataColumns[] = 'categories';
238
+
$wgCargoPageDataColumns[] = 'numRevisions';
239
+
$wgCargoPageDataColumns[] = 'outgoingLinks';
240
+
$wgCargoPageDataColumns[] = 'isRedirect';
241
+
$wgCargoPageDataColumns[] = 'pageNameOrRedirect';
242
+
$wgCargoPageDataColumns[] = 'pageIDOrRedirect';
243
+
244
+
$wgCargoFileDataColumns[] = 'mediaType';
245
+
$wgCargoFileDataColumns[] = 'path';
246
+
$wgCargoFileDataColumns[] = 'lastUploadDate';
247
+
248
+
$wgFixDoubleRedirects = true;
249
+
250
+
$wgMFAutodetectMobileView = true;
251
+
$wgMFEnableMobilePreferences = true;
252
+
wfLoadSkin( 'MinervaNeue' );
253
+
254
+
$wgShowExceptionDetails = true;
255
+
$wgDevelopmentWarnings = true;
256
+
'';
257
+
webserver = "nginx";
258
+
url = "https://${config.ingredient.wiki.wiki.hostname}";
259
+
nginx.hostName = config.ingredient.wiki.wiki.hostname;
260
+
name = "Freshly Wiki";
261
+
database.createLocally = true;
262
+
263
+
passwordSender = config.ingredient.wiki.wiki.email;
264
+
265
+
passwordFile = "/secrets/mediawiki/initial_admin_password.txt";
266
+
};
267
+
268
+
systemd.timers.mediawiki-maintenance = {
269
+
wantedBy = [ "timers.target" ];
270
+
timerConfig = {
271
+
OnUnitActiveSec = "30";
272
+
OnBootSec = "30";
273
+
Persistent = false;
274
+
Unit = "mediawiki-maintenance.service";
275
+
};
276
+
};
277
+
278
+
systemd.services.mediawiki-maintenance = {
279
+
script = ''
280
+
${config.services.phpfpm.pools.mediawiki.phpPackage}/bin/php ${config.services.mediawiki.finalPackage}/share/mediawiki/maintenance/run.php runJobs --memory-limit 1G --maxtime 30
281
+
'';
282
+
serviceConfig = {
283
+
Type = "oneshot";
284
+
RemainAfterExit = false;
285
+
User = "mediawiki";
286
+
Group = "nginx";
287
+
PrivateTmp = true;
288
+
Environment = "MEDIAWIKI_CONFIG=${config.services.phpfpm.pools.mediawiki.phpEnv.MEDIAWIKI_CONFIG}";
289
+
};
290
+
};
291
+
292
+
services.opensearch = {
293
+
# needed for cirrussearch
294
+
enable = true;
295
+
package = project.packages.opensearch.result.${system};
296
+
settings = {
297
+
"http.port" = 1037;
298
+
"path.data" = "/var/lib/private/opensearch/data";
299
+
"path.logs" = "/var/lib/private/opensearch/logs";
300
+
};
301
+
};
302
+
303
+
services.nginx.enable = true;
304
+
services.nginx.virtualHosts.${config.ingredient.wiki.wiki.hostname} = {
305
+
listen = [
306
+
{
307
+
addr = "127.0.0.1";
308
+
port = 1036;
309
+
}
310
+
];
311
+
312
+
locations = {
313
+
"= /" = lib.mkForce {
314
+
extraConfig = ''
315
+
return 301 https://${config.ingredient.wiki.wiki.hostname}/wiki/;
316
+
''; # overriding nixpkgs /wiki/ redirect since as our double-proxy makes it redirect to :1036
317
+
};
318
+
"= /favicon.ico".alias = ./wiki/favicon.ico;
319
+
"= /icon.svg".alias = ./wiki/icon.svg;
320
+
};
321
+
322
+
extraConfig = ''
323
+
client_max_body_size 1024M;
324
+
'';
325
+
};
326
+
services.nginx.virtualHosts."external.${config.ingredient.wiki.wiki.hostname}" =
327
+
lib.mkIf config.ingredient.wiki.wiki.enablePublicInternet
328
+
{
329
+
listenAddresses = [
330
+
"0.0.0.0"
331
+
"[::0]"
332
+
];
333
+
334
+
serverName = config.ingredient.wiki.wiki.hostname;
335
+
336
+
addSSL = true;
337
+
enableACME = true;
338
+
acmeRoot = null;
339
+
340
+
locations."/" = {
341
+
proxyPass = "http://127.0.0.1:1036";
342
+
recommendedProxySettings = true;
343
+
proxyWebsockets = true;
344
+
345
+
extraConfig = ''
346
+
proxy_set_header X-Webauth-Login "";
347
+
proxy_cache off;
348
+
'';
349
+
};
350
+
351
+
extraConfig = ''
352
+
client_max_body_size 1024M;
353
+
'';
354
+
};
355
+
services.nginx.virtualHosts."internal.${config.ingredient.wiki.wiki.hostname}" = {
356
+
listenAddresses = [ "localhost.tailscale" ];
357
+
358
+
serverName = config.ingredient.wiki.wiki.hostname;
359
+
360
+
addSSL = true;
361
+
enableACME = true;
362
+
acmeRoot = null;
363
+
364
+
locations."/" = {
365
+
proxyPass = "http://127.0.0.1:1036";
366
+
recommendedProxySettings = true;
367
+
proxyWebsockets = true;
368
+
369
+
extraConfig = ''
370
+
proxy_cache off;
371
+
'';
372
+
};
373
+
374
+
extraConfig = ''
375
+
client_max_body_size 1024M;
376
+
'';
377
+
};
378
+
379
+
services.nginx.tailscaleAuth = {
380
+
enable = true;
381
+
virtualHosts = [ "internal.${config.ingredient.wiki.wiki.hostname}" ];
382
+
};
383
+
};
384
+
}
packetmix/systems/teal/wiki/CirrusSearch.composer.lock
packetmix/systems/wiki/wiki/CirrusSearch.composer.lock
packetmix/systems/teal/wiki/CirrusSearch.composer.lock
packetmix/systems/wiki/wiki/CirrusSearch.composer.lock
packetmix/systems/teal/wiki/CirrusSearch.composer.lock.license
packetmix/systems/wiki/wiki/CirrusSearch.composer.lock.license
packetmix/systems/teal/wiki/CirrusSearch.composer.lock.license
packetmix/systems/wiki/wiki/CirrusSearch.composer.lock.license
packetmix/systems/teal/wiki/Elastica.composer.lock
packetmix/systems/wiki/wiki/Elastica.composer.lock
packetmix/systems/teal/wiki/Elastica.composer.lock
packetmix/systems/wiki/wiki/Elastica.composer.lock
packetmix/systems/teal/wiki/Elastica.composer.lock.license
packetmix/systems/wiki/wiki/Elastica.composer.lock.license
packetmix/systems/teal/wiki/Elastica.composer.lock.license
packetmix/systems/wiki/wiki/Elastica.composer.lock.license
packetmix/systems/teal/wiki/Network.composer.lock
packetmix/systems/wiki/wiki/Network.composer.lock
packetmix/systems/teal/wiki/Network.composer.lock
packetmix/systems/wiki/wiki/Network.composer.lock
packetmix/systems/teal/wiki/Network.composer.lock.license
packetmix/systems/wiki/wiki/Network.composer.lock.license
packetmix/systems/teal/wiki/Network.composer.lock.license
packetmix/systems/wiki/wiki/Network.composer.lock.license
packetmix/systems/teal/wiki/OpenIDConnect.composer.lock
packetmix/systems/wiki/wiki/OpenIDConnect.composer.lock
packetmix/systems/teal/wiki/OpenIDConnect.composer.lock
packetmix/systems/wiki/wiki/OpenIDConnect.composer.lock
packetmix/systems/teal/wiki/OpenIDConnect.composer.lock.license
packetmix/systems/wiki/wiki/OpenIDConnect.composer.lock.license
packetmix/systems/teal/wiki/OpenIDConnect.composer.lock.license
packetmix/systems/wiki/wiki/OpenIDConnect.composer.lock.license
packetmix/systems/teal/wiki/favicon.ico
packetmix/systems/wiki/wiki/favicon.ico
packetmix/systems/teal/wiki/favicon.ico
packetmix/systems/wiki/wiki/favicon.ico
packetmix/systems/teal/wiki/favicon.ico.license
packetmix/systems/wiki/wiki/favicon.ico.license
packetmix/systems/teal/wiki/favicon.ico.license
packetmix/systems/wiki/wiki/favicon.ico.license
packetmix/systems/teal/wiki/icon.svg
packetmix/systems/wiki/wiki/icon.svg
packetmix/systems/teal/wiki/icon.svg
packetmix/systems/wiki/wiki/icon.svg
packetmix/systems/teal/wiki/icon.svg.license
packetmix/systems/wiki/wiki/icon.svg.license
packetmix/systems/teal/wiki/icon.svg.license
packetmix/systems/wiki/wiki/icon.svg.license