Skip to content

{nixos, nixos/tests}/traefik: re-refactor traefik, update tests - #490985

Open
jackrosenberg wants to merge 11 commits into
NixOS:masterfrom
jackrosenberg:revert-490920-revert-482512-push-lysqxmrwmzlt
Open

{nixos, nixos/tests}/traefik: re-refactor traefik, update tests#490985
jackrosenberg wants to merge 11 commits into
NixOS:masterfrom
jackrosenberg:revert-490920-revert-482512-push-lysqxmrwmzlt

Conversation

@jackrosenberg

@jackrosenberg jackrosenberg commented Feb 16, 2026

Copy link
Copy Markdown
Member

WIP WIP

Un-Reverts #490920, with the necessary fixes.

Closes #471071, traefik/traefik#12777

TODO:

@jackrosenberg jackrosenberg changed the title nixos/traefik: re-refactor traefik, {nixos, nixos/tests}/traefik: re-refactor traefik, update tests Feb 16, 2026
@nixpkgs-ci nixpkgs-ci Bot added 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog This PR adds or changes release notes 8.has: module (update) This PR changes an existing module in `nixos/` 8.has: documentation This PR adds or changes documentation labels Feb 16, 2026
@jackrosenberg

Copy link
Copy Markdown
Member Author

@TheRealGramdalf @SigmaSquadron @adamcstephens continuing the conversation in #490814,
the ExecStartPre was not working. useEnvSubst was default true, which means the finalStaticConf file defaulted to /run/traefik/config.json. I believe this file was supposed to be created by the ExecStartPre using envsubst and >, but was not. This lead to traefik being run with default static conf, while printing the whole true static conf to the logs, which only made it look like it was being used.

My preference goes toward removing the useEnvSubst logic, since traefik as a module is already quite complicated. I think less is more here, as we already provide a way to securely use secrets via environmentFiles.

I have tested extensively, especially in regards to Fernando's changes here. They work as expected, but are also needlessly complex.
I don't think we need to add extra options to ensure people can run traefik with an explicit singular configuration that secretly translates to the same result as the other options. I am all for simplifying here as well.

@jackrosenberg

Copy link
Copy Markdown
Member Author

Furthermore, we need to revamp the testing of this module. I propose integration testing with pangolin or some other complex module that depends on traefik. Open to suggestions/feedback here.

@jackrosenberg jackrosenberg self-assigned this Feb 16, 2026
@jackrosenberg
jackrosenberg force-pushed the revert-490920-revert-482512-push-lysqxmrwmzlt branch 2 times, most recently from 6a0597c to e214125 Compare February 17, 2026 12:01
@jackrosenberg
jackrosenberg force-pushed the revert-490920-revert-482512-push-lysqxmrwmzlt branch from e214125 to e9f5ac0 Compare February 17, 2026 13:36
@nixpkgs-ci nixpkgs-ci Bot added 8.has: package (new) This PR adds a new package 10.rebuild-darwin: 1-10 This PR causes between 1 and 10 packages to rebuild on Darwin. 6.topic: fetch Fetchers (e.g. fetchgit, fetchsvn, ...) and removed 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin. labels Feb 17, 2026
@jackrosenberg
jackrosenberg force-pushed the revert-490920-revert-482512-push-lysqxmrwmzlt branch from e9f5ac0 to d3be4dd Compare February 17, 2026 18:26
@nixpkgs-ci nixpkgs-ci Bot added the 2.status: merge conflict This PR has merge conflicts with the target branch label Feb 20, 2026
@jackrosenberg
jackrosenberg force-pushed the revert-490920-revert-482512-push-lysqxmrwmzlt branch 3 times, most recently from 8048ce6 to d779e78 Compare February 20, 2026 14:01
@jackrosenberg

Copy link
Copy Markdown
Member Author

@ofborg test traefik

@RafaelKr

Copy link
Copy Markdown
Contributor

I understand that concern, but this isn't blindly generated LLM garbage (slop). I put a lot of thought into it myself and I manually checked every line of code.

Most of it diffs cleanly against the original PR code or even is the original code just repositioned in the config tree to make it work with the attrTag pattern. You might like to skim through the diff against this PR and if you're still not convinced then I'll apologize to have stolen your time.

@SigmaSquadron
SigmaSquadron marked this pull request as draft July 19, 2026 10:20
@SigmaSquadron

Copy link
Copy Markdown
Contributor

I've marked this as a draft following @jackrosenberg's wishes to rollback all AI-assisted code, a decision that I agree with. LLMs do not understand the complexities of the module system and NixOS module design, and I have already seen a couple of AI-generated mistakes in the new code.

@jackrosenberg

Copy link
Copy Markdown
Member Author

@TheRealGramdalf would you please move your commits to a seperate PR, based on this one?

@nixpkgs-ci nixpkgs-ci Bot added the 2.status: merge conflict This PR has merge conflicts with the target branch label Jul 19, 2026
@truh
truh self-requested a review July 21, 2026 14:03
@RafaelKr

RafaelKr commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Following up on the draft: I've rebuilt my attrTag refactor as a commit series on top of 162b5d3 (your last commit), so it no longer touches or references any of the work that's in question. Branch: traefik-install-routing-attrtag-v2 (diff against 162b5d33). If the trimmed head ends up different from 162b5d3, I'll rebase onto that first.

This comment is long because it carries the reasoning behind each decision. The non-trivial commits carry that same reasoning in their messages, so you can also just go through the series commit by commit.

Same disclosure as before: LLM-assisted, but the design and the reasoning are mine. What I first posted was a proof of concept; since then I've worked it through properly, and every line of these commits has been through my own review.
@jackrosenberg: I'm confident it's in good shape now, but you're right that this is a complex module, and it warrants a careful review rather than taking my word for it.

I understand the concern about LLMs. For this series I can only say that the tests show what the module actually generates, and that Traefik serves it. I'd just like it reviewed like any other patch, and if something is wrong I'd rather know.

A few commits build on TheRealGramdalf's work from this PR and carry his Co-authored-by; since you've asked for those commits to move to their own PR, I checked those pieces especially carefully against the module evaluation and the VM test before keeping them.

For context on why I'm in this module at all: this grew out of #487367 (NetBird). The NetBird stack runs fine behind nginx, but their newer built-in reverse proxy is a separate feature that needs Traefik: the NetBird proxy manages its own certificates, so whatever sits in front of it must not terminate TLS, and Traefik is the only proxy NetBird supports for that. That work is still WIP and not yet tested against this series. I'll follow up when it is. I'd like to help move this module forward wherever I can.

What's in the series

The main goal was to make the mutually exclusive options unrepresentable by construction, instead of having assertions catch them afterwards. The implementation itself stays as close to Traefik's own configuration as possible: if you have used Traefik before NixOS, your existing config should translate almost key for key, and the examples from Traefik's docs carry over directly. The three docs-mirror nodes in the test check exactly that.

Nine small standalone fixes come first (see "What I hit" below), then:

  • install becomes attrTag { file; settings } and the routing side gets routing.provider = nullOr (attrTag { file; externalFile; directory }). The mutually-exclusive combinations can't be written any more, so the assertions that policed them drop out. The derived config — providers.file from the provider, experimental.localPlugins from the plugin packages — is merged in when the config file is generated, instead of being written into install.settings.
  • routing.settings becomes first-class instead of deprecated: it's where a machine's own routing config belongs, and it's what the released dynamicConfigOptions rename resolves to, so upgrading users don't land on an option that's scheduled for removal. Named routing.extraFiles entries stay for config that has to remain individually identifiable. That's where other modules should contribute, and it's what pangolin already does. routing.* has never been in a release, so dropping the migration shim breaks nobody.
  • Tests: one node per configuration shape; the generated --configfile is asserted directly through an internal readOnly installConfigFile option (no ExecStart scraping); three nodes mirror examples from Traefik's v3.7 docs and assert the generated files match them 1:1, with a negative control proving the comparison can fail.
  • Two rename-only commits at the very end (localPluginslocalPluginPackages, routing.filesrouting.extraFiles). Both are names @TheRealGramdalf already chose in this PR, so those commits carry his Co-authored-by; I kept his spelling rather than invent a third one. Nothing sits on top of them, so they're easy to drop if you'd rather keep your own names.

nixosTests.traefik passes (12 subtests; the container nodes need a daemon with auto-allocate-uids = true) and the manual builds. Every intermediate commit evaluates the test suite, so the series bisects. The pangolin module needs no changes beyond the renames, and one commit updates the pangolin and authelia tests to the current option names.

Why the type-level split

At 162b5d33 the module writes its derived config into the same options users write into: providers.file and experimental.localPlugins are merged into install.settings, and routing.settings is copied into a generated routing.files entry. Two things follow. install.settings' own { entryPoints.http.address = ":80"; } default can never apply, because a default only applies while nothing defines the option and with the default routing.dir the module always does; enable = true alone yields a config with no entryPoints. And the exclusivity checks have to compare values against defaults, which an explicitly-written default value defeats.

With the attrTag split, options hold only user configuration and the module's own derived values are merged at generation time — there's nothing to tell apart afterwards, and what you write is what Traefik gets:

How the options flow, before and after (diagrams LLM-assisted)

at 162b5d33, the module writes its derived values into install.settings and routing.files, the options you also write into; the :80 default never applies:

routing.settings    ──> routing.files."custom-migrated"
routing.dir         ─┐
routing.file        ─┼────────────┐
localPlugins        ─┘            │  written into the option
                                  v
┌─ install.settings (its ":80" default never applies) ───────────────┐
└─────────────────────────────────┬──────────────────────────────────┘
                                  v
                             install file

every arrow is a definition the module writes into an option

my attrTag refactor: install.settings is read once and nothing is written back into an option, and the routing side ends in its own file(s):

┌─ install.settings (plain json.type) ───────────────────────────────┐
└─────────────────────────────────┬──────────────────────────────────┘
                                  │  merged on top:
routing.provider    ──────────────┤    as providers.file
localPluginPackages ──────────────┤    as experimental.localPlugins
                                  v
                          installConfigFile

routing.settings    ─┐
routing.extraFiles  ─┴─> routing file(s)
                         (one merged file — or, under a
                          directory provider, one file per fragment)

both merges happen in the module's let, not by defining an option

If we want to expose the derived final install config we still could do so by putting it in a readOnly option, e.g. installConfig (it can't live under install, which is the attrTag), and generating installConfigFile from that.

What I hit at 162b5d33

Flagging these because they matter independently of the refactor; all are addressed in the series, mostly as standalone one-commit fixes. These are all against 162b5d33, your last commit and my branch's base. Four of them are already fixed in @TheRealGramdalf's commits (marked below), so those only matter if the rollback lands.

  • install.file fails eval when set: the exclusivity assertion passes a list to builtins.all without a predicate, so any non-default value dies with expected a Boolean but found the partially applied built-in function 'all'. (A one-line fix if you keep the current shape; the attrTag makes the assertion unnecessary, so the series removes it.) Already fixed in TheRealGramdalf's commits.
  • The unreachable :80 default above. Already fixed in TheRealGramdalf's commits.
  • With a custom user the dataDir tmpfiles rule is skipped (it requires user == "traefik"). /var/lib/traefik then only appears as a side effect of the routing.dir rule, owned by root and mode 0755, so Traefik can't write its ACME store there; with routing.dir = null nothing creates it at all and the unit fails on a nonexistent WorkingDirectory. Already fixed in TheRealGramdalf's commits.
  • A routing.files entry without settings evaluates to null and ships a routing file containing just null.
  • The unmarked-plugin warning lists the correctly-marked plugins instead of the unmarked ones; the docker warning suggests services.docker (the option is virtualisation.docker.enable); the docs call the plugins option services.traefik.plugins. Already fixed in TheRealGramdalf's commits.
  • The geoblock docs example can't work: the plugin requires an api endpoint and a cacheSize it never gets, the entrypoint middleware reference needs the provider-qualified list form, and the websecure entrypoint it attaches to is declared without an address.
  • The routing-route test check can race Traefik's file provider (READY arrives before the routes are loaded), so the series switches it to wait_until_succeeds.

One suggestion rather than a bug: I'd drop the new user option and keep the fixed traefik user. The two sources I checked both run a dedicated traefik user: Traefik's own contrib systemd unit, and the released module, which hardcodes User = "traefik". The docker case is what group/supplementaryGroups already cover. Without a custom user the dataDir tmpfiles rule collapses to one unconditional line (and my dataDir fix above mostly dissolves).

The docs-example tests are the regression guard for the verbatim rendering: nixos/tests/traefik.nix.

It's your PR and your call. Cherry-pick and build on it if it's useful, or drop it. No hard feelings either way.

directory = mkOption {
default = cfg.routing.dir;
defaultText = literalExpression "cfg.routing.dir";
description = "Load dynamic configuration from a file.";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this description flip flopped with the file description above?

@RafaelKr

RafaelKr commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

@ulic75 I'm not sure if this PR is in a good state for review.
@jackrosenberg and @SigmaSquadron asked @TheRealGramdalf to drop his commits, which didn't happen yet.

You could review the changes up until 162b5d3: 3836cc44c259f27c5e3fc15e3e9aa9585a555334^...162b5d3

If you're very invested you might also like to check my previous comment. But I understand if you don’t have time for that 😆

Edit: jackrosenberg just dropped the commits.

@jackrosenberg
jackrosenberg force-pushed the revert-490920-revert-482512-push-lysqxmrwmzlt branch from c208a98 to 51eed21 Compare August 5, 2026 15:14
@jackrosenberg

Copy link
Copy Markdown
Member Author

I've force pushed back to 51eed21. I truly don't mean to erase other's work, but will not have LLM assisted work in my PR. Feel free to open a separate PR based on this one. I will be fixing the conflicts in this and polishing this up in the next few days :). Hopefully we can finally get this rework merged, and open up some room for future work!

@RafaelKr

RafaelKr commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

I understand that you don't want LLM assisted work on your PR.

To speak for me: I didn't open a "competing" PR to your work as it feels like an attack against you and if I would "steal" your work. This is the last thing I want. I'd really like to build and move this forward together :)

As to the fixes you want to tackle: You might want to check out the first 9 commits from my changes: RafaelKr/nixpkgs@162b5d3...c5f9c10
They're very small (+53, -31) and self-contained, every commit message mentions what's fixed :) Feel free to take them, even without any credit.

Still I would appreciate some feedback on my attrTag implementation, as I really like the option interface it provides.
The nixos/modules/services/web-servers/traefik.md describes it in a short form and nixos/tests/traefik.nix contains many usage examples. If some people like it and you, as the initial author, are fine with it, I might open an own PR.

jackrosenberg and others added 11 commits August 12, 2026 16:28
…x configurations and failing testcases."

Co-Authored-By: Fernando Rodrigues <alpha@sigmasquadron.net>
Co-Authored-By: TheRealGramdalf <gramdalftech@gmail.com>
Co-Authored-By: Florian Schubert <30634234+JamesofScout@users.noreply.github.com>
This function takes in the provider, owner and plugin name, and outputs
a correctly-formatted derivation with the Traefik plugin, which can be
`symlinkJoin`ed in the `/var/lib/traefik/plugins-local` folder.

Signed-off-by: Fernando Rodrigues <alpha@sigmasquadron.net>
…refactor traefik module

Signed-off-by: Fernando Rodrigues <alpha@sigmasquadron.net>
Co-authored-by: Jack Rosenberg <github@jackr.eu>
Signed-off-by: Fernando Rodrigues <alpha@sigmasquadron.net>
Signed-off-by: Fernando Rodrigues <alpha@sigmasquadron.net>
Signed-off-by: Fernando Rodrigues <alpha@sigmasquadron.net>
Signed-off-by: Fernando Rodrigues <alpha@sigmasquadron.net>
Signed-off-by: Fernando Rodrigues <alpha@sigmasquadron.net>
@jackrosenberg

Copy link
Copy Markdown
Member Author

Rebased and fixed conflicts. I would appreciate another round of feedback if people are willing :) Looking to get this merged soon!

@TheRealGramdalf

TheRealGramdalf commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

I've force pushed back to 51eed21. I truly don't mean to erase other's work, but will not have LLM assisted work in my PR. Feel free to open a separate PR based on this one. I will be fixing the conflicts in this and polishing this up in the next few days :). Hopefully we can finally get this rework merged, and open up some room for future work!

If you meant to drop my work as well, I'm quite frustrated by this.

  • I originally opened a PR with the vast majority of this refactor several years ago
  • You found my PR and adopted it as part of another which introduced traefik plugins to nixpkgs/the module
  • It was merged prematurely with changes that I missed during the review process that completely changed the approach to how things were done
  • Those changes were reverted, and this PR was opened
  • I did my best to stay up to date and help with this PR despite being very busy in my personal life
  • I was given access to @jackrosenberg nixpkgs repository, and made many fixes
  • I used AI once, following the proper guidelines outlined by nixpkgs, and in a very intentional way - specifically to substitute for my lack of capacity to overanalyze every portion of this very large PR. AI did not create any of the code that I pushed - that was all written by me, by hand.
  • I was asked to drop the commits I made, to move work to a separate PR. I did this (though I don't think I've published the branch to my fork of nixpkgs or opened a PR yet).
  • I missed some of the more recent messages, my best guess as to why is that github doesn't deal with long discussions well.
  • The PR has been reverted to a very broken state, discarding all of the work I have done since it was opened.
  • It wasn't made very clear to me why I should move my commits, and I assumed it was to split out the complexity of changing the module on top of introducing the plugins interface
  • All of my work has been erased, though thankfully I have a copy of the bulk of the changes (the module and the tests) from my start at splitting things off
  • The changes that still remain in this PR are almost all slight variations of my original code, changed in ways that I disagree with.

If you don't want AI in "your" PR, I'm happy to take my code elsewhere. If that's the case, I'd ask that you remain consistent and drop the code that was based on my initial work as well. As I said on matrix, that means basically everything except for the plugins option and fetcher.

I'm happy to collaborate if you're open to it, but I'm not okay with my work being essentially stolen and getting kicked out of my own project. If you want to include my work, then you need to include all of it. Even if it was mildly assisted by AI to move things along quicker as you so desperately seem to want.

@jackrosenberg

Copy link
Copy Markdown
Member Author

TBH i'm pretty done guys. This PR is very large, and I'm tired of pulling and pulling to get this over the finish line.

I am vehemently opposed to LLM usage in any way shape or form. I made this clear above. Seeing walls of LLM text as a response to me saying 'dont use LLM in my fork', motivated me to drop all commits that were not my own or @SigmaSquadron's. @TheRealGramdalf, I asked you to move your new commits to a separate PR because this one is huge, not because I want to kick you out and claim credit for your part of the work.

@TheRealGramdalf

Copy link
Copy Markdown
Contributor

TBH i'm pretty done guys. This PR is very large, and I'm tired of pulling and pulling to get this over the finish line.

I'm sorry for the part I played in this. I've just been very busy, though I'm afraid that's about the most I can say - I'd prefer to keep the details private.

I am vehemently opposed to LLM usage in any way shape or form. I made this clear above. Seeing walls of LLM text as a response to me saying 'dont use LLM in my fork', motivated me to drop all commits that were not my own or @SigmaSquadron's.

To each their own; I can respect that. Thanks for clarifying.

@TheRealGramdalf, I asked you to move your new commits to a separate PR because this one is huge, not because I want to kick you out and claim credit for your part of the work.

Thank you for making that clear, and sorry if what I said came across the wrong way. I didn't intend to be accusatory, rereading it now I can see my frustration getting the better of me. Apologies for the kerfuffle.


Going forward, here's what I propose:

  • I'll split the module and test refactor into a separate PR
  • The addition of plugins/the fetcher can be left to @jackrosenberg which can happen in a separate PR
  • I'll do my best to fix the documentation, but I won't let that drag my PR on forever. I'll prioritize getting the actual module changes merged, and docs improvements can happen later if needed
  • I'll try to get things merged ASAP

Does that sound reasonable?

@TheRealGramdalf

TheRealGramdalf commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Here's the code that I removed for the plugins:


Located under the services.traefik.install.settings submodule

# TODO make sure this properly replaces `mkIf` statement as intended
experimental.localPlugins = mkOption {
  default =
    default=
      lib.listToAttrs (
        map (
          plugin: lib.nameValuePair plugin.plugin { inherit (plugin) moduleName; }
        ) cfg.localPluginPackages
      );
  defaultText = literalExpression ''
    default=
      lib.listToAttrs (
        map (
          plugin: lib.nameValuePair plugin.plugin { inherit (plugin) moduleName; }
        ) config.services.traefik.localPluginPackages
      );
  '';
  example = {
    "wasm-plugin-name".settings = {
      envs = [ "SECRET_ENV" ];
      mounts = [ "/path/to/mount" ];
    };
  };
  description = ''
    Local plugins allow you to use plugins from a local directory, without publishing them to the Traefik plugin catalog.

    ::: {.note}
    By default, this will create an attribute set from the option `cfg.localPluginPackages`. To add a plugin from a package, use that option instead.
    :::
  '';
};

Located at services.traefik.localPluginPackages

localPluginPackages = mkOption {
  default = [ ];
  type = listOf package;
  example = literalExpression ''
    [
      pkgs.geoblock
      pkgs.fetchTraefikPlugin
      {
        plugin = "plugindemo";
        owner = "traefik";
        version = "0.2.2";
        hash = "sha256-6MuKVvtHUtWuibjUMZknOEklzaHQUjRYHvXdP2QqE6c=";
      }
    ];
  '';
  description = ''
    List of plugin packages to be added to the `localPlugins` attribute in the install configuration.

    These plugins can be packaged in Nixpkgs, or [fetched directly](#module-services-traefik-plugins-custom)
  '';
};

Add to config

warnings =
  # TODO check for functionality as intended
  # TODO does/can this show where the definition location is (i.e. what file of the user's config)?
  ++ optional (!(builtins.all (plugin: plugin._isTraefikPlugin or false) cfg.localPluginPackages)) ''
    Some of the Traefik local plugins in 'services.traefik.localPluginPackages' may be misconfigured.
    The following paths are built from derivations that do not have the '_isTraefikPlugin' attribute set to 'true':
    - ${
      concatMapStringsSep "\n- " (badPlugin: badPlugin.outPath) (
        filter (plugin: !plugin._isTraefikPlugin or false) cfg.localPluginPackages
      )
    }
  '';

Add to tmpfiles settings

# Symlink package directories (in the nix store) to the `plugins-local` folder
# This path is hard coded, and should be placed in the working directory of the process running the Traefik binary.
# TODO What happens to old symlinks? it appears they would just pile up indefinitely.
(mkIf (cfg.localPluginPackages != [ ]) {
  "${cfg.dataDir}/plugins-local"."L+" = {
    argument = toString (
      pkgs.symlinkJoin {
        name = "traefik-plugins";
        paths = cfg.localPluginPackages;
      }
    );
  };
})

NixOS Manual:

  "module-services-traefik-plugins": [
    "index.html#module-services-traefik-plugins"
  ],
  "module-services-traefik-plugins-custom": [
    "index.html#module-services-traefik-plugins-custom"
  ],

Plugins {#module-services-traefik-plugins}

When using the structured settings configuration options, the Traefik module
supports [plugins][upstream-3]. Plugins in Traefik are an additional routing
configuration source and can programatically set up routes and proxies.

The {option}services.traefik.localPluginPackages option takes in a list of derivations
that contain Traefik plugins. Some plugins are available in the package set, and
can be called directly from pkgs. The example below sets up geoblock, a
Traefik plugin that blocks connections from a given list of countries based on
the client's IP address, to block all connections not coming from the Netherlands.

{
  services.traefik = {
    plugins = [ pkgs.geoblock ];
    install.settings.entryPoints.websecure.http.middlewares = "my-geoblock";
    routing.settings.http.middlewares.my-geoblock.plugin.geoblock.countries = [ "NL" ];
  };
}

Custom Plugins {#module-services-traefik-plugins-custom}

Plugins that are not currently packaged in Nixpkgs can also be added to the
{option}services.traefik.localPluginPackages option after being built with the
fetchTraefikPlugin builder. See the Nixpkgs manual section on
fetchTraefikPlugin
for more information on the available options.

{
  services.traefik.localPluginPackages = [
    (pkgs.fetchTraefikPlugin {
      plugin = "traefik";
      owner = "plugindemo";
      version = "v0.2.2";
      hash = "";
    })
  ];
}

For plugins not found in plugins.traefik.io, simply use the
lib.fileset.toSource library function to build a derivation from a path to a
local plugin. The module will generate a warning mentioning that the local plugin
may be misconfigured, but it can be safely ignored, or removed by updating the
derivation to include the _isTraefikPlugin attribute.

{
  services.traefik.localPluginPackages = [
    (
      (lib.fileset.toSource {
        root = ./my-plugin;
        fileset = ./my-plugin;
      })
      # Supress Traefik module warning.
      # Don't forget to ensure that ./my-plugin has an appropriate
      # directory structure as expected by Traefik.
      // {
        _isTraefikPlugin = true;
      }
    )
  ];
}

And some todo list items:

Future PRs

  • localPluginPackages do not currently have any tests associated with them. I believe it's up to @jackrosenberg as the creator of the plugins interface
    • The pangolin module acts as the de facto test for the purposes of this already large PR. Direct tests could be implemented in a further PR
  • creation and auto-updating of a traefikPlugins package set, see {nixos, nixos/tests}/traefik: re-refactor traefik, update tests #490985 (comment)
  • The section of the traefik docs uses the non-existent example-author/example plugin - should this be changed to traefik/plugindemo as well?
  • Change fetchTraefikPlugin docs example to fetch the traefik demo plugin

Comment on lines +1075 to +1120
# Building a Traefik plugin hosted on `plugins.traefik.io`

The following recipe shows how to use `fetchTraefikPlugin` to fetch the `geoblock` Traefik plugin at version `0.3.3`:

```nix
{ fetchTraefikPlugin }:
fetchTraefikPlugin {
plugin = "geoblock";
owner = "PascalMinder";
version = "0.3.3";
hash = "sha256-gLhihjsBJEKGzpIwWzu/zmvLJbqnqXsF8ZiJWWKwDIA=";
}
```

After building the recipe, the derivation output will set up the appropriate paths expected by Traefik:

```shell
$ nix-build
(output removed for clarity)
/nix/store/m68kmlay1vdjzqjq7144r6ra885fd8l8-geoblock-0.3.3

$ tree /nix/store/m68kmlay1vdjzqjq7144r6ra885fd8l8-geoblock-0.3.3
/nix/store/m68kmlay1vdjzqjq7144r6ra885fd8l8-geoblock-0.3.3
└── src
└── github.com
└── PascalMinder
└── geoblock
├── docker
│ ├── dev-geoblock
│ │ └── docker-compose.yml
│ └── traefik-config
│ ├── dynamic-configuration.yml
│ └── traefik.yml
├── lrucache
│ ├── lru.go
│ ├── lru_interface.go
│ └── lru_test.go
├── LICENSE
├── Makefile
├── geoblock.go
├── geoblock_test.go
├── go.mod
└── readme.md
```

::::

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use the demoplugin, that should be a pretty stable example which won't look out of place in a few years. There's a fetch example in my latest PR comment with the right parameters you can steal, but the tree will need to be regenerated

Comment on lines +171 to +173
+ The Traefik module has been refactored to allow new ways to deploy the install and routing configuration files, as well as nixpkgs packaged plugins. See [Migrating traefik for pre 26.11 configurations](#module-services-traefik-migrating-to-26.11).
+
>>>>>>> conflict 1 of 1 ends

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
+ The Traefik module has been refactored to allow new ways to deploy the install and routing configuration files, as well as nixpkgs packaged plugins. See [Migrating traefik for pre 26.11 configurations](#module-services-traefik-migrating-to-26.11).
+
>>>>>>> conflict 1 of 1 ends

I have this in my new PR, you can drop it for this one

Comment on lines +265 to +276
"module-services-traefik-usage": [
"index.html#module-services-traefik-usage"
],
"module-services-traefik-usage-routing": [
"index.html#module-services-traefik-usage-routing"
],
"module-services-traefik-usage-install": [
"index.html#module-services-traefik-usage-install"
],
"module-services-traefik-migrating-to-26.11": [
"index.html#module-services-traefik-migrating-to-26.11"
],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"module-services-traefik-usage": [
"index.html#module-services-traefik-usage"
],
"module-services-traefik-usage-routing": [
"index.html#module-services-traefik-usage-routing"
],
"module-services-traefik-usage-install": [
"index.html#module-services-traefik-usage-install"
],
"module-services-traefik-migrating-to-26.11": [
"index.html#module-services-traefik-migrating-to-26.11"
],

Covered, can be dropped

Comment on lines +253 to +258
"module-services-traefik": [
"index.html#module-services-traefik"
],
"module-services-traefik-environment": [
"index.html#module-services-traefik-environment"
],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"module-services-traefik": [
"index.html#module-services-traefik"
],
"module-services-traefik-environment": [
"index.html#module-services-traefik-environment"
],

Covered, can be dropped

group = "fossorial";
dataDir = "${cfg.dataDir}/config/traefik";
staticConfigOptions = {
localPlugins = [ pkgs.fosrl-badger ];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
localPlugins = [ pkgs.fosrl-badger ];
localPluginPackages = [ pkgs.fosrl-badger ];

I renamed this attribute to distinguish it in my PR

meta = {
description = "Traefik plugin that handles authentication for Pangolin resources";
homepage = "https://plugins.traefik.io/plugins/676da7c6eaa878daeef9c7e9/fossorial-badger";
license = lib.licenses.mit;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
license = lib.licenses.mit;
license = [ lib.licenses.mit ];

There was a discussion about this on matrix a while back, a list is preferred

Comment on lines +16 to +18
maintainers = with lib.maintainers; [
jackr
];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
maintainers = with lib.maintainers; [
jackr
];
maintainers = [
lib.maintainers.jackr
];

meta = {
description = "Traefik plugin that denies requests based on country of origin";
homepage = "https://plugins.traefik.io/plugins/62d6ce04832ba9805374d62c/geo-block";
license = lib.licenses.asl20;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
license = lib.licenses.asl20;
license = [ lib.licenses.asl20 ];

Comment on lines +16 to +18
maintainers = with lib.maintainers; [
jackr
];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
maintainers = with lib.maintainers; [
jackr
];
maintainers = [
lib.maintainers.jackr
];

Minor gripe, I can't say that it actually makes a difference performance wise (I've never been able to get a clear answer) but the general sentiment is to avoid with unless necessary.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd have to double check, but I think I covered everything that needs to be added here in my PR comment. I would just drop everything while rebasing and copy the plugin stuff in afterwards to avoid merge conflicts. I can re-review once this is rebased.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2.status: merge conflict This PR has merge conflicts with the target branch 6.topic: fetch Fetchers (e.g. fetchgit, fetchsvn, ...) 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog This PR adds or changes release notes 8.has: documentation This PR adds or changes documentation 8.has: module (update) This PR changes an existing module in `nixos/` 8.has: package (new) This PR adds a new package 10.rebuild-darwin: 1-10 This PR causes between 1 and 10 packages to rebuild on Darwin. 10.rebuild-linux: 1-10 This PR causes between 1 and 10 packages to rebuild on Linux. 12.approvals: 1 This PR was reviewed and approved by one person.

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

nixos/modules/services/web-servers/traefik.nix: 'group' option not applied correctly

9 participants