at 22.05-pre 9.7 kB view raw
1{ lib, pkgs, config, ... }: 2 3with lib; 4 5let 6 cfg = config.services.plausible; 7 8in { 9 options.services.plausible = { 10 enable = mkEnableOption "plausible"; 11 12 releaseCookiePath = mkOption { 13 default = null; 14 type = with types; nullOr (either str path); 15 description = '' 16 The path to the file with release cookie. (used for remote connection to the running node). 17 ''; 18 }; 19 20 adminUser = { 21 name = mkOption { 22 default = "admin"; 23 type = types.str; 24 description = '' 25 Name of the admin user that plausible will created on initial startup. 26 ''; 27 }; 28 29 email = mkOption { 30 type = types.str; 31 example = "admin@localhost"; 32 description = '' 33 Email-address of the admin-user. 34 ''; 35 }; 36 37 passwordFile = mkOption { 38 type = types.either types.str types.path; 39 description = '' 40 Path to the file which contains the password of the admin user. 41 ''; 42 }; 43 44 activate = mkEnableOption "activating the freshly created admin-user"; 45 }; 46 47 database = { 48 clickhouse = { 49 setup = mkEnableOption "creating a clickhouse instance" // { default = true; }; 50 url = mkOption { 51 default = "http://localhost:8123/default"; 52 type = types.str; 53 description = '' 54 The URL to be used to connect to <package>clickhouse</package>. 55 ''; 56 }; 57 }; 58 postgres = { 59 setup = mkEnableOption "creating a postgresql instance" // { default = true; }; 60 dbname = mkOption { 61 default = "plausible"; 62 type = types.str; 63 description = '' 64 Name of the database to use. 65 ''; 66 }; 67 socket = mkOption { 68 default = "/run/postgresql"; 69 type = types.str; 70 description = '' 71 Path to the UNIX domain-socket to communicate with <package>postgres</package>. 72 ''; 73 }; 74 }; 75 }; 76 77 server = { 78 disableRegistration = mkOption { 79 default = true; 80 type = types.bool; 81 description = '' 82 Whether to prohibit creating an account in plausible's UI. 83 ''; 84 }; 85 secretKeybaseFile = mkOption { 86 type = types.either types.path types.str; 87 description = '' 88 Path to the secret used by the <literal>phoenix</literal>-framework. Instructions 89 how to generate one are documented in the 90 <link xlink:href="https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Secret.html#content"> 91 framework docs</link>. 92 ''; 93 }; 94 port = mkOption { 95 default = 8000; 96 type = types.port; 97 description = '' 98 Port where the service should be available. 99 ''; 100 }; 101 baseUrl = mkOption { 102 type = types.str; 103 description = '' 104 Public URL where plausible is available. 105 106 Note that <literal>/path</literal> components are currently ignored: 107 <link xlink:href="https://github.com/plausible/analytics/issues/1182"> 108 https://github.com/plausible/analytics/issues/1182 109 </link>. 110 ''; 111 }; 112 }; 113 114 mail = { 115 email = mkOption { 116 default = "hello@plausible.local"; 117 type = types.str; 118 description = '' 119 The email id to use for as <emphasis>from</emphasis> address of all communications 120 from Plausible. 121 ''; 122 }; 123 smtp = { 124 hostAddr = mkOption { 125 default = "localhost"; 126 type = types.str; 127 description = '' 128 The host address of your smtp server. 129 ''; 130 }; 131 hostPort = mkOption { 132 default = 25; 133 type = types.port; 134 description = '' 135 The port of your smtp server. 136 ''; 137 }; 138 user = mkOption { 139 default = null; 140 type = types.nullOr types.str; 141 description = '' 142 The username/email in case SMTP auth is enabled. 143 ''; 144 }; 145 passwordFile = mkOption { 146 default = null; 147 type = with types; nullOr (either str path); 148 description = '' 149 The path to the file with the password in case SMTP auth is enabled. 150 ''; 151 }; 152 enableSSL = mkEnableOption "SSL when connecting to the SMTP server"; 153 retries = mkOption { 154 type = types.ints.unsigned; 155 default = 2; 156 description = '' 157 Number of retries to make until mailer gives up. 158 ''; 159 }; 160 }; 161 }; 162 }; 163 164 config = mkIf cfg.enable { 165 assertions = [ 166 { assertion = cfg.adminUser.activate -> cfg.database.postgres.setup; 167 message = '' 168 Unable to automatically activate the admin-user if no locally managed DB for 169 postgres (`services.plausible.database.postgres.setup') is enabled! 170 ''; 171 } 172 ]; 173 174 services.postgresql = mkIf cfg.database.postgres.setup { 175 enable = true; 176 }; 177 178 services.clickhouse = mkIf cfg.database.clickhouse.setup { 179 enable = true; 180 }; 181 182 services.epmd.enable = true; 183 184 environment.systemPackages = [ pkgs.plausible ]; 185 186 systemd.services = mkMerge [ 187 { 188 plausible = { 189 inherit (pkgs.plausible.meta) description; 190 documentation = [ "https://plausible.io/docs/self-hosting" ]; 191 wantedBy = [ "multi-user.target" ]; 192 after = optionals cfg.database.postgres.setup [ "postgresql.service" "plausible-postgres.service" ]; 193 requires = optional cfg.database.clickhouse.setup "clickhouse.service" 194 ++ optionals cfg.database.postgres.setup [ 195 "postgresql.service" 196 "plausible-postgres.service" 197 ]; 198 199 environment = { 200 # NixOS specific option to avoid that it's trying to write into its store-path. 201 # See also https://github.com/lau/tzdata#data-directory-and-releases 202 STORAGE_DIR = "/var/lib/plausible/elixir_tzdata"; 203 204 # Configuration options from 205 # https://plausible.io/docs/self-hosting-configuration 206 PORT = toString cfg.server.port; 207 DISABLE_REGISTRATION = boolToString cfg.server.disableRegistration; 208 209 RELEASE_TMP = "/var/lib/plausible/tmp"; 210 # Home is needed to connect to the node with iex 211 HOME = "/var/lib/plausible"; 212 213 ADMIN_USER_NAME = cfg.adminUser.name; 214 ADMIN_USER_EMAIL = cfg.adminUser.email; 215 216 DATABASE_SOCKET_DIR = cfg.database.postgres.socket; 217 DATABASE_NAME = cfg.database.postgres.dbname; 218 CLICKHOUSE_DATABASE_URL = cfg.database.clickhouse.url; 219 220 BASE_URL = cfg.server.baseUrl; 221 222 MAILER_EMAIL = cfg.mail.email; 223 SMTP_HOST_ADDR = cfg.mail.smtp.hostAddr; 224 SMTP_HOST_PORT = toString cfg.mail.smtp.hostPort; 225 SMTP_RETRIES = toString cfg.mail.smtp.retries; 226 SMTP_HOST_SSL_ENABLED = boolToString cfg.mail.smtp.enableSSL; 227 228 SELFHOST = "true"; 229 } // (optionalAttrs (cfg.mail.smtp.user != null) { 230 SMTP_USER_NAME = cfg.mail.smtp.user; 231 }); 232 233 path = [ pkgs.plausible ] 234 ++ optional cfg.database.postgres.setup config.services.postgresql.package; 235 script = '' 236 export CONFIG_DIR=$CREDENTIALS_DIRECTORY 237 238 # setup 239 ${pkgs.plausible}/createdb.sh 240 ${pkgs.plausible}/migrate.sh 241 ${optionalString cfg.adminUser.activate '' 242 if ! ${pkgs.plausible}/init-admin.sh | grep 'already exists'; then 243 psql -d plausible <<< "UPDATE users SET email_verified=true;" 244 fi 245 ''} 246 ${optionalString (cfg.releaseCookiePath != null) '' 247 export RELEASE_COOKIE="$(< $CREDENTIALS_DIRECTORY/RELEASE_COOKIE )" 248 ''} 249 plausible start 250 ''; 251 252 serviceConfig = { 253 DynamicUser = true; 254 PrivateTmp = true; 255 WorkingDirectory = "/var/lib/plausible"; 256 StateDirectory = "plausible"; 257 LoadCredential = [ 258 "ADMIN_USER_PWD:${cfg.adminUser.passwordFile}" 259 "SECRET_KEY_BASE:${cfg.server.secretKeybaseFile}" 260 ] ++ lib.optionals (cfg.mail.smtp.passwordFile != null) [ "SMTP_USER_PWD:${cfg.mail.smtp.passwordFile}"] 261 ++ lib.optionals (cfg.releaseCookiePath != null) [ "RELEASE_COOKIE:${cfg.releaseCookiePath}"]; 262 }; 263 }; 264 } 265 (mkIf cfg.database.postgres.setup { 266 # `plausible' requires the `citext'-extension. 267 plausible-postgres = { 268 after = [ "postgresql.service" ]; 269 partOf = [ "plausible.service" ]; 270 serviceConfig = { 271 Type = "oneshot"; 272 User = config.services.postgresql.superUser; 273 RemainAfterExit = true; 274 }; 275 script = with cfg.database.postgres; '' 276 PSQL() { 277 ${config.services.postgresql.package}/bin/psql --port=5432 "$@" 278 } 279 # check if the database already exists 280 if ! PSQL -lqt | ${pkgs.coreutils}/bin/cut -d \| -f 1 | ${pkgs.gnugrep}/bin/grep -qw ${dbname} ; then 281 PSQL -tAc "CREATE ROLE plausible WITH LOGIN;" 282 PSQL -tAc "CREATE DATABASE ${dbname} WITH OWNER plausible;" 283 PSQL -d ${dbname} -tAc "CREATE EXTENSION IF NOT EXISTS citext;" 284 fi 285 ''; 286 }; 287 }) 288 ]; 289 }; 290 291 meta.maintainers = with maintainers; [ ma27 ]; 292 meta.doc = ./plausible.xml; 293}