1{
2 config,
3 pkgs,
4 lib,
5 ...
6}:
7let
8 inherit (lib)
9 escapeShellArgs
10 getBin
11 hasPrefix
12 literalExpression
13 mkBefore
14 mkEnableOption
15 mkIf
16 mkOption
17 mkPackageOption
18 optionalString
19 types
20 ;
21 cfg = config.services.victorialogs;
22 startCLIList = [
23 "${cfg.package}/bin/victoria-logs"
24 "-storageDataPath=/var/lib/${cfg.stateDir}"
25 "-httpListenAddr=${cfg.listenAddress}"
26 ] ++ cfg.extraOptions;
27in
28{
29 options.services.victorialogs = {
30 enable = mkEnableOption "VictoriaLogs is an open source user-friendly database for logs from VictoriaMetrics";
31 package = mkPackageOption pkgs "victoriametrics" { };
32 listenAddress = mkOption {
33 default = ":9428";
34 type = types.str;
35 description = ''
36 TCP address to listen for incoming http requests.
37 '';
38 };
39 stateDir = mkOption {
40 type = types.str;
41 default = "victorialogs";
42 description = ''
43 Directory below `/var/lib` to store VictoriaLogs data.
44 This directory will be created automatically using systemd's StateDirectory mechanism.
45 '';
46 };
47 extraOptions = mkOption {
48 type = types.listOf types.str;
49 default = [ ];
50 example = literalExpression ''
51 [
52 "-httpAuth.username=username"
53 "-httpAuth.password=file:///abs/path/to/file"
54 "-loggerLevel=WARN"
55 ]
56 '';
57 description = ''
58 Extra options to pass to VictoriaLogs. See {command}`victoria-logs -help` for
59 possible options.
60 '';
61 };
62 };
63 config = mkIf cfg.enable {
64 systemd.services.victorialogs = {
65 description = "VictoriaLogs logs database";
66 wantedBy = [ "multi-user.target" ];
67 after = [ "network.target" ];
68 startLimitBurst = 5;
69
70 serviceConfig = {
71 ExecStart = escapeShellArgs startCLIList;
72 DynamicUser = true;
73 RestartSec = 1;
74 Restart = "on-failure";
75 RuntimeDirectory = "victorialogs";
76 RuntimeDirectoryMode = "0700";
77 StateDirectory = cfg.stateDir;
78 StateDirectoryMode = "0700";
79
80 # Hardening
81 DeviceAllow = [ "/dev/null rw" ];
82 DevicePolicy = "strict";
83 LockPersonality = true;
84 MemoryDenyWriteExecute = true;
85 NoNewPrivileges = true;
86 PrivateDevices = true;
87 PrivateTmp = true;
88 PrivateUsers = true;
89 ProtectClock = true;
90 ProtectControlGroups = true;
91 ProtectHome = true;
92 ProtectHostname = true;
93 ProtectKernelLogs = true;
94 ProtectKernelModules = true;
95 ProtectKernelTunables = true;
96 ProtectProc = "invisible";
97 ProtectSystem = "full";
98 RemoveIPC = true;
99 RestrictAddressFamilies = [
100 "AF_INET"
101 "AF_INET6"
102 "AF_UNIX"
103 ];
104 RestrictNamespaces = true;
105 RestrictRealtime = true;
106 RestrictSUIDSGID = true;
107 SystemCallArchitectures = "native";
108 SystemCallFilter = [
109 "@system-service"
110 "~@privileged"
111 ];
112 };
113
114 postStart =
115 let
116 bindAddr = (optionalString (hasPrefix ":" cfg.listenAddress) "127.0.0.1") + cfg.listenAddress;
117 in
118 mkBefore ''
119 until ${getBin pkgs.curl}/bin/curl -s -o /dev/null http://${bindAddr}/ping; do
120 sleep 1;
121 done
122 '';
123 };
124 };
125}