Sanity check getting Traefik to work

I am trying to get traefik to work with a static-config.yaml file I put in my flake. My config wants to use Cloudflare as an ACME dns resolver and I have to use an env file to add the key.

However, if I read the service definition of Traefik correctly, it will assume that the static config is in /run/traefik/config.toml, but the derivation doesn’t actually create this file?

That seems like a bug to me, but I wanted to get a sanity check before I create a bug report on the tracker.

My traefik nix file:

{ config, lib, pkgs, secretsRoot, ... }:
let
  dataDir = config.services.traefik.dataDir;
  isEnabled = config.services.traefik.enable;
  dataPath = /. + config.services.traefik.dataDir;
in
{
  services.traefik = {
    enable = lib.mkDefault false;

    staticConfigFile = ./traefik-static.yaml;
    environmentFiles = [
      config.sops.secrets."traefik/env".path
    ];
  };

  sops.secrets = lib.mkIf isEnabled {
    traefik-acme = 
    let acmePath = lib.path.append dataPath "acme.json";
    in
    {
      format = "binary";
      sopsFile = lib.path.append secretsRoot "general/acme.json";
      group = config.services.traefik.group;
      path = builtins.toString acmePath;
      mode = "0660";
      reloadUnits = [
        "traefik.service"
      ];
    };

    "traefik/env" = {};
  };
}

I believe it will be overridden using the --configfile flag.

ExecStart = "${cfg.package}/bin/traefik --configfile=${finalStaticConfigFile}";

You can probably find the path to the final file by running systemctl cat traefik.service

A lot of services in NixOS don’t put their configfiles outside the nix store, so it’s probably not the last time you’ll be referring to the systemd unit to find the config file.

It will. The problem is that it the path that finalStaticConfigFile points to, isn’t created by the derivation. So it points to a file that doesn’t exist.

Ah, I overlooked the config you provided earlier.

The problem is that it the path that finalStaticConfigFile points to, isn’t created by the derivation. So it points to a file that doesn’t exist.

I don’t think it should. In your case you have a staticConfigFile specified, in addition to secrets in an environmentFile. From the service definition, this should lead to a systemd unit with an ExecStartPre script that uses envSubst and injects secrets into your staticConfigFile content before putting it in /run/traefik/config.toml, and specify that path with --configfile. The relevant parts of the module are:

# Should result in `staticConfigFile = cfg.staticConfigFile`
staticConfigFile = if cfg.staticConfigFile == null then
   .....
else
  cfg.staticConfigFile;

# Should result in `finalStaticConfigFile = "/run/traefik/config.toml"`
finalStaticConfigFile =
  if cfg.environmentFiles == []
  then staticConfigFile
  else "/run/traefik/config.toml";

....

# Should result in an `ExecStartPre` phase that writes out the config template
# with injected secrets into "/run/traefik/config.toml" right before starting the service
ExecStartPre = lib.optional (cfg.environmentFiles != [])
  (pkgs.writeShellScript "pre-start" ''
    umask 077
    ${pkgs.envsubst}/bin/envsubst -i "${staticConfigFile}" > "${finalStaticConfigFile}"
  '');

Could you verify that the ExecStartPre field is part of the service? If it is not, then that’s problematic. If it is, could you check whether the file exists while traefik.service is running?

It was, but I think I was running into permission issues (because of how I added my “external” configs). After overriding some values of the systemd service in my own module I managed to get it to work (sort off).

Traefik runs and starts now, but I can’t get to the dashboard yet. That is a problem for another time though :slight_smile: