1 { config, pkgs, lib, utils, ... }:
3 cfg = config.services.pghero;
4 settingsFormat = pkgs.formats.yaml { };
5 settingsFile = settingsFormat.generate "pghero.yaml" cfg.settings;
8 options.services.pghero = {
9 enable = lib.mkEnableOption "PgHero service";
10 package = lib.mkPackageOption pkgs "pghero" { };
12 listenAddress = lib.mkOption {
14 example = "[::1]:3000";
16 `hostname:port` to listen for HTTP traffic.
18 This is bound using the systemd socket activation.
22 extraArgs = lib.mkOption {
23 type = lib.types.listOf lib.types.str;
26 Additional command-line arguments for the systemd service.
28 Refer to the [Puma web server documentation] for available arguments.
30 [Puma web server documentation]: https://puma.io/puma#configuration
34 settings = lib.mkOption {
35 type = settingsFormat.type;
40 url = "<%= ENV['PRIMARY_DATABASE_URL'] %>";
45 PgHero configuration. Refer to the [PgHero documentation] for more
48 [PgHero documentation]: https://github.com/ankane/pghero/blob/master/guides/Linux.md#multiple-databases
52 environment = lib.mkOption {
53 type = lib.types.attrsOf lib.types.str;
56 Environment variables to set for the service. Secrets should be
57 specified using {option}`environmentFile`.
61 environmentFiles = lib.mkOption {
62 type = lib.types.listOf lib.types.path;
65 File to load environment variables from. Loaded variables override
66 values set in {option}`environment`.
70 extraGroups = lib.mkOption {
71 type = lib.types.listOf lib.types.str;
73 example = [ "tlskeys" ];
75 Additional groups for the systemd service.
80 config = lib.mkIf cfg.enable {
81 systemd.sockets.pghero = {
82 unitConfig.Description = "PgHero HTTP socket";
83 wantedBy = [ "sockets.target" ];
84 listenStreams = [ cfg.listenAddress ];
87 systemd.services.pghero = {
88 description = "PgHero performance dashboard for PostgreSQL";
89 wantedBy = [ "multi-user.target" ];
90 requires = [ "pghero.socket" ];
91 after = [ "pghero.socket" "network.target" ];
94 RAILS_ENV = "production";
95 PGHERO_CONFIG_PATH = settingsFile;
102 ExecStart = utils.escapeSystemdExecArgs ([
103 (lib.getExe cfg.package)
104 "--bind-to-activated-sockets"
109 WorkingDirectory = "${cfg.package}/share/pghero";
111 EnvironmentFile = cfg.environmentFiles;
112 SupplementaryGroups = cfg.extraGroups;
118 ProtectProc = "invisible";
121 ProtectHostname = true;
122 ProtectControlGroups = true;
123 ProtectKernelLogs = true;
124 ProtectKernelModules = true;
125 ProtectKernelTunables = true;
127 PrivateDevices = true;
128 RestrictRealtime = true;
129 RestrictNamespaces = true;
130 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
131 DeviceAllow = [ "" ];
132 DevicePolicy = "closed";
133 CapabilityBoundingSet = [ "" ];
134 MemoryDenyWriteExecute = true;
135 LockPersonality = true;
136 SystemCallArchitectures = "native";
137 SystemCallErrorNumber = "EPERM";
138 SystemCallFilter = [ "@system-service" ];