Technitium DNS fails with "access denied" at /var/lib

I’m having an issue starting the Technitium DNS server.

I have this fragment in my configuration:

services.technitium-dns-server = {
    enable = true;
    openFirewall = true;
};

I can rebuild my configuration without error. However, when I switch to the configuration, the service fails to start. I can observe this output with sudo journalctl -xeu technitium-dns-server.service:

May 23 15:08:03 wyseguy systemd[1]: technitium-dns-server.service: Scheduled restart job, >
	 Subject: Automatic restarting of a unit has been scheduled
	 Defined-By: systemd
	 Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
	
	 Automatic restarting of the unit technitium-dns-server.service has been scheduled, as t>
	 the configured Restart= setting for the unit.
May 23 15:08:03 wyseguy systemd[1]: Started Technitium DNS Server.
	 Subject: A start job for unit technitium-dns-server.service has finished successfully
	 Defined-By: systemd
	 Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
	
	 A start job for unit technitium-dns-server.service has finished successfully.
	
	 The job identifier is 52512.
May 23 15:19:37 wyseguy technitium-dns-server[14963]: System.UnauthorizedAccessException: Access to the path '/var/lib/technitium-dns-server/blocklists' is denied.
May 23 15:19:37 wyseguy technitium-dns-server[14963]:  ---> System.IO.IOException: Permission denied
May 23 15:19:37 wyseguy technitium-dns-server[14963]:    --- End of inner exception stack trace ---
May 23 15:19:37 wyseguy technitium-dns-server[14963]:    at System.IO.FileSystem.CreateDirectory(String fullPath, UnixFileMode unixCreateMode)
May 23 15:19:37 wyseguy technitium-dns-server[14963]:    at System.IO.Directory.CreateDirectory(String path)
May 23 15:19:37 wyseguy technitium-dns-server[14963]:    at DnsServerCore.DnsWebService..ctor(String configFolder, Uri updateCheckUri, Uri appStoreUri) in /build/technitium-dns-server-13.6.0/DnsServerCore/DnsWebService.cs:line 141
May 23 15:19:37 wyseguy technitium-dns-server[14963]:    at DnsServerApp.Program.Main(String[] args) in /build/technitium-dns-server-13.6.0/DnsServerApp/Program.cs:line 62
May 23 15:19:37 wyseguy technitium-dns-server[14963]:
May 23 15:19:37 wyseguy technitium-dns-server[14963]: Technitium DNS Server is stopping...
May 23 15:19:37 wyseguy technitium-dns-server[14963]: Technitium DNS Server was stopped successfully.
May 23 15:19:37 wyseguy systemd[1]: technitium-dns-server.service: Deactivated successfully.
	 Subject: Unit succeeded
	 Defined-By: systemd
	 Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
	
	 The unit technitium-dns-server.service has successfully entered the 'dead' state.

This output repeats as long as the service is enabled.

To me, this looks like a permissions issue at the path /var/lib/technitium-dns-server. The permissions currently look like this:

~/.nixos: sudo ls /var/lib/ -ahl | grep technitium
lrwxrwxrwx  1 root            root              29 May 23 14:10 technitium-dns-server -> private/technitium-dns-server

~/.nixos: sudo ls /var/lib/private/ -ahl
total 16K
drwx------  4 root   root    4.0K May 23 14:10 .
drwxr-xr-x 26 root   root    4.0K May 23 15:00 ..
drwxr-xr-x  2 nobody nogroup 4.0K May 23 14:10 technitium-dns-server

By reviewing both the generated service definition and the NixOS service definition, I’ve noticed that this service uses a dynamic user. My issue seems slightly similar to this reported issue with the dendrite package, but the OP of that issue never responded after posting the issue, and I don’t think I understand the suggestion to use systemd.tmpfiles.rules.

I have tried manually removing the directory /var/lib/private/technitium-dns-server and allowing systemd to recreate it. The permissions end up looking exactly the same, and I get the same exception in the journalctl logs.

I am using Nixpkgs unstable, and I am not using impermanence.

Is this an issue with the Technitium package that I need to report on GitHub, or am I doing something wrong with my permissions or something? What might cause a permission denied error for a service accessing its own config directory?

I have exactly the same problem, and I couldn’t fix it.
I’ve tried two different suggestions of tmpfiles option:

tmpfiles.rules = [ “d /var/lib/technitium-dns-server 0755 root root” ];
and
tmpfiles.rules = [ “d /var/lib/technitium-dns-server 0755 technitium-dns-server technitium-dns-server” ];
users.users.myusername = {
extraGroups = [ “technitium-dns-server” ];
};

It’s definitely an issue with the module and should be reported upstream. Pre-creating the path can only break things further, I would suggest removing that config and making sure to delete any directories it created, just in case systemd doesn’t want to override them.

1 Like

If anyone runs into this in future, I found that the following custom SystemD service file has the benefit of being both functional AND hardened (and is based on the services.technitium-dns-server option). If you don’t care for hardening, you can probably save yourself a tonne of headache and just write a basic autostart module.

(As of present, the services.technitium-dns-server option is completely borked.)

systemd.services.technitium-dns-server = {
  description = "Technitium DNS Server";
  wantedBy = [ "multi-user.target" ];
  after = [ "network.target" ];

  serviceConfig = {
    ExecStart = "${pkgs.technitium-dns-server}/bin/technitium-dns-server /var/lib/technitium/config";

    DynamicUser = true;

    StateDirectory = "technitium";
    LogsDirectory = "technitium";
    CacheDirectory = "technitium";

    WorkingDirectory = "/var/lib/technitium";
    ReadWritePaths = "/var/lib/technitium /var/log/technitium /var/cache/technitium";

    Restart = "always";
    RestartSec = 10;
    TimeoutStopSec = 10;
    KillSignal = "SIGINT";

    # Harden the service
    LockPersonality = true;
    NoNewPrivileges = true;
    PrivateDevices = true;
    PrivateMounts = true;
    PrivateTmp = true;
    ProtectClock = true;
    ProtectControlGroups = true;
    ProtectHome = true;
    ProtectHostname = true;
    ProtectKernelLogs = true;
    ProtectKernelModules = true;
    ProtectKernelTunables = true;
    ProtectSystem = "strict";
    RemoveIPC = true;
    RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_NETLINK";
    RestrictNamespaces = true;
    RestrictRealtime = true;
    RestrictSUIDSGID = true;

    AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
    CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
  };
}