1{
2 pkgs,
3 lib,
4 config,
5 ...
6}:
7
8with lib;
9
10let
11 cfg = config.services.flarum;
12
13 flarumInstallConfig = pkgs.writeText "config.json" (
14 builtins.toJSON {
15 debug = false;
16 offline = false;
17
18 baseUrl = cfg.baseUrl;
19 databaseConfiguration = cfg.database;
20 adminUser = {
21 username = cfg.adminUser;
22 password = cfg.initialAdminPassword;
23 email = cfg.adminEmail;
24 };
25 settings = {
26 forum_title = cfg.forumTitle;
27 };
28 }
29 );
30in
31{
32 options.services.flarum = {
33 enable = mkEnableOption "Flarum discussion platform";
34
35 package = mkPackageOption pkgs "flarum" { };
36
37 forumTitle = mkOption {
38 type = types.str;
39 default = "A Flarum Forum on NixOS";
40 description = "Title of the forum.";
41 };
42
43 domain = mkOption {
44 type = types.str;
45 default = "localhost";
46 example = "forum.example.com";
47 description = "Domain to serve on.";
48 };
49
50 baseUrl = mkOption {
51 type = types.str;
52 default = "http://localhost";
53 example = "https://forum.example.com";
54 description = "Change `domain` instead.";
55 };
56
57 adminUser = mkOption {
58 type = types.str;
59 default = "flarum";
60 description = "Username for first web application administrator";
61 };
62
63 adminEmail = mkOption {
64 type = types.str;
65 default = "admin@example.com";
66 description = "Email for first web application administrator";
67 };
68
69 initialAdminPassword = mkOption {
70 type = types.str;
71 default = "flarum";
72 description = "Initial password for the adminUser";
73 };
74
75 user = mkOption {
76 type = types.str;
77 default = "flarum";
78 description = "System user to run Flarum";
79 };
80
81 group = mkOption {
82 type = types.str;
83 default = "flarum";
84 description = "System group to run Flarum";
85 };
86
87 stateDir = mkOption {
88 type = types.path;
89 default = "/var/lib/flarum";
90 description = "Home directory for writable storage";
91 };
92
93 database = mkOption rec {
94 type =
95 with types;
96 attrsOf (oneOf [
97 str
98 bool
99 int
100 ]);
101 description = "MySQL database parameters";
102 default = {
103 # the database driver; i.e. MySQL; MariaDB...
104 driver = "mysql";
105 # the host of the connection; localhost in most cases unless using an external service
106 host = "localhost";
107 # the name of the database in the instance
108 database = "flarum";
109 # database username
110 username = "flarum";
111 # database password
112 password = "";
113 # the prefix for the tables; useful if you are sharing the same database with another service
114 prefix = "";
115 # the port of the connection; defaults to 3306 with MySQL
116 port = 3306;
117 strict = false;
118 };
119 };
120
121 createDatabaseLocally = mkOption {
122 type = types.bool;
123 default = false;
124 description = ''
125 Create the database and database user locally, and run installation.
126
127 WARNING: Due to <https://github.com/flarum/framework/issues/4018>, this option is set
128 to false by default. The 'flarum install' command may delete existing database tables.
129 Only set this to true if you are certain you are working with a fresh, empty database.
130 '';
131 };
132 };
133
134 config = mkIf cfg.enable {
135 users.users.${cfg.user} = {
136 isSystemUser = true;
137 home = cfg.stateDir;
138 createHome = true;
139 homeMode = "755";
140 group = cfg.group;
141 };
142 users.groups.${cfg.group} = { };
143
144 services.phpfpm.pools.flarum = {
145 user = cfg.user;
146 settings = {
147 "listen.owner" = config.services.nginx.user;
148 "listen.group" = config.services.nginx.group;
149 "listen.mode" = "0600";
150 "pm" = mkDefault "dynamic";
151 "pm.max_children" = mkDefault 10;
152 "pm.max_requests" = mkDefault 500;
153 "pm.start_servers" = mkDefault 2;
154 "pm.min_spare_servers" = mkDefault 1;
155 "pm.max_spare_servers" = mkDefault 3;
156 };
157 phpOptions = ''
158 error_log = syslog
159 log_errors = on
160 '';
161 };
162
163 services.nginx = {
164 enable = true;
165 virtualHosts."${cfg.domain}" = {
166 root = "${cfg.stateDir}/public";
167 locations."~ \\.php$".extraConfig = ''
168 fastcgi_pass unix:${config.services.phpfpm.pools.flarum.socket};
169 fastcgi_index site.php;
170 '';
171 extraConfig = ''
172 index index.php;
173 include ${cfg.package}/share/php/flarum/.nginx.conf;
174 '';
175 };
176 };
177
178 services.mysql = mkIf cfg.enable {
179 enable = true;
180 package = pkgs.mariadb;
181 ensureDatabases = [ cfg.database.database ];
182 ensureUsers = [
183 {
184 name = cfg.database.username;
185 ensurePermissions = {
186 "${cfg.database.database}.*" = "ALL PRIVILEGES";
187 };
188 }
189 ];
190 };
191
192 assertions = [
193 {
194 assertion = !cfg.createDatabaseLocally || cfg.database.driver == "mysql";
195 message = "Flarum can only be automatically installed in MySQL/MariaDB.";
196 }
197 ];
198
199 systemd.services."phpfpm-flarum" = {
200 restartTriggers = [ cfg.package ];
201 };
202
203 systemd.services.flarum-install = {
204 description = "Flarum installation";
205 requiredBy = [ "phpfpm-flarum.service" ];
206 before = [ "phpfpm-flarum.service" ];
207 requires = [ "mysql.service" ];
208 after = [ "mysql.service" ];
209 serviceConfig = {
210 Type = "oneshot";
211 User = cfg.user;
212 Group = cfg.group;
213 };
214 path = [ config.services.phpfpm.phpPackage ];
215 script = ''
216 mkdir -p ${cfg.stateDir}/{extensions,public/assets/avatars}
217 mkdir -p ${cfg.stateDir}/storage/{cache,formatter,sessions,views}
218 cd ${cfg.stateDir}
219 cp -f ${cfg.package}/share/php/flarum/{extend.php,site.php,flarum} .
220 ln -sf ${cfg.package}/share/php/flarum/vendor .
221 ln -sf ${cfg.package}/share/php/flarum/public/index.php public/
222 ''
223 + optionalString (cfg.createDatabaseLocally && cfg.database.driver == "mysql") ''
224 if [ ! -f config.php ]; then
225 php flarum install --file=${flarumInstallConfig}
226 fi
227 ''
228 + ''
229 if [ -f config.php ]; then
230 php flarum migrate
231 php flarum cache:clear
232 fi
233 '';
234 };
235 };
236
237 meta.maintainers = with lib.maintainers; [
238 fsagbuya
239 jasonodoom
240 ];
241}