feat(caddy): move to new package
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
83fe089c5e
commit
98833bdc6f
14 changed files with 367 additions and 19 deletions
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
buildApp,
|
buildApp,
|
||||||
callPackage,
|
callPackage,
|
||||||
|
go,
|
||||||
nix-update,
|
nix-update,
|
||||||
nodejs_latest,
|
nodejs_latest,
|
||||||
prefetch-npm-deps,
|
prefetch-npm-deps,
|
||||||
|
@ -11,6 +12,7 @@ buildApp {
|
||||||
npmDepsHash = "sha256-TU7HoUGeCXUKwm2s4Np6NQahk6gWBN9WC5vob3zw7Ns=";
|
npmDepsHash = "sha256-TU7HoUGeCXUKwm2s4Np6NQahk6gWBN9WC5vob3zw7Ns=";
|
||||||
|
|
||||||
runtimeInputs = [
|
runtimeInputs = [
|
||||||
|
go
|
||||||
nix-update
|
nix-update
|
||||||
nodejs_latest
|
nodejs_latest
|
||||||
prefetch-npm-deps
|
prefetch-npm-deps
|
||||||
|
|
|
@ -10,6 +10,7 @@ import updateNodeModules from './node-modules';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
runNixUpdate,
|
runNixUpdate,
|
||||||
|
updateCaddyPlugins,
|
||||||
updateCustomPackage,
|
updateCustomPackage,
|
||||||
updateVuetorrent,
|
updateVuetorrent,
|
||||||
} from './misc';
|
} from './misc';
|
||||||
|
@ -66,6 +67,10 @@ const main = async() => {
|
||||||
console.log(runNixUpdate('homepage'));
|
console.log(runNixUpdate('homepage'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args['cp'] || args['caddy-plugins']) {
|
||||||
|
console.log(updateCaddyPlugins());
|
||||||
|
}
|
||||||
|
|
||||||
if (args['a'] || args['all']) {
|
if (args['a'] || args['all']) {
|
||||||
// Update this first because of nix run cmd
|
// Update this first because of nix run cmd
|
||||||
const firefoxOutput = updateFirefoxAddons();
|
const firefoxOutput = updateFirefoxAddons();
|
||||||
|
@ -93,6 +98,11 @@ const main = async() => {
|
||||||
console.log(vuetorrentOutput);
|
console.log(vuetorrentOutput);
|
||||||
|
|
||||||
|
|
||||||
|
const caddyPluginsOutput = updateCaddyPlugins();
|
||||||
|
|
||||||
|
console.log(caddyPluginsOutput);
|
||||||
|
|
||||||
|
|
||||||
// This doesn't need to be added to commit msgs
|
// This doesn't need to be added to commit msgs
|
||||||
console.log(updateCustomPackage(
|
console.log(updateCustomPackage(
|
||||||
'scopedPackages.x86_64-linux.lovelace-components.custom-sidebar',
|
'scopedPackages.x86_64-linux.lovelace-components.custom-sidebar',
|
||||||
|
@ -144,6 +154,9 @@ const main = async() => {
|
||||||
if (vuetorrentOutput.length > 5) {
|
if (vuetorrentOutput.length > 5) {
|
||||||
output.push(`Misc Sources:\n${indentOutput(vuetorrentOutput)}\n\n`);
|
output.push(`Misc Sources:\n${indentOutput(vuetorrentOutput)}\n\n`);
|
||||||
}
|
}
|
||||||
|
if (caddyPluginsOutput.length > 5) {
|
||||||
|
output.push(`Caddy Plugins:\n${indentOutput(caddyPluginsOutput)}\n\n`);
|
||||||
|
}
|
||||||
if (nixUpdateOutputs.length > 5) {
|
if (nixUpdateOutputs.length > 5) {
|
||||||
output.push(`nix-update executions:\n${indentOutput(nixUpdateOutputs)}\n`);
|
output.push(`nix-update executions:\n${indentOutput(nixUpdateOutputs)}\n`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { writeFileSync } from 'node:fs';
|
import { writeFileSync } from 'node:fs';
|
||||||
import { spawnSync } from 'node:child_process';
|
import { spawnSync } from 'node:child_process';
|
||||||
|
|
||||||
import { parseFetchurl } from './lib';
|
import { parseFetchurl, replaceInFile } from './lib';
|
||||||
|
|
||||||
|
|
||||||
/* Constants */
|
/* Constants */
|
||||||
|
@ -71,3 +71,78 @@ export const runNixUpdate = (
|
||||||
stderr: execution.stderr.toString(),
|
stderr: execution.stderr.toString(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const genPluginsText = (
|
||||||
|
plugins: Record<string, { url: string, version: string }>,
|
||||||
|
) => `# This file was autogenerated. DO NOT EDIT!
|
||||||
|
{
|
||||||
|
plugins = {
|
||||||
|
${Object.entries(plugins)
|
||||||
|
.map(([key, value]) => `
|
||||||
|
${key} = {
|
||||||
|
url = "${value.url}";
|
||||||
|
version = "${value.version}";
|
||||||
|
};
|
||||||
|
`)
|
||||||
|
.join('')}
|
||||||
|
};
|
||||||
|
|
||||||
|
hash = "";
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const updateCaddyPlugins = () => {
|
||||||
|
let updates = '';
|
||||||
|
const dir = `${FLAKE}/configurations/cluster/modules/caddy`;
|
||||||
|
|
||||||
|
// Setup workspace
|
||||||
|
spawnSync(
|
||||||
|
[
|
||||||
|
'rm -rf /tmp/update-caddy',
|
||||||
|
'mkdir -p /tmp/update-caddy',
|
||||||
|
'cd /tmp/update-caddy || exit 1',
|
||||||
|
'go mod init temp',
|
||||||
|
].join('; '),
|
||||||
|
[],
|
||||||
|
{ shell: true, cwd: '/tmp' },
|
||||||
|
);
|
||||||
|
|
||||||
|
const plugins = JSON.parse(spawnSync('nix',
|
||||||
|
['eval', '-f', `${dir}/plugins.nix`, '--json'],
|
||||||
|
{ shell: true }).stdout.toString()).plugins as Record<string, { url: string, version: string }>;
|
||||||
|
|
||||||
|
// Get most recent versions of plugins
|
||||||
|
Object.entries(plugins).forEach(([key, value]) => {
|
||||||
|
const NEW_VERSION = spawnSync([
|
||||||
|
'go mod init temp > /dev/null',
|
||||||
|
`go get ${value.url} > /dev/null`,
|
||||||
|
`grep '${value.url}' go.mod`,
|
||||||
|
].join('; '), [], { shell: true, cwd: '/tmp/update-caddy' })
|
||||||
|
.stdout
|
||||||
|
.toString()
|
||||||
|
.trim()
|
||||||
|
.replace(' // indirect', '')
|
||||||
|
.split(' ')[1];
|
||||||
|
|
||||||
|
if (plugins[key].version !== NEW_VERSION) {
|
||||||
|
updates += `${key}: ${plugins[key].version} -> ${NEW_VERSION}`;
|
||||||
|
plugins[key].version = NEW_VERSION;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
writeFileSync(`${dir}/plugins.nix`, genPluginsText(plugins));
|
||||||
|
|
||||||
|
// Get new hash
|
||||||
|
const caddyPkgAttr = 'nixosConfigurations.thingone.config.services.caddy.package';
|
||||||
|
|
||||||
|
const NEW_HASH = spawnSync(
|
||||||
|
`nix build "$FLAKE#${caddyPkgAttr}" |& sed -n 's/.*got: *//p'`,
|
||||||
|
[],
|
||||||
|
{ shell: true },
|
||||||
|
).stdout.toString().trim();
|
||||||
|
|
||||||
|
replaceInFile(/hash = ".*";/, `hash = "${NEW_HASH}";`, `${dir}/plugins.nix`);
|
||||||
|
|
||||||
|
return updates;
|
||||||
|
};
|
||||||
|
|
|
@ -1,36 +1,37 @@
|
||||||
{
|
{
|
||||||
caddy-plugins,
|
|
||||||
config,
|
config,
|
||||||
|
lib,
|
||||||
mainUser,
|
mainUser,
|
||||||
pkgs,
|
pkgs,
|
||||||
|
self,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
|
inherit (lib) attrValues;
|
||||||
|
|
||||||
inherit (config.sops) secrets;
|
inherit (config.sops) secrets;
|
||||||
inherit (config.networking) hostName;
|
inherit (config.networking) hostName;
|
||||||
|
|
||||||
caddy = caddy-plugins.packages.${pkgs.system}.default;
|
|
||||||
in {
|
in {
|
||||||
imports = [caddy-plugins.nixosModules.default];
|
imports = [self.nixosModules.caddy-plus];
|
||||||
|
|
||||||
# User stuff
|
|
||||||
environment.systemPackages = [caddy];
|
|
||||||
users.users.${mainUser}.extraGroups = ["caddy"];
|
users.users.${mainUser}.extraGroups = ["caddy"];
|
||||||
|
|
||||||
boot.kernel.sysctl."net.ipv4.ip_nonlocal_bind" = 1;
|
boot.kernel.sysctl."net.ipv4.ip_nonlocal_bind" = 1;
|
||||||
|
|
||||||
systemd.services.caddy.serviceConfig = {
|
systemd.services.caddy.serviceConfig = {
|
||||||
EnvironmentFile = secrets.caddy-cloudflare.path;
|
EnvironmentFile = secrets.caddy-cloudflare.path;
|
||||||
|
|
||||||
# For some reason the service
|
|
||||||
# doesn't shutdown normally
|
|
||||||
KillSignal = "SIGKILL";
|
|
||||||
RestartKillSignal = "SIGKILL";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.caddy = {
|
services.caddy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableReload = false;
|
enableReload = false;
|
||||||
package = caddy;
|
|
||||||
|
package = let
|
||||||
|
pluginsInfo = import ./plugins.nix;
|
||||||
|
in
|
||||||
|
pkgs.caddy.withPlugins {
|
||||||
|
plugins = map (x: "${x.url}@${x.version}") (attrValues pluginsInfo.plugins);
|
||||||
|
inherit (pluginsInfo) hash;
|
||||||
|
};
|
||||||
|
|
||||||
virtualHosts = let
|
virtualHosts = let
|
||||||
clusterIP = config.services.pcsd.virtualIps.caddy-vip.ip;
|
clusterIP = config.services.pcsd.virtualIps.caddy-vip.ip;
|
11
configurations/cluster/modules/caddy/plugins.nix
Normal file
11
configurations/cluster/modules/caddy/plugins.nix
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# This file was autogenerated. DO NOT EDIT!
|
||||||
|
{
|
||||||
|
plugins = {
|
||||||
|
cloudflare = {
|
||||||
|
url = "github.com/caddy-dns/cloudflare";
|
||||||
|
version = "v0.0.0-20240703190432-89f16b99c18e";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
hash = "sha256-WGV/Ve7hbVry5ugSmTYWDihoC9i+D3Ct15UKgdpYc9U=";
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
{...}: {
|
{...}: {
|
||||||
imports = [
|
imports = [
|
||||||
./blocky.nix
|
./blocky.nix
|
||||||
./caddy.nix
|
./caddy
|
||||||
./headscale
|
./headscale
|
||||||
./nfs-client.nix
|
./nfs-client.nix
|
||||||
./pcsd.nix
|
./pcsd.nix
|
||||||
|
|
BIN
flake.lock
BIN
flake.lock
Binary file not shown.
BIN
flake.nix
BIN
flake.nix
Binary file not shown.
|
@ -73,11 +73,6 @@ let
|
||||||
owner = "matt1432";
|
owner = "matt1432";
|
||||||
repo = "nixos-pcsd";
|
repo = "nixos-pcsd";
|
||||||
};
|
};
|
||||||
|
|
||||||
caddy-plugins = mkDep {
|
|
||||||
owner = "matt1432";
|
|
||||||
repo = "nixos-caddy-cloudflare";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
serviviInputs = {
|
serviviInputs = {
|
||||||
|
|
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.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ self: {
|
||||||
base = import ./base self;
|
base = import ./base self;
|
||||||
base-droid = import ./base/default-droid.nix self;
|
base-droid = import ./base/default-droid.nix self;
|
||||||
borgbackup = import ./borgbackup;
|
borgbackup = import ./borgbackup;
|
||||||
|
caddy-plus = import ./caddy-plus self;
|
||||||
desktop = import ./desktop self;
|
desktop = import ./desktop self;
|
||||||
docker = import ./docker self.inputs.khepri;
|
docker = import ./docker self.inputs.khepri;
|
||||||
esphome-plus = import ./esphome-plus;
|
esphome-plus = import ./esphome-plus;
|
||||||
|
|
Loading…
Reference in a new issue