.hive/modules/services/gotify-instance.nix

132 lines
3.7 KiB
Nix

{
config,
lib,
...
}: let
cfg = config.hive.gotify-instance;
server-config = {
server = {
listenaddr = "localhost";
port = 54545;
ssl.enabled = false;
ssl.redirecttohttps = false;
cors.alloworigins = ["${cfg.instanceFQDN}"];
stream.allowedorigins = ["${cfg.instanceFQDN}"];
};
database = {
dialect = "postgres";
connection = "host=/run/postgresql dbname=${cfg.user} user=${cfg.user}";
};
defaultuser = {
name = "admin";
pass = config.sops.placeholder.${cfg.adminPasswordSopsKey};
};
registration = false;
};
server-config-yaml = lib.generators.toYAML {} server-config;
in {
options.hive.gotify-instance = {
enable = lib.mkEnableOption "Enable the Gotify instance";
instanceFQDN = lib.mkOption {
type = lib.types.singleLineStr;
example = "gotify.example.com";
description = "Fully qualified domain name of the Gotify instance";
};
user = lib.mkOption {
type = lib.types.singleLineStr;
default = "gotify";
description = "The user to run the service as";
};
group = lib.mkOption {
type = lib.types.singleLineStr;
default = "gotify";
description = "The group to run the service as";
};
adminPasswordSopsKey = lib.mkOption {
type = lib.types.singleLineStr;
description = "The SOPS key for the default admin user";
};
};
config = lib.mkIf cfg.enable {
services.gotify.enable = true;
# Config setup
sops.templates."gotify-server-config.yml" = {
owner = cfg.user;
content = server-config-yaml;
};
environment.etc."gotify/config.yml".source = config.sops.templates."gotify-server-config.yml".path;
# User setup
users.users = lib.mkIf (cfg.user == "gotify") {
gotify = {
description = "Gotify service";
useDefaultShell = true;
group = cfg.group;
isSystemUser = true;
};
};
users.groups = lib.mkIf (cfg.group == "gotify") {
gotify = {};
};
# Configure gotify to run as the specified user (for postgres authentication)
systemd.services.gotify-server = {
serviceConfig = {
DynamicUser = lib.mkForce false;
User = cfg.user;
RuntimeDirectory = "gotify";
};
};
# Fallback server with only 403
services.nginx.virtualHosts.${config.networking.domain} = lib.mkDefault {
default = true;
locations."/".return = 403;
forceSSL = true;
enableACME = true;
};
# Virtual host for gotify
services.nginx.virtualHosts."${cfg.instanceFQDN}" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://${server-config.server.listenaddr}:${toString server-config.server.port}";
extraConfig = ''
# Ensuring it can use websockets
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto http;
proxy_redirect http:// $scheme://;
# The proxy must preserve the host because gotify verifies the host with the origin
# for WebSocket connections
proxy_set_header Host $host;
# These sets the timeout so that the websocket can stay alive
proxy_connect_timeout 1m;
proxy_send_timeout 1m;
proxy_read_timeout 1m;
'';
};
};
# Database setup
services.postgresql = {
enable = true;
ensureDatabases = [cfg.user];
ensureUsers = [
{
name = cfg.user;
ensureDBOwnership = true;
}
];
};
};
}