blog/source/_posts/caddy-v2-nixos.md

5.1 KiB

title excerpt date updated tags
Running Caddy 2 in NixOS 20.03 Use stable v2 instead of beta release 2020-05-24 2020-11-10
server
caddy
nixos

Applies to 20.03 or older only

In NixOS 20.03, caddy package is still version 1.0.4 and caddy2 package uses version 2.0 beta 10. The package maintainer plans to upgrade the caddy package to v2 in 20.09, while retaining v1 as caddy1. In the meantime, I show you how to run v2 stable release by using the caddy2 package from the unstable channel; note that this only affects caddy2 package, all other packages still use the stable nixos channel.

(Execute commands with "sudo" privilege)

Add the unstable channel:

$ nix-channel --add https://nixos.org/channels/nixos-unstable unstable
$ nix-channel --update unstable

Add caddyTwo.nix file (this example stores the file in "/etc/caddy"):

{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.caddyTwo;

  # v2-specific options
  isCaddy2 = versionAtLeast cfg.package.version "2.0";
in {
  options.services.caddyTwo = {
    enable = mkEnableOption "Caddy web server";

    config = mkOption {
      default = "/etc/caddy/Caddyfile";
      type = types.str;
      description = "Path to Caddyfile";
    };

    dataDir = mkOption {
      default = "/var/lib/caddy";
      type = types.path;
      description = ''
        The data directory, for storing certificates. Before 17.09, this
        would create a .caddy directory. With 17.09 the contents of the
        .caddy directory are in the specified data directory instead.
      '';
    };

    package = mkOption {
      default = pkgs.caddy;
      defaultText = "pkgs.caddy";
      type = types.package;
      description = "Caddy package to use.";
    };

    adapter = mkOption {
      default = "caddyfile";
      example = "nginx";
      type = types.str;
      description = ''
        Name of the config adapter to use. Not applicable to Caddy v1.
        See https://caddyserver.com/docs/config-adapters for the full list.
      '';
    };
  };

  config = mkIf cfg.enable {
    systemd.services.caddy = {
      description = "Caddy web server";
      after = [ "network-online.target" ];
      wantedBy = [ "multi-user.target" ];
      environment = mkIf (versionAtLeast config.system.stateVersion "17.09" && !isCaddy2)
        { CADDYPATH = cfg.dataDir; };
      serviceConfig = {
        ExecStart = if isCaddy2 then ''
          ${cfg.package}/bin/caddy run --config ${cfg.config} --adapter ${cfg.adapter}
        '' else ''
          ${cfg.package}/bin/caddy -root=/var/tmp -conf=${cfg.config}
        '';
        ExecReload =
          if isCaddy2 then
            "${cfg.package}/bin/caddy reload --config ${cfg.config} --adapter ${cfg.adapter}"
          else
            "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
        Type = "simple";
        User = "caddy";
        Group = "caddy";
        Restart = "on-abnormal";
        StartLimitIntervalSec = 14400;
        StartLimitBurst = 10;
        NoNewPrivileges = true;
        LimitNPROC = 512;
        LimitNOFILE = 1048576;
        PrivateTmp = true;
        PrivateDevices = true;
        ProtectHome = true;
        ProtectSystem = "full";
        ReadWriteDirectories = cfg.dataDir;
        KillMode = "mixed";
        KillSignal = "SIGQUIT";
        TimeoutStopSec = "5s";
        # Remove two options below if caddy doesn't listen on port <1024
        AmbientCapabilities = "cap_net_bind_service";
        CapabilityBoundingSet = "cap_net_bind_service";
      };
    };

    users.users.caddy = {
      home = cfg.dataDir;
      createHome = true;
    };

    users.groups.caddy = {
      members = [ "caddy" ];
    };
  };
}

Enable caddy service in "configuration.nix":

  require = [ /etc/caddy/caddyTwo.nix ];
  services.caddyTwo = {
    enable = true;
    package = unstable.caddy2
    config = "/path/to/caddyFile";
    adapter = "caddyfile";
  };

If you use other config formats, modify the following options:

  services.caddyTwo = {
    config = "/path/to/yaml";
    adapter = "yaml";
  };

Package maintainer is updating the caddy package to v2 in #86686, once that pull request is merged, update the following option:

  services.caddyTwo = {
    package = unstable.caddy;
  };

Import unstable channel:

{ config, pkgs, ... }:

let
  unstable = import <unstable> {};
in
{
  # existing options

  require = [ /etc/caddy/caddyTwo.nix ];
  services.caddyTwo = {
    enable = true;
    package = unstable.caddy2;
    config = "/path/to/caddyFile";
    adapter = "caddyfile";
  };
}

Runs a rebuild and check the status:

$ nixos-rebuild switch
$ systemctl status caddy

To revert to v1, remove package and adapter options:

  services.caddyTwo = {
    enable = true;
    config = "/path/to/caddyFile";
  };