nixos/gancio: init module
This commit is contained in:
parent
0e639f2cc0
commit
f5e44554c4
@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
- [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr), proxy server to bypass Cloudflare protection. Available as [services.flaresolverr](#opt-services.flaresolverr.enable) service.
|
- [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr), proxy server to bypass Cloudflare protection. Available as [services.flaresolverr](#opt-services.flaresolverr.enable) service.
|
||||||
|
|
||||||
|
- [Gancio](https://gancio.org/), a shared agenda for local communities. Available as [services.gancio](#opt-services.gancio.enable).
|
||||||
|
|
||||||
- [Goatcounter](https://www.goatcounter.com/), Easy web analytics. No tracking of personal data. Available as [services.goatcounter](options.html#opt-services.goatcocunter.enable).
|
- [Goatcounter](https://www.goatcounter.com/), Easy web analytics. No tracking of personal data. Available as [services.goatcounter](options.html#opt-services.goatcocunter.enable).
|
||||||
|
|
||||||
- [UWSM](https://github.com/Vladimir-csp/uwsm), a wayland session manager to wrap Wayland Compositors into useful systemd units such as `graphical-session.target`. Available as [programs.uwsm](#opt-programs.uwsm.enable).
|
- [UWSM](https://github.com/Vladimir-csp/uwsm), a wayland session manager to wrap Wayland Compositors into useful systemd units such as `graphical-session.target`. Available as [programs.uwsm](#opt-programs.uwsm.enable).
|
||||||
|
@ -1411,6 +1411,7 @@
|
|||||||
./services/web-apps/fluidd.nix
|
./services/web-apps/fluidd.nix
|
||||||
./services/web-apps/freshrss.nix
|
./services/web-apps/freshrss.nix
|
||||||
./services/web-apps/galene.nix
|
./services/web-apps/galene.nix
|
||||||
|
./services/web-apps/gancio.nix
|
||||||
./services/web-apps/gerrit.nix
|
./services/web-apps/gerrit.nix
|
||||||
./services/web-apps/glance.nix
|
./services/web-apps/glance.nix
|
||||||
./services/web-apps/gotify-server.nix
|
./services/web-apps/gotify-server.nix
|
||||||
|
280
nixos/modules/services/web-apps/gancio.nix
Normal file
280
nixos/modules/services/web-apps/gancio.nix
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
{
|
||||||
|
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 = "";
|
||||||
|
example = "/gancio";
|
||||||
|
description = "The URL path under which the server is reachable.";
|
||||||
|
};
|
||||||
|
server = {
|
||||||
|
host = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "localhost";
|
||||||
|
example = "::";
|
||||||
|
description = ''
|
||||||
|
The address (IPv4, IPv6 or DNS) for the gancio server to listen on.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 13120;
|
||||||
|
description = ''
|
||||||
|
Port number of 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 (import ../web-servers/nginx/vhost-options.nix { inherit config lib; });
|
||||||
|
default = { };
|
||||||
|
example = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
};
|
||||||
|
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}";
|
||||||
|
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
|
||||||
|
{
|
||||||
|
enableACME = mkDefault true;
|
||||||
|
forceSSL = mkDefault true;
|
||||||
|
locations = {
|
||||||
|
"/" = {
|
||||||
|
index = "index.html";
|
||||||
|
tryFiles = "$uri $uri @proxy";
|
||||||
|
};
|
||||||
|
"@proxy" = {
|
||||||
|
proxyWebsockets = true;
|
||||||
|
proxyPass = "http://${cfg.settings.server.host}:${toString cfg.settings.server.port}";
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -365,6 +365,7 @@ in {
|
|||||||
ft2-clone = handleTest ./ft2-clone.nix {};
|
ft2-clone = handleTest ./ft2-clone.nix {};
|
||||||
legit = handleTest ./legit.nix {};
|
legit = handleTest ./legit.nix {};
|
||||||
mimir = handleTest ./mimir.nix {};
|
mimir = handleTest ./mimir.nix {};
|
||||||
|
gancio = handleTest ./gancio.nix {};
|
||||||
garage = handleTest ./garage {};
|
garage = handleTest ./garage {};
|
||||||
gemstash = handleTest ./gemstash.nix {};
|
gemstash = handleTest ./gemstash.nix {};
|
||||||
geoserver = runTest ./geoserver.nix;
|
geoserver = runTest ./geoserver.nix;
|
||||||
|
87
nixos/tests/gancio.nix
Normal file
87
nixos/tests/gancio.nix
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import ./make-test-python.nix (
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
extraHosts = ''
|
||||||
|
192.168.13.12 agenda.example.com
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
name = "gancio";
|
||||||
|
meta.maintainers = with pkgs.lib.maintainers; [ jbgi ];
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
server =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
networking = {
|
||||||
|
interfaces.eth1 = {
|
||||||
|
ipv4.addresses = [
|
||||||
|
{
|
||||||
|
address = "192.168.13.12";
|
||||||
|
prefixLength = 24;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
inherit extraHosts;
|
||||||
|
firewall.allowedTCPPorts = [ 80 ];
|
||||||
|
};
|
||||||
|
environment.systemPackages = [ pkgs.gancio ];
|
||||||
|
services.gancio = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
hostname = "agenda.example.com";
|
||||||
|
db.dialect = "postgres";
|
||||||
|
};
|
||||||
|
plugins = [ pkgs.gancioPlugins.telegram-bridge ];
|
||||||
|
userLocale = {
|
||||||
|
en = {
|
||||||
|
register = {
|
||||||
|
description = "My new registration page description";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nginx = {
|
||||||
|
enableACME = false;
|
||||||
|
forceSSL = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
client =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
environment.systemPackages = [ pkgs.jq ];
|
||||||
|
networking = {
|
||||||
|
interfaces.eth1 = {
|
||||||
|
ipv4.addresses = [
|
||||||
|
{
|
||||||
|
address = "192.168.13.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
inherit extraHosts;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
server.wait_for_unit("postgresql")
|
||||||
|
server.wait_for_unit("gancio")
|
||||||
|
server.wait_for_unit("nginx")
|
||||||
|
server.wait_for_open_port(13120)
|
||||||
|
server.wait_for_open_port(80)
|
||||||
|
|
||||||
|
# Check can create user via cli
|
||||||
|
server.succeed("cd /var/lib/gancio && sudo -u gancio gancio users create admin dummy admin")
|
||||||
|
|
||||||
|
# Check event list is returned
|
||||||
|
client.wait_until_succeeds("curl --verbose --fail-with-body http://agenda.example.com/api/events", timeout=30)
|
||||||
|
|
||||||
|
server.shutdown()
|
||||||
|
client.shutdown()
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user