Merge pull request #217536 from sephii/caddy-reload

nixos/caddy: add support for reload
This commit is contained in:
Emily 2023-07-04 22:57:24 +02:00 committed by GitHub
commit 3a79936b45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 8 deletions

View file

@ -64,6 +64,8 @@
- `spamassassin` no longer supports the `Hashcash` module. The module needs to be removed from the `loadplugin` list if it was copied over from the default `initPreConf` option. - `spamassassin` no longer supports the `Hashcash` module. The module needs to be removed from the `loadplugin` list if it was copied over from the default `initPreConf` option.
- The Caddy module gained a new option named `services.caddy.enableReload` which is enabled by default. It allows reloading the service instead of restarting it, if only a config file has changed. This option must be disabled if you have turned off the [Caddy admin API](https://caddyserver.com/docs/caddyfile/options#admin). If you keep this option enabled, you should consider setting [`grace_period`](https://caddyserver.com/docs/caddyfile/options#grace-period) to a non-infinite value to prevent Caddy from delaying the reload indefinitely.
## Other Notable Changes {#sec-release-23.11-notable-changes} ## Other Notable Changes {#sec-release-23.11-notable-changes}
- The Cinnamon module now enables XDG desktop integration by default. If you are experiencing collisions related to xdg-desktop-portal-gtk you can safely remove `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];` from your NixOS configuration. - The Cinnamon module now enables XDG desktop integration by default. If you are experiencing collisions related to xdg-desktop-portal-gtk you can safely remove `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];` from your NixOS configuration.

View file

@ -41,6 +41,10 @@ let
in in
"${if pkgs.stdenv.buildPlatform == pkgs.stdenv.hostPlatform then Caddyfile-formatted else Caddyfile}/Caddyfile"; "${if pkgs.stdenv.buildPlatform == pkgs.stdenv.hostPlatform then Caddyfile-formatted else Caddyfile}/Caddyfile";
etcConfigFile = "caddy/caddy_config";
configPath = "/etc/${etcConfigFile}";
acmeHosts = unique (catAttrs "useACMEHost" acmeVHosts); acmeHosts = unique (catAttrs "useACMEHost" acmeVHosts);
mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix; mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix;
@ -155,11 +159,16 @@ in
description = lib.mdDoc '' description = lib.mdDoc ''
Override the configuration file used by Caddy. By default, Override the configuration file used by Caddy. By default,
NixOS generates one automatically. NixOS generates one automatically.
The configuration file is exposed at {file}`${configPath}`.
''; '';
}; };
adapter = mkOption { adapter = mkOption {
default = null; default = if (builtins.baseNameOf cfg.configFile) == "Caddyfile" then "caddyfile" else null;
defaultText = literalExpression ''
if (builtins.baseNameOf cfg.configFile) == "Caddyfile" then "caddyfile" else null
'';
example = literalExpression "nginx"; example = literalExpression "nginx";
type = with types; nullOr str; type = with types; nullOr str;
description = lib.mdDoc '' description = lib.mdDoc ''
@ -275,6 +284,21 @@ in
''; '';
}; };
enableReload = mkOption {
default = true;
type = types.bool;
description = lib.mdDoc ''
Reload Caddy instead of restarting it when configuration file changes.
Note that enabling this option requires the [admin API](https://caddyserver.com/docs/caddyfile/options#admin)
to not be turned off.
If you enable this option, consider setting [`grace_period`](https://caddyserver.com/docs/caddyfile/options#grace-period)
to a non-infinite value in {option}`services.caddy.globalConfig`
to prevent Caddy waiting for active connections to finish,
which could delay the reload essentially indefinitely.
'';
};
}; };
# implementation # implementation
@ -311,13 +335,16 @@ in
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
startLimitIntervalSec = 14400; startLimitIntervalSec = 14400;
startLimitBurst = 10; startLimitBurst = 10;
reloadTriggers = optional cfg.enableReload cfg.configFile;
serviceConfig = { serviceConfig = let
runOptions = ''--config ${configPath} ${optionalString (cfg.adapter != null) "--adapter ${cfg.adapter}"}'';
in {
# https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart= # https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
# If the empty string is assigned to this option, the list of commands to start is reset, prior assignments of this option will have no effect. # If the empty string is assigned to this option, the list of commands to start is reset, prior assignments of this option will have no effect.
ExecStart = [ "" ''${cfg.package}/bin/caddy run --config ${cfg.configFile} ${optionalString (cfg.adapter != null) "--adapter ${cfg.adapter}"} ${optionalString cfg.resume "--resume"}'' ]; ExecStart = [ "" ''${cfg.package}/bin/caddy run ${runOptions} ${optionalString cfg.resume "--resume"}'' ];
ExecReload = [ "" ''${cfg.package}/bin/caddy reload --config ${cfg.configFile} ${optionalString (cfg.adapter != null) "--adapter ${cfg.adapter}"} --force'' ]; # Validating the configuration before applying it ensures well get a proper error that will be reported when switching to the configuration
ExecStartPre = ''${cfg.package}/bin/caddy validate --config ${cfg.configFile} ${optionalString (cfg.adapter != null) "--adapter ${cfg.adapter}"}''; ExecReload = [ "" ''${cfg.package}/bin/caddy reload ${runOptions} --force'' ];
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
ReadWriteDirectories = cfg.dataDir; ReadWriteDirectories = cfg.dataDir;
@ -353,5 +380,6 @@ in
in in
listToAttrs certCfg; listToAttrs certCfg;
environment.etc.${etcConfigFile}.source = cfg.configFile;
}; };
} }

View file

@ -20,6 +20,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
} }
} }
''; '';
services.caddy.enableReload = true;
specialisation.etag.configuration = { specialisation.etag.configuration = {
services.caddy.extraConfig = lib.mkForce '' services.caddy.extraConfig = lib.mkForce ''
@ -54,9 +55,9 @@ import ./make-test-python.nix ({ pkgs, ... }: {
testScript = { nodes, ... }: testScript = { nodes, ... }:
let let
etagSystem = "${nodes.webserver.config.system.build.toplevel}/specialisation/etag"; etagSystem = "${nodes.webserver.system.build.toplevel}/specialisation/etag";
justReloadSystem = "${nodes.webserver.config.system.build.toplevel}/specialisation/config-reload"; justReloadSystem = "${nodes.webserver.system.build.toplevel}/specialisation/config-reload";
multipleConfigs = "${nodes.webserver.config.system.build.toplevel}/specialisation/multiple-configs"; multipleConfigs = "${nodes.webserver.system.build.toplevel}/specialisation/multiple-configs";
in in
'' ''
url = "http://localhost/example.html" url = "http://localhost/example.html"
@ -96,6 +97,8 @@ import ./make-test-python.nix ({ pkgs, ... }: {
"${justReloadSystem}/bin/switch-to-configuration test >&2" "${justReloadSystem}/bin/switch-to-configuration test >&2"
) )
webserver.wait_for_open_port(8080) webserver.wait_for_open_port(8080)
webserver.fail("journalctl -u caddy | grep -q -i stopped")
webserver.succeed("journalctl -u caddy | grep -q -i reloaded")
with subtest("multiple configs are correctly merged"): with subtest("multiple configs are correctly merged"):
webserver.succeed( webserver.succeed(