1{
2 lib,
3 pkgs,
4 config,
5 ...
6}:
7
8with lib;
9
10let
11 cfg = config.services.wiki-js;
12
13 format = pkgs.formats.json { };
14
15 configFile = format.generate "wiki-js.yml" cfg.settings;
16in
17{
18 options.services.wiki-js = {
19 enable = mkEnableOption "wiki-js";
20
21 environmentFile = mkOption {
22 type = types.nullOr types.path;
23 default = null;
24 example = "/root/wiki-js.env";
25 description = ''
26 Environment file to inject e.g. secrets into the configuration.
27 '';
28 };
29
30 stateDirectoryName = mkOption {
31 default = "wiki-js";
32 type = types.str;
33 description = ''
34 Name of the directory in {file}`/var/lib`.
35 '';
36 };
37
38 settings = mkOption {
39 default = { };
40 type = types.submodule {
41 freeformType = format.type;
42 options = {
43 port = mkOption {
44 type = types.port;
45 default = 3000;
46 description = ''
47 TCP port the process should listen to.
48 '';
49 };
50
51 bindIP = mkOption {
52 default = "0.0.0.0";
53 type = types.str;
54 description = ''
55 IPs the service should listen to.
56 '';
57 };
58
59 db = {
60 type = mkOption {
61 default = "postgres";
62 type = types.enum [
63 "postgres"
64 "mysql"
65 "mariadb"
66 "mssql"
67 ];
68 description = ''
69 Database driver to use for persistence. Please note that `sqlite`
70 is currently not supported as the build process for it is currently not implemented
71 in `pkgs.wiki-js` and it's not recommended by upstream for
72 production use.
73 '';
74 };
75 host = mkOption {
76 type = types.str;
77 example = "/run/postgresql";
78 description = ''
79 Hostname or socket-path to connect to.
80 '';
81 };
82 db = mkOption {
83 default = "wiki";
84 type = types.str;
85 description = ''
86 Name of the database to use.
87 '';
88 };
89 };
90
91 logLevel = mkOption {
92 default = "info";
93 type = types.enum [
94 "error"
95 "warn"
96 "info"
97 "verbose"
98 "debug"
99 "silly"
100 ];
101 description = ''
102 Define how much detail is supposed to be logged at runtime.
103 '';
104 };
105
106 offline = mkEnableOption "offline mode" // {
107 description = ''
108 Disable latest file updates and enable
109 [sideloading](https://docs.requarks.io/install/sideload).
110 '';
111 };
112 };
113 };
114 description = ''
115 Settings to configure `wiki-js`. This directly
116 corresponds to [the upstream configuration options](https://docs.requarks.io/install/config).
117
118 Secrets can be injected via the environment by
119 - specifying [](#opt-services.wiki-js.environmentFile)
120 to contain secrets
121 - and setting sensitive values to `$(ENVIRONMENT_VAR)`
122 with this value defined in the environment-file.
123 '';
124 };
125 };
126
127 config = mkIf cfg.enable {
128 services.wiki-js.settings.dataPath = "/var/lib/${cfg.stateDirectoryName}";
129 systemd.services.wiki-js = {
130 description = "A modern and powerful wiki app built on Node.js";
131 documentation = [ "https://docs.requarks.io/" ];
132 wantedBy = [ "multi-user.target" ];
133
134 path = with pkgs; [
135 # Needed for git storage.
136 git
137 # Needed for git+ssh storage.
138 openssh
139 ];
140
141 preStart = ''
142 ln -sf ${configFile} /var/lib/${cfg.stateDirectoryName}/config.yml
143 ln -sf ${pkgs.wiki-js}/server /var/lib/${cfg.stateDirectoryName}
144 ln -sf ${pkgs.wiki-js}/assets /var/lib/${cfg.stateDirectoryName}
145 ln -sf ${pkgs.wiki-js}/package.json /var/lib/${cfg.stateDirectoryName}/package.json
146 '';
147
148 serviceConfig = {
149 EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
150 StateDirectory = cfg.stateDirectoryName;
151 WorkingDirectory = "/var/lib/${cfg.stateDirectoryName}";
152 DynamicUser = true;
153 PrivateTmp = true;
154 ExecStart = "${pkgs.nodejs_20}/bin/node ${pkgs.wiki-js}/server";
155 };
156 };
157 };
158
159 meta.maintainers = with maintainers; [ ma27 ];
160}