parent
83fe089c5e
commit
98833bdc6f
14 changed files with 367 additions and 46 deletions
modules/caddy-plus
104
modules/caddy-plus/default.nix
Normal file
104
modules/caddy-plus/default.nix
Normal 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;
|
||||
};
|
||||
}
|
43
modules/caddy-plus/sub-dir-options.nix
Normal file
43
modules/caddy-plus/sub-dir-options.nix
Normal 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`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
52
modules/caddy-plus/sub-domain-options.nix
Normal file
52
modules/caddy-plus/sub-domain-options.nix
Normal 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`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
51
modules/caddy-plus/vhost-options.nix
Normal file
51
modules/caddy-plus/vhost-options.nix
Normal 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.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue