Personnaliser les modules de Caddy avec Nix

Vincent Bernat

Caddy est un serveur web libre écrit en Go. Il gère automatiquement les certificats TLS et propose une syntaxe de configuration simple. Les utilisateurs peuvent étendre ses fonctionnalités via des modules pour ajouter, par exemple, la limitation de débit, la mise en cache et l’intégration à Docker.

Bien que Caddy soit disponible dans Nixpkgs, l’ajout de modules supplémentaires n’est pas simple1. Le processus de compilation nécessite un accès Internet, ce que Nix refuse pendant la compilation pour garantir la reproductibilité. Lorsqu’on essaie de construire la dérivation suivante en utilisant xcaddy, un outil pour compiler Caddy avec des modules supplémentaires, cela échoue avec cette erreur : dial tcp: lookup proxy.golang.org on [::1]:53: connection refused.

{ pkgs }:
pkgs.stdenv.mkDerivation {
  name = "caddy-with-xcaddy";
  nativeBuildInputs = with pkgs; [ go xcaddy cacert ];
  unpackPhase = "true";
  buildPhase =
    ''
      xcaddy build --with github.com/caddy-dns/powerdns@v1.0.1
    '';
  installPhase = ''
    mkdir -p $out/bin
    cp caddy $out/bin
  '';
}

Les dérivations à sortie fixe (fixed-output derivations) constituent une exception à cette règle et obtiennent un accès réseau pendant la compilation. Elles doivent spécifier leur hash de sortie. Par exemple, la fonction fetchurl produit une dérivation à sortie fixe :

{ stdenv, fetchurl }:
stdenv.mkDerivation rec {
  pname = "hello";
  version = "2.12.1";
  src = fetchurl {
    url = "mirror://gnu/hello/hello-${version}.tar.gz";
    hash = "sha256-jZkUKv2SV28wsM18tCqNxoCZmLxdYH2Idh9RLibH2yA=";
  };
}

Pour créer une dérivation à sortie fixe, vous devez définir l’attribut outputHash. L’exemple ci-dessous montre comment obtenir le code source de Caddy, avec certains modules activés, comme une dérivation à sortie fixe en utilisant xcaddy et go mod vendor.

pkgs.stdenvNoCC.mkDerivation rec {
  pname = "caddy-src-with-xcaddy";
  version = "2.8.4";
  nativeBuildInputs = with pkgs; [ go xcaddy cacert ];
  unpackPhase = "true";
  buildPhase =
    ''
      export GOCACHE=$TMPDIR/go-cache
      export GOPATH="$TMPDIR/go"
      XCADDY_SKIP_BUILD=1 TMPDIR="$PWD" \
        xcaddy build v${version} --with github.com/caddy-dns/powerdns@v1.0.1
      (cd buildenv* && go mod vendor)
    '';
  installPhase = ''
    mv buildenv* $out
  '';

  outputHash = "sha256-F/jqR4iEsklJFycTjSaW8B/V3iTGqqGOzwYBUXxRKrc=";
  outputHashAlgo = "sha256";
  outputHashMode = "recursive";
}

Avec une dérivation à sortie fixe, c’est à nous de nous assurer que la sortie est toujours la même :

  • xcaddy ne pas compile le programme et conserve le code source2
  • nous spécifions la version de Caddy que nous voulons construire
  • nous spécifions la version de chaque module demandé

Vous pouvez utiliser cette dérivation pour remplacer l’attribut src dans pkgs.caddy :

pkgs.caddy.overrideAttrs (prev: {
  src = pkgs.stdenvNoCC.mkDerivation { /* ... */ };
  vendorHash = null;
  subPackages = [ "." ];
});

Consultez l’exemple complet dans le dépôt GitHub. Pour une intégration dans un Flake, vous pouvez utiliser github:vincentbernat/caddy-nix comme surcouche à Nixpkgs :

{
  inputs = {
    nixpkgs.url = "nixpkgs";
    flake-utils.url = "github:numtide/flake-utils";
    caddy.url = "github:vincentbernat/caddy-nix";
  };
  outputs = { self, nixpkgs, flake-utils, caddy }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = import nixpkgs {
          inherit system;
          overlays = [ caddy.overlays.default ];
        };
      in
      {
        packages = {
          default = pkgs.caddy.withPlugins {
            plugins = [ "github.com/caddy-dns/powerdns@v1.0.1" ];
            hash = "sha256-F/jqR4iEsklJFycTjSaW8B/V3iTGqqGOzwYBUXxRKrc=";
          };
        };
      });
}

Mise à jour (11.2024)

Cela ne fonctionne pas avec Nixpkgs 24.05 car cette modification est nécessaire pour pouvoir changer la valeur de l’attribut vendorHash.


  1. C’est une demande depuis un certain temps. Une solution proposée a été rejetée. Celle décrite dans cet article est un peu différente et je l’ai proposée en remplacement. ↩︎

  2. Ce n’est pas parfait : si le code source produit par xcaddy change, le hash changerait et la compilation échouerait. ↩︎