nix: initial nixos module; complete packaging
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I59ec5a4f67ddae2139e72ef4c0c113366a6a6964
This commit is contained in:
parent
da1fab4257
commit
75018f69df
3 changed files with 223 additions and 10 deletions
182
nix/module.nix
Normal file
182
nix/module.nix
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
inputs: {
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.options) mkOption mkEnableOption mkPackageOption;
|
||||
inherit (lib.types) str path bool;
|
||||
|
||||
settingsType = (pkgs.formats.yaml {}).type;
|
||||
|
||||
cfg = config.services.watchdog;
|
||||
in {
|
||||
meta.maintainers = with lib.maintainers; [NotAShelf];
|
||||
|
||||
options.services.watchdog = {
|
||||
enable = mkEnableOption "Watchdog privacy-preserving analytics";
|
||||
|
||||
package = mkPackageOption inputs.self.packages.${pkgs.stdenv.hostPlatform.system} "watchdog" {
|
||||
pkgsText = "self.packages.\${pkgs.stdenv.hostPlatform.system}";
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = settingsType;
|
||||
default = {};
|
||||
description = ''
|
||||
Configuration for Watchdog analytics.
|
||||
|
||||
See <https://github.com/notashelf/watchdog> for available options.
|
||||
'';
|
||||
example = {
|
||||
site = {
|
||||
domain = "example.com";
|
||||
salt_rotation = "daily";
|
||||
sampling = 1.0;
|
||||
collect = {
|
||||
pageviews = true;
|
||||
country = false;
|
||||
device = true;
|
||||
referrer = "domain";
|
||||
};
|
||||
|
||||
path = {
|
||||
strip_query = true;
|
||||
strip_fragment = true;
|
||||
collapse_numeric_segments = true;
|
||||
max_segments = 5;
|
||||
normalize_trailing_slash = true;
|
||||
};
|
||||
};
|
||||
|
||||
limits = {
|
||||
max_paths = 10000;
|
||||
max_sources = 500;
|
||||
max_custom_events = 100;
|
||||
max_events_per_minute = 10000;
|
||||
device_breakpoints = {
|
||||
mobile = 768;
|
||||
tablet = 1024;
|
||||
};
|
||||
};
|
||||
|
||||
security = {
|
||||
trusted_proxies = ["127.0.0.1" "::1"];
|
||||
cors = {
|
||||
enabled = false;
|
||||
allowed_origins = ["*"];
|
||||
};
|
||||
metrics_auth = {
|
||||
enabled = false;
|
||||
};
|
||||
};
|
||||
|
||||
server = {
|
||||
listen_addr = "127.0.0.1:8080";
|
||||
metrics_path = "/metrics";
|
||||
ingestion_path = "/api/event";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = str;
|
||||
default = "watchdog";
|
||||
description = "User account under which Watchdog runs.";
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = str;
|
||||
default = "watchdog";
|
||||
description = "Group under which Watchdog runs.";
|
||||
};
|
||||
|
||||
stateDir = mkOption {
|
||||
type = path;
|
||||
default = "/var/lib/watchdog";
|
||||
description = "Directory for Watchdog state (HLL persistence).";
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
description = "Open firewall port for Watchdog.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.watchdog = {
|
||||
description = "Watchdog Privacy Analytics";
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["network-online.target"];
|
||||
wants = ["network-online.target"];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
|
||||
ExecStart = "${lib.getExe cfg.package} -config ${settingsType.generate "config.yaml" cfg.settings}";
|
||||
|
||||
Restart = "on-failure";
|
||||
RestartSec = "5s";
|
||||
|
||||
# Security hardening
|
||||
NoNewPrivileges = true;
|
||||
PrivateTmp = true;
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
ReadWritePaths = [cfg.stateDir];
|
||||
|
||||
# Capabilities
|
||||
AmbientCapabilities = "";
|
||||
CapabilityBoundingSet = "";
|
||||
|
||||
# Sandboxing
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectControlGroups = true;
|
||||
RestrictAddressFamilies = ["AF_INET" "AF_INET6" "AF_UNIX"];
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
PrivateMounts = true;
|
||||
|
||||
# System call filtering
|
||||
SystemCallFilter = ["@system-service" "~@privileged" "~@resources"];
|
||||
SystemCallErrorNumber = "EPERM";
|
||||
SystemCallArchitectures = "native";
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
users = mkIf (cfg.user == "watchdog") {
|
||||
watchdog = {
|
||||
description = "Watchdog analytics daemon user";
|
||||
isSystemUser = true;
|
||||
group = cfg.group;
|
||||
home = cfg.stateDir;
|
||||
};
|
||||
};
|
||||
|
||||
groups = mkIf (cfg.group == "watchdog") {
|
||||
watchdog = {};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -"
|
||||
];
|
||||
|
||||
networking.firewall = mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = let
|
||||
# Extract port from listen_addr (format: "host:port" or ":port")
|
||||
listenAddr = cfg.settings.server.listen_addr or "127.0.0.1:8080";
|
||||
port = lib.toInt (lib.last (lib.splitString ":" listenAddr));
|
||||
in [port];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,11 +1,40 @@
|
|||
{buildGoModule}:
|
||||
buildGoModule {
|
||||
pname = "sample-go";
|
||||
version = "0.0.1";
|
||||
{
|
||||
lib,
|
||||
buildGoModule,
|
||||
}:
|
||||
buildGoModule (finalAttrs: {
|
||||
pname = "watchdog";
|
||||
version = "0.1.0";
|
||||
|
||||
src = ../.;
|
||||
src = let
|
||||
fs = lib.fileset;
|
||||
s = ../.;
|
||||
in
|
||||
fs.toSource {
|
||||
root = s;
|
||||
fileset = fs.unions [
|
||||
(s + /cmd)
|
||||
(s + /internal)
|
||||
(s + /go.mod)
|
||||
(s + /go.sum)
|
||||
];
|
||||
};
|
||||
|
||||
vendorHash = "";
|
||||
vendorHash = "sha256-jMqPVvMZDm406Gi2g4zNSRJMySLAN7/CR/2NgF+gqtA=";
|
||||
|
||||
ldflags = ["-s" "-w"];
|
||||
}
|
||||
ldflags = ["-s" "-w" "-X main.version=${finalAttrs.version}"];
|
||||
|
||||
# Copy web assets
|
||||
postInstall = ''
|
||||
mkdir -p $out/share/watchdog
|
||||
cp -r $src/web $out/share/watchdog/
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Privacy-preserving web analytics with Prometheus-native metrics";
|
||||
homepage = "https://github.com/notashelf/watchdog";
|
||||
license = lib.licenses.gpl3Only;
|
||||
maintainers = with lib.maintainers; [NotAShelf];
|
||||
mainProgram = "watchdog";
|
||||
};
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,13 +2,15 @@
|
|||
mkShell,
|
||||
go,
|
||||
gopls,
|
||||
golines,
|
||||
delve,
|
||||
}:
|
||||
mkShell {
|
||||
name = "go";
|
||||
packages = [
|
||||
delve
|
||||
go
|
||||
gopls
|
||||
gopls # formatter
|
||||
golines # line wrapper
|
||||
delve # debugger
|
||||
];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue