feat(caddy): move to new package

This commit is contained in:
matt1432 2024-12-29 01:28:33 -05:00
parent 83fe089c5e
commit 98833bdc6f
14 changed files with 367 additions and 46 deletions

View file

@ -0,0 +1,104 @@
self: {
config,
lib,
pkgs,
...
}: let
inherit (lib) types;
inherit (lib.attrsets) attrValues;
inherit (lib.modules) mkIf mkOverride;
inherit (lib.options) mkOption;
inherit (lib.strings) concatMapStringsSep concatStringsSep optionalString stringLength substring toUpper;
cfg = config.services.caddy;
capitalize = str:
toUpper (substring 0 1 str)
+ substring 1 (stringLength str) str;
mkSubDirConf = subOpts:
optionalString (subOpts.reverseProxy != null) (
if subOpts.experimental
then ''
${subOpts.extraConfig}
redir /${subOpts.subDirName} /${subOpts.subDirName}/
route /${subOpts.subDirName}/* {
uri strip_prefix ${subOpts.subDirName}
reverse_proxy ${subOpts.reverseProxy} {
header_up X-Real-IP {remote}
header_up X-${capitalize (subOpts.subDirName)}-Base "/${subOpts.subDirName}"
}
}
''
else ''
${subOpts.extraConfig}
redir /${subOpts.subDirName} /${subOpts.subDirName}/
reverse_proxy /${subOpts.subDirName}/* {
to ${subOpts.reverseProxy}
}
''
);
mkSubDomainConf = hostName: subOpts: ''
@${subOpts.subDomainName} host ${subOpts.subDomainName}.${hostName}
handle @${subOpts.subDomainName} {
${subOpts.extraConfig}
${optionalString (subOpts.reverseProxy != null) "reverse_proxy ${subOpts.reverseProxy}"}
${concatMapStringsSep "\n" mkSubDirConf (attrValues subOpts.subDirectories)}
}
'';
mkVHostConf = hostOpts: let
sslCertDir = config.security.acme.certs.${hostOpts.useACMEHost}.directory;
in ''
${hostOpts.hostName} ${concatStringsSep " " hostOpts.serverAliases} {
${optionalString (hostOpts.listenAddresses != []) "bind ${concatStringsSep " " hostOpts.listenAddresses}"}
${optionalString (hostOpts.useACMEHost != null) "tls ${sslCertDir}/cert.pem ${sslCertDir}/key.pem"}
log {
${hostOpts.logFormat}
}
${hostOpts.extraConfig}
${optionalString (hostOpts.reverseProxy != null) "reverse_proxy ${hostOpts.reverseProxy}"}
${concatMapStringsSep "\n" mkSubDirConf (attrValues hostOpts.subDirectories)}
${concatMapStringsSep "\n" (mkSubDomainConf hostOpts.hostName) (attrValues hostOpts.subDomains)}
}
'';
settingsFormat = pkgs.formats.json {};
configFile =
if cfg.settings != {}
then settingsFormat.generate "caddy.json" cfg.settings
else let
Caddyfile = pkgs.writeTextDir "Caddyfile" ''
{
${cfg.globalConfig}
}
${cfg.extraConfig}
${concatMapStringsSep "\n" mkVHostConf (attrValues cfg.virtualHosts)}
'';
Caddyfile-formatted = pkgs.runCommand "Caddyfile-formatted" {nativeBuildInputs = [cfg.package];} ''
mkdir -p $out
cp --no-preserve=mode ${Caddyfile}/Caddyfile $out/Caddyfile
caddy fmt --overwrite $out/Caddyfile
'';
in "${
if pkgs.stdenv.buildPlatform == pkgs.stdenv.hostPlatform
then Caddyfile-formatted
else Caddyfile
}/Caddyfile";
in {
options.services.caddy.virtualHosts = mkOption {
type = types.attrsOf (types.submodule (import ./vhost-options.nix {inherit cfg;}));
};
# implementation
config = mkIf cfg.enable {
services.caddy.configFile = mkOverride 80 configFile;
};
}

View file

@ -0,0 +1,43 @@
{cfg}: {
lib,
name,
...
}: let
inherit (lib) mkOption types;
in {
options = {
subDirName = mkOption {
type = types.str;
default = name;
description = "The sub directory name to handle.";
};
reverseProxy = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Option to give the parameters to a simple "reverse_proxy" command
appended after extraConfig.
'';
};
experimental = mkOption {
type = types.bool;
default = false;
description = ''
Specify if the app being proxied expects to be under a subdirectory.
If it doesn't, we can attempt to circumvent that but it is not guaranteed
to work for every app.
'';
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Additional lines of configuration appended to this sub domain in the
automatically generated `Caddyfile`.
'';
};
};
}

View file

@ -0,0 +1,52 @@
{cfg}: {
lib,
name,
...
}: let
inherit (lib) literalExpression mkOption types;
in {
options = {
subDomainName = mkOption {
type = types.str;
default = name;
description = "The sub domain name to handle.";
};
reverseProxy = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Option to give the parameters to a simple "reverse_proxy" command
appended after extraConfig.
'';
};
subDirectories = mkOption {
type = types.attrsOf (types.submodule (import ./sub-dir-options.nix {inherit cfg;}));
default = {};
example = literalExpression ''
{
headscale = {
appSupport = false;
reverseProxy = "localhost:8080";
extraConfig = '''
encode gzip
''';
};
};
'';
description = ''
Declarative specification of a subdomain's subdirectories served by Caddy.
'';
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Additional lines of configuration appended to this sub domain in the
automatically generated `Caddyfile`.
'';
};
};
}

View file

@ -0,0 +1,51 @@
{cfg}: {lib, ...}: let
inherit (lib) literalExpression mkOption types;
in {
options = {
reverseProxy = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Option to give the parameters to a simple "reverse_proxy" command
appended after extraConfig.
'';
};
subDomains = mkOption {
type = types.attrsOf (types.submodule (import ./sub-domain-options.nix {inherit cfg;}));
default = {};
example = literalExpression ''
{
headscale = {
reverseProxy = "localhost:8080";
extraConfig = '''
encode gzip
''';
}
};
'';
description = ''
Declarative specification of a virtual hosts subdomain served by Caddy.
'';
};
subDirectories = mkOption {
type = types.attrsOf (types.submodule (import ./sub-dir-options.nix {inherit cfg;}));
default = {};
example = literalExpression ''
{
headscale = {
appSupport = false;
reverseProxy = "localhost:8080";
extraConfig = '''
encode gzip
''';
};
};
'';
description = ''
Declarative specification of a subdomain's subdirectories served by Caddy.
'';
};
};
}