{ config, self, lib, self', pkgs, ... }: let d = self.lib.data.services.planka; in { systemd = { tmpfiles.settings."10-planka" = { "/var/lib/planka/private/attachments".d = { group = "planka"; mode = "774"; user = "planka"; }; "/var/lib/planka/protected/background-images".d = { group = "planka"; mode = "774"; user = "planka"; }; "/var/lib/planka/protected/favicons".d = { group = "planka"; mode = "774"; user = "planka"; }; "/var/lib/planka/protected/user-avatars".d = { group = "planka"; mode = "774"; user = "planka"; }; "/var/lib/planka/public/preloaded-favicons".d = { group = "planka"; mode = "774"; user = "planka"; }; }; services = { planka-server = { description = "Planka Server"; wantedBy = [ "multi-user.target" ]; after = [ "postgresql.target" ]; path = [ pkgs.nodejs-slim ]; environment = { BASE_URL = "https://${d.extUrl}"; DEFAULT_ADMIN_EMAIL = "pyrox@pyrox.dev"; DEFAULT_ADMIN_USERNAME = "pyrox"; TRUST_PROXY = "true"; DEFAULT_LANGUAGE = "en-US"; DATABASE_URL = "postgresql://planka@localhost/planka"; LOG_FILE = "/tmp/planka.log"; NODE_ENV = "production"; sails_port = toString d.port; sails_http__trustProxy = "true"; sails_session__cookie__secure = "true"; sails_custom__uploadsBasePath = "/var/lib/planka"; sails_custom__uploadsTempPath = "/tmp/uploads"; sails_custom__attachmentsPathSegment = "attachments"; sails_custom__backgroundImagesPathSegment = "background-images"; sails_custom__faviconsPathSegment = "favicons"; sails_custom__preloadedFaviconsPathSegment = "preloaded-favicons"; sails_custom__userAvatarsPathSegment = "user-avatars"; }; serviceConfig = { User = "planka"; Group = "planka"; StateDirectory = "planka"; ExecStart = "${lib.getExe self'.packages.planka} --port ${toString d.port}"; WorkingDirectory = "/var/lib/planka"; EnvironmentFile = [ config.age.secrets.planka-env.path ]; # Hardening ProtectProc = "invisible"; NoNewPrivileges = true; ProtectSystem = true; ProtectHome = true; PrivateTmp = true; PrivateDevices = true; ProtectHostname = true; ProtectClock = true; ProtectKernelTunables = true; ProtectKernelModules = true; ProtectKernelLogs = true; ProtectControlGroups = true; RestrictSUIDSGID = true; }; }; }; }; services.postgresql = { ensureUsers = [ { name = "planka"; ensureDBOwnership = true; } ]; ensureDatabases = [ "planka" ]; # https://www.postgresql.org/docs/current/auth-pg-hba-conf.html # method database user address method # Should only allow connections from planka user to planka table without password authentication = lib.mkBefore '' host planka planka 127.0.0.1/32 trust host planka planka ::1/128 trust ''; }; users = { users.planka = { isSystemUser = true; group = "planka"; }; groups.planka = { }; }; age.secrets.planka-env = { file = ./secrets/planka-env.age; owner = "planka"; group = "planka"; }; services.anubis.instances.planka = { settings = { COOKIE_DOMAIN = ".cs2a.club"; BIND = ":${toString d.anubis}"; TARGET = "http://localhost:${toString d.port}"; }; }; }