1{
2 config,
3 options,
4 lib,
5 pkgs,
6 ...
7}:
8
9let
10 cfg = config.services.nextcloud.notify_push;
11 cfgN = config.services.nextcloud;
12in
13{
14 options.services.nextcloud.notify_push = {
15 enable = lib.mkEnableOption "Notify push";
16
17 package = lib.mkPackageOption pkgs "nextcloud-notify_push" { };
18
19 socketPath = lib.mkOption {
20 type = lib.types.str;
21 default = "/run/nextcloud-notify_push/sock";
22 description = "Socket path to use for notify_push";
23 };
24
25 logLevel = lib.mkOption {
26 type = lib.types.enum [
27 "error"
28 "warn"
29 "info"
30 "debug"
31 "trace"
32 ];
33 default = "error";
34 description = "Log level";
35 };
36
37 nextcloudUrl = lib.mkOption {
38 type = lib.types.str;
39 default = "http${lib.optionalString cfgN.https "s"}://${cfgN.hostName}";
40 defaultText = lib.literalExpression ''"http''${lib.optionalString config.services.nextcloud.https "s"}://''${config.services.nextcloud.hostName}"'';
41 description = "Configure the nextcloud URL notify_push tries to connect to.";
42 };
43
44 bendDomainToLocalhost = lib.mkOption {
45 type = lib.types.bool;
46 default = false;
47 description = ''
48 Whether to add an entry to `/etc/hosts` for the configured nextcloud domain to point to `localhost` and add `localhost `to nextcloud's `trusted_proxies` config option.
49
50 This is useful when nextcloud's domain is not a static IP address and when the reverse proxy cannot be bypassed because the backend connection is done via unix socket.
51 '';
52 };
53 }
54 // (lib.genAttrs
55 [
56 "dbtype"
57 "dbname"
58 "dbuser"
59 "dbpassFile"
60 "dbhost"
61 "dbport"
62 "dbtableprefix"
63 ]
64 (
65 opt:
66 options.services.nextcloud.config.${opt}
67 // {
68 default = config.services.nextcloud.config.${opt};
69 defaultText = lib.literalExpression "config.services.nextcloud.config.${opt}";
70 }
71 )
72 );
73
74 config = lib.mkIf cfg.enable {
75 systemd.services = {
76 nextcloud-notify_push = {
77 description = "Push daemon for Nextcloud clients";
78 documentation = [ "https://github.com/nextcloud/notify_push" ];
79 after = [
80 "nextcloud-setup.service"
81 "phpfpm-nextcloud.service"
82 "redis-nextcloud.service"
83 ];
84 requires = [
85 "nextcloud-setup.service"
86 "phpfpm-nextcloud.service"
87 ];
88 wantedBy = [ "multi-user.target" ];
89 environment = {
90 NEXTCLOUD_URL = cfg.nextcloudUrl;
91 SOCKET_PATH = cfg.socketPath;
92 DATABASE_PREFIX = cfg.dbtableprefix;
93 LOG = cfg.logLevel;
94 };
95 script =
96 let
97 dbType = if cfg.dbtype == "pgsql" then "postgresql" else cfg.dbtype;
98 dbUser = lib.optionalString (cfg.dbuser != null) cfg.dbuser;
99 dbPass = lib.optionalString (cfg.dbpassFile != null) ":$DATABASE_PASSWORD";
100 dbHostHasPrefix = prefix: lib.hasPrefix prefix (toString cfg.dbhost);
101 isPostgresql = dbType == "postgresql";
102 isMysql = dbType == "mysql";
103 isSocket = (isPostgresql && dbHostHasPrefix "/") || (isMysql && dbHostHasPrefix "localhost:/");
104 dbHost = lib.optionalString (cfg.dbhost != null) (
105 if isSocket then lib.optionalString isMysql "@localhost" else "@${cfg.dbhost}"
106 );
107 dbOpts = lib.optionalString (cfg.dbhost != null && isSocket) (
108 if isPostgresql then
109 "?host=${cfg.dbhost}"
110 else if isMysql then
111 "?socket=${lib.removePrefix "localhost:" cfg.dbhost}"
112 else
113 throw "unsupported dbtype"
114 );
115 dbName = lib.optionalString (cfg.dbname != null) "/${cfg.dbname}";
116 dbUrl = "${dbType}://${dbUser}${dbPass}${dbHost}${dbName}${dbOpts}";
117 in
118 lib.optionalString (cfg.dbpassFile != null) ''
119 export DATABASE_PASSWORD="$(<"$CREDENTIALS_DIRECTORY/dbpass")"
120 ''
121 + ''
122 export DATABASE_URL="${dbUrl}"
123 exec ${cfg.package}/bin/notify_push '${cfgN.datadir}/config/config.php'
124 '';
125 serviceConfig = {
126 User = "nextcloud";
127 Group = "nextcloud";
128 RuntimeDirectory = [ "nextcloud-notify_push" ];
129 Restart = "on-failure";
130 RestartSec = "5s";
131 Type = "notify";
132 LoadCredential = lib.optional (cfg.dbpassFile != null) "dbpass:${cfg.dbpassFile}";
133 };
134 };
135
136 nextcloud-notify_push_setup = {
137 wantedBy = [ "multi-user.target" ];
138 requiredBy = [ "nextcloud-notify_push.service" ];
139 after = [ "nextcloud-notify_push.service" ];
140 serviceConfig = {
141 Type = "oneshot";
142 User = "nextcloud";
143 Group = "nextcloud";
144 ExecStart = "${lib.getExe cfgN.occ} notify_push:setup ${cfg.nextcloudUrl}/push";
145 LoadCredential = config.systemd.services.nextcloud-cron.serviceConfig.LoadCredential;
146 RestartMode = "direct";
147 Restart = "on-failure";
148 RestartSec = "5s";
149 };
150 unitConfig = {
151 StartLimitIntervalSec = 30;
152 StartLimitBurst = 5;
153 };
154 };
155 };
156
157 networking.hosts = lib.mkIf cfg.bendDomainToLocalhost {
158 "127.0.0.1" = [ cfgN.hostName ];
159 "::1" = [ cfgN.hostName ];
160 };
161
162 services = lib.mkMerge [
163 {
164 nginx.virtualHosts.${cfgN.hostName}.locations."^~ /push/" = {
165 proxyPass = "http://unix:${cfg.socketPath}";
166 proxyWebsockets = true;
167 recommendedProxySettings = lib.mkDefault true;
168 extraConfig = # nginx
169 ''
170 # disable in case it was configured on a higher level
171 keepalive_timeout 0;
172 proxy_buffering off;
173 '';
174 };
175 }
176
177 (lib.mkIf cfg.bendDomainToLocalhost {
178 nextcloud.settings.trusted_proxies = [
179 "127.0.0.1"
180 "::1"
181 ];
182 })
183 ];
184 };
185}