159e378cbb
GitOrigin-RevId: c04d5652cfa9742b1d519688f65d1bbccea9eb7e
287 lines
8.6 KiB
Nix
287 lines
8.6 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.services.gancio;
|
|
settingsFormat = pkgs.formats.json { };
|
|
inherit (lib)
|
|
mkEnableOption
|
|
mkPackageOption
|
|
mkOption
|
|
types
|
|
literalExpression
|
|
mkIf
|
|
optional
|
|
mapAttrsToList
|
|
concatStringsSep
|
|
concatMapStringsSep
|
|
getExe
|
|
mkMerge
|
|
mkDefault
|
|
;
|
|
in
|
|
{
|
|
options.services.gancio = {
|
|
enable = mkEnableOption "Gancio, a shared agenda for local communities";
|
|
|
|
package = mkPackageOption pkgs "gancio" { };
|
|
|
|
plugins = mkOption {
|
|
type = with types; listOf package;
|
|
default = [ ];
|
|
example = literalExpression "[ pkgs.gancioPlugins.telegram-bridge ]";
|
|
description = ''
|
|
Paths of gancio plugins to activate (linked under $WorkingDirectory/plugins/).
|
|
'';
|
|
};
|
|
|
|
user = mkOption {
|
|
type = types.str;
|
|
description = "The user (and PostgreSQL database name) used to run the gancio server";
|
|
default = "gancio";
|
|
};
|
|
|
|
settings = mkOption rec {
|
|
type = types.submodule {
|
|
freeformType = settingsFormat.type;
|
|
options = {
|
|
hostname = mkOption {
|
|
type = types.str;
|
|
description = "The domain name under which the server is reachable.";
|
|
};
|
|
baseurl = mkOption {
|
|
type = types.str;
|
|
default = "http${
|
|
lib.optionalString config.services.nginx.virtualHosts."${cfg.settings.hostname}".enableACME "s"
|
|
}://${cfg.settings.hostname}";
|
|
defaultText = lib.literalExpression ''"https://''${cfg.settings.hostname}"'';
|
|
example = "https://demo.gancio.org/gancio";
|
|
description = "The full URL under which the server is reachable.";
|
|
};
|
|
server = {
|
|
socket = mkOption {
|
|
type = types.path;
|
|
readOnly = true;
|
|
default = "/run/gancio/socket";
|
|
description = ''
|
|
The unix socket for the gancio server to listen on.
|
|
'';
|
|
};
|
|
};
|
|
db = {
|
|
dialect = mkOption {
|
|
type = types.enum [
|
|
"sqlite"
|
|
"postgres"
|
|
];
|
|
default = "sqlite";
|
|
description = ''
|
|
The database dialect to use
|
|
'';
|
|
};
|
|
storage = mkOption {
|
|
description = ''
|
|
Location for the SQLite database.
|
|
'';
|
|
readOnly = true;
|
|
type = types.nullOr types.str;
|
|
default = if cfg.settings.db.dialect == "sqlite" then "/var/lib/gancio/db.sqlite" else null;
|
|
defaultText = ''
|
|
if cfg.settings.db.dialect == "sqlite" then "/var/lib/gancio/db.sqlite" else null
|
|
'';
|
|
};
|
|
host = mkOption {
|
|
description = ''
|
|
Connection string for the PostgreSQL database
|
|
'';
|
|
readOnly = true;
|
|
type = types.nullOr types.str;
|
|
default = if cfg.settings.db.dialect == "postgres" then "/run/postgresql" else null;
|
|
defaultText = ''
|
|
if cfg.settings.db.dialect == "postgres" then "/run/postgresql" else null
|
|
'';
|
|
};
|
|
database = mkOption {
|
|
description = ''
|
|
Name of the PostgreSQL database
|
|
'';
|
|
readOnly = true;
|
|
type = types.nullOr types.str;
|
|
default = if cfg.settings.db.dialect == "postgres" then cfg.user else null;
|
|
defaultText = ''
|
|
if cfg.settings.db.dialect == "postgres" then cfg.user else null
|
|
'';
|
|
};
|
|
};
|
|
log_level = mkOption {
|
|
description = "Gancio log level.";
|
|
type = types.enum [
|
|
"debug"
|
|
"info"
|
|
"warning"
|
|
"error"
|
|
];
|
|
default = "info";
|
|
};
|
|
# FIXME upstream proper journald logging
|
|
log_path = mkOption {
|
|
description = "Directory Gancio logs into";
|
|
readOnly = true;
|
|
type = types.str;
|
|
default = "/var/log/gancio";
|
|
};
|
|
};
|
|
};
|
|
description = ''
|
|
Configuration for Gancio, see <https://gancio.org/install/config> for supported values.
|
|
'';
|
|
};
|
|
|
|
userLocale = mkOption {
|
|
type = with types; attrsOf (attrsOf (attrsOf str));
|
|
default = { };
|
|
example = {
|
|
en.register.description = "My new registration page description";
|
|
};
|
|
description = ''
|
|
Override default locales within gancio.
|
|
See [https://framagit.org/les/gancio/tree/master/locales](default languages and locales).
|
|
'';
|
|
};
|
|
|
|
nginx = mkOption {
|
|
type = types.submodule (
|
|
lib.recursiveUpdate (import ../web-servers/nginx/vhost-options.nix { inherit config lib; }) {
|
|
# enable encryption by default,
|
|
# as sensitive login credentials should not be transmitted in clear text.
|
|
options.forceSSL.default = true;
|
|
options.enableACME.default = true;
|
|
}
|
|
);
|
|
default = { };
|
|
example = {
|
|
enableACME = false;
|
|
forceSSL = false;
|
|
};
|
|
description = "Extra configuration for the nginx virtual host of gancio.";
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
environment.systemPackages = [ cfg.package ];
|
|
|
|
users.users.gancio = lib.mkIf (cfg.user == "gancio") {
|
|
isSystemUser = true;
|
|
group = cfg.user;
|
|
home = "/var/lib/gancio";
|
|
};
|
|
users.groups.gancio = lib.mkIf (cfg.user == "gancio") { };
|
|
|
|
systemd.tmpfiles.settings."10-gancio" =
|
|
let
|
|
rules = {
|
|
mode = "0755";
|
|
user = cfg.user;
|
|
group = config.users.users.${cfg.user}.group;
|
|
};
|
|
in
|
|
{
|
|
"/var/lib/gancio/user_locale".d = rules;
|
|
"/var/lib/gancio/plugins".d = rules;
|
|
};
|
|
|
|
systemd.services.gancio =
|
|
let
|
|
configFile = settingsFormat.generate "gancio-config.json" cfg.settings;
|
|
in
|
|
{
|
|
description = "Gancio server";
|
|
documentation = [ "https://gancio.org/" ];
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [
|
|
"network.target"
|
|
] ++ optional (cfg.settings.db.dialect == "postgres") "postgresql.service";
|
|
|
|
environment = {
|
|
NODE_ENV = "production";
|
|
};
|
|
|
|
preStart = ''
|
|
# We need this so the gancio executable run by the user finds the right settings.
|
|
ln -sf ${configFile} config.json
|
|
|
|
rm -f user_locale/*
|
|
${concatStringsSep "\n" (
|
|
mapAttrsToList (
|
|
l: c: "ln -sf ${settingsFormat.generate "gancio-${l}-locale.json" c} user_locale/${l}.json"
|
|
) cfg.userLocale
|
|
)}
|
|
|
|
rm -f plugins/*
|
|
${concatMapStringsSep "\n" (p: "ln -sf ${p} plugins/") cfg.plugins}
|
|
'';
|
|
|
|
serviceConfig = {
|
|
ExecStart = "${getExe cfg.package} start ${configFile}";
|
|
# set umask so that nginx can write to the server socket
|
|
# FIXME: upstream socket permission configuration in Nuxt
|
|
UMask = "0002";
|
|
RuntimeDirectory = "gancio";
|
|
StateDirectory = "gancio";
|
|
WorkingDirectory = "/var/lib/gancio";
|
|
LogsDirectory = "gancio";
|
|
User = cfg.user;
|
|
# hardening
|
|
RestrictRealtime = true;
|
|
RestrictNamespaces = true;
|
|
LockPersonality = true;
|
|
ProtectKernelModules = true;
|
|
ProtectKernelTunables = true;
|
|
ProtectKernelLogs = true;
|
|
ProtectControlGroups = true;
|
|
ProtectClock = true;
|
|
RestrictSUIDSGID = true;
|
|
SystemCallArchitectures = "native";
|
|
CapabilityBoundingSet = "";
|
|
ProtectProc = "invisible";
|
|
};
|
|
};
|
|
|
|
services.postgresql = mkIf (cfg.settings.db.dialect == "postgres") {
|
|
enable = true;
|
|
ensureDatabases = [ cfg.user ];
|
|
ensureUsers = [
|
|
{
|
|
name = cfg.user;
|
|
ensureDBOwnership = true;
|
|
}
|
|
];
|
|
};
|
|
|
|
services.nginx = {
|
|
enable = true;
|
|
virtualHosts."${cfg.settings.hostname}" = mkMerge [
|
|
cfg.nginx
|
|
{
|
|
locations = {
|
|
"/" = {
|
|
index = "index.html";
|
|
tryFiles = "$uri $uri @proxy";
|
|
};
|
|
"@proxy" = {
|
|
proxyWebsockets = true;
|
|
proxyPass = "http://unix:${cfg.settings.server.socket}";
|
|
recommendedProxySettings = true;
|
|
};
|
|
};
|
|
}
|
|
];
|
|
};
|
|
# for nginx to access gancio socket
|
|
users.users."${config.services.nginx.user}".extraGroups = [ config.users.users.${cfg.user}.group ];
|
|
};
|
|
}
|