1 { config, lib, pkgs, ... }:
3 cfg = config.services.restic.server;
6 meta.maintainers = [ lib.maintainers.bachp ];
8 options.services.restic.server = {
9 enable = lib.mkEnableOption "Restic REST Server";
11 listenAddress = lib.mkOption {
13 example = "127.0.0.1:8080";
15 description = "Listen on a specific IP address and port or unix socket.";
18 dataDir = lib.mkOption {
19 default = "/var/lib/restic";
20 type = lib.types.path;
21 description = "The directory for storing the restic repository.";
24 appendOnly = lib.mkOption {
26 type = lib.types.bool;
28 Enable append only mode.
29 This mode allows creation of new backups but prevents deletion and modification of existing backups.
30 This can be useful when backing up systems that have a potential of being hacked.
34 privateRepos = lib.mkOption {
36 type = lib.types.bool;
39 Grants access only when a subdirectory with the same name as the user is specified in the repository URL.
43 prometheus = lib.mkOption {
45 type = lib.types.bool;
46 description = "Enable Prometheus metrics at /metrics.";
49 extraFlags = lib.mkOption {
50 type = lib.types.listOf lib.types.str;
53 Extra commandline options to pass to Restic REST server.
57 package = lib.mkPackageOption pkgs "restic-rest-server" { };
60 config = lib.mkIf cfg.enable {
62 assertion = lib.substring 0 1 cfg.listenAddress != ":";
63 message = "The restic-rest-server now uses systemd socket activation, which expects only the Port number: services.restic.server.listenAddress = \"${lib.substring 1 6 cfg.listenAddress}\";";
66 systemd.services.restic-rest-server = {
67 description = "Restic REST Server";
68 after = [ "network.target" "restic-rest-server.socket" ];
69 requires = [ "restic-rest-server.socket" ];
70 wantedBy = [ "multi-user.target" ];
73 ${cfg.package}/bin/rest-server \
74 --path ${cfg.dataDir} \
75 ${lib.optionalString cfg.appendOnly "--append-only"} \
76 ${lib.optionalString cfg.privateRepos "--private-repos"} \
77 ${lib.optionalString cfg.prometheus "--prometheus"} \
78 ${lib.escapeShellArgs cfg.extraFlags} \
85 CapabilityBoundingSet = "";
86 LockPersonality = true;
87 MemoryDenyWriteExecute = true;
88 NoNewPrivileges = true;
89 PrivateNetwork = true;
94 ProtectHostname = true;
95 ProtectKernelLogs = true;
96 ProtectProc = "invisible";
97 ProtectSystem = "strict";
98 ProtectKernelTunables = true;
99 ProtectKernelModules = true;
100 ProtectControlGroups = true;
101 PrivateDevices = true;
102 ReadWritePaths = [ cfg.dataDir ];
104 RestrictAddressFamilies = "none";
105 RestrictNamespaces = true;
106 RestrictRealtime = true;
107 RestrictSUIDSGID = true;
108 SystemCallArchitectures = "native";
109 SystemCallFilter = "@system-service";
114 systemd.sockets.restic-rest-server = {
115 listenStreams = [ cfg.listenAddress ];
116 wantedBy = [ "sockets.target" ];
119 systemd.tmpfiles.rules = lib.mkIf cfg.privateRepos [
120 "f ${cfg.dataDir}/.htpasswd 0700 restic restic -"
123 users.users.restic = {
127 uid = config.ids.uids.restic;
130 users.groups.restic.gid = config.ids.uids.restic;