Compare commits
7 commits
dfd28d637a
...
c45ed013ed
| Author | SHA1 | Date | |
|---|---|---|---|
| c45ed013ed | |||
| c809de6e80 | |||
| 160bb60ee6 | |||
| 3cc870fe8f | |||
| 1bfd0b9f42 | |||
| 6fe4bced45 | |||
| df70d61664 |
3 changed files with 150 additions and 12 deletions
|
|
@ -4,7 +4,7 @@
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
@health path /health-ping
|
@health path /health-ping
|
||||||
handle @health {
|
handle @health {
|
||||||
reverse_proxy localhost:8070
|
respond 200
|
||||||
}
|
}
|
||||||
|
|
||||||
handle {
|
handle {
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,16 @@
|
||||||
# dataDir — base directory for repo and data (default: /srv/<name>)
|
# dataDir — base directory for repo and data (default: /srv/<name>)
|
||||||
# readWritePaths — paths the server can write to at runtime (default: [])
|
# readWritePaths — paths the server can write to at runtime (default: [])
|
||||||
# afterServices — systemd units to wait for before building (default: ["forgejo.service"])
|
# afterServices — systemd units to wait for before building (default: ["forgejo.service"])
|
||||||
|
# preview.enable — TinyAuth-protected preview of this site (default: false)
|
||||||
|
# preview.branch — branch for preview (default: "develop")
|
||||||
|
# preview.domain — preview domain (default: 0<name>.ily.rs)
|
||||||
|
# preview.port — preview server port (required when static = false)
|
||||||
#
|
#
|
||||||
# remarks:
|
# remarks:
|
||||||
#
|
#
|
||||||
# - a listener is active on http://localhost:4323/hooks/${name}-rebuild for CD
|
# - a listener is active on http://localhost:4323/hooks/${name}-rebuild for CD
|
||||||
# Forgejo repo -> settings -> Webhooks -> Add webhook
|
# Forgejo repo -> settings -> Webhooks -> Add webhook
|
||||||
|
# - preview webhook: http://localhost:4323/hooks/${name}-preview-rebuild
|
||||||
|
|
||||||
{ ... }:
|
{ ... }:
|
||||||
let
|
let
|
||||||
|
|
@ -48,6 +53,7 @@ in
|
||||||
redirectDomains = [ "penfield.wynne.rs" ];
|
redirectDomains = [ "penfield.wynne.rs" ];
|
||||||
repo = "https://git.ily.rs/lew/penfield";
|
repo = "https://git.ily.rs/lew/penfield";
|
||||||
static = true;
|
static = true;
|
||||||
|
preview.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.site.record-generator = {
|
services.site.record-generator = {
|
||||||
|
|
|
||||||
154
modules/site.nix
154
modules/site.nix
|
|
@ -85,10 +85,32 @@ let
|
||||||
default = [ "forgejo.service" ];
|
default = [ "forgejo.service" ];
|
||||||
description = "Systemd units to wait for before building.";
|
description = "Systemd units to wait for before building.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
preview = {
|
||||||
|
enable = lib.mkEnableOption "TinyAuth-protected preview of this site";
|
||||||
|
|
||||||
|
branch = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "develop";
|
||||||
|
};
|
||||||
|
|
||||||
|
domain = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "0${name}.ily.rs";
|
||||||
|
description = "Preview domain. Defaults to 0<name>.ily.rs.";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.nullOr types.port;
|
||||||
|
default = null;
|
||||||
|
description = "Port for preview Node.js server. Required when parent static = false.";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
cfg = lib.filterAttrs (_: site: site.enable) config.services.site;
|
cfg = lib.filterAttrs (_: site: site.enable) config.services.site;
|
||||||
|
previewCfg = lib.filterAttrs (_: site: site.enable && site.preview.enable) config.services.site;
|
||||||
|
|
||||||
webhookPort = 4323;
|
webhookPort = 4323;
|
||||||
|
|
||||||
|
|
@ -113,7 +135,12 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
services.caddy.virtualHosts = mkMerge (mapAttrsToList (name: site:
|
assertions = mapAttrsToList (name: site: {
|
||||||
|
assertion = site.static || site.preview.port != null;
|
||||||
|
message = "services.site.${name}.preview.port is required when static = false and preview is enabled";
|
||||||
|
}) previewCfg;
|
||||||
|
|
||||||
|
services.caddy.virtualHosts = mkMerge ((mapAttrsToList (name: site:
|
||||||
{
|
{
|
||||||
${site.domain}.extraConfig = if site.static then ''
|
${site.domain}.extraConfig = if site.static then ''
|
||||||
root * ${site.dataDir}/repo/${site.buildOutputDir}
|
root * ${site.dataDir}/repo/${site.buildOutputDir}
|
||||||
|
|
@ -130,7 +157,33 @@ in
|
||||||
redir https://${site.domain}{uri} permanent
|
redir https://${site.domain}{uri} permanent
|
||||||
'';
|
'';
|
||||||
}) site.redirectDomains)
|
}) site.redirectDomains)
|
||||||
) cfg);
|
) cfg) ++ (mapAttrsToList (name: site:
|
||||||
|
let previewDataDir = "/srv/${name}-preview"; in {
|
||||||
|
${site.preview.domain}.extraConfig = if site.static then ''
|
||||||
|
@health path /health-ping
|
||||||
|
handle @health {
|
||||||
|
respond 200
|
||||||
|
}
|
||||||
|
handle {
|
||||||
|
import tinyauth
|
||||||
|
root * ${previewDataDir}/repo/${site.buildOutputDir}
|
||||||
|
encode zstd gzip
|
||||||
|
try_files {path} /index.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
'' else ''
|
||||||
|
@health path /health-ping
|
||||||
|
handle @health {
|
||||||
|
respond 200
|
||||||
|
}
|
||||||
|
handle {
|
||||||
|
import tinyauth
|
||||||
|
reverse_proxy localhost:${toString site.preview.port}
|
||||||
|
encode zstd gzip
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
) previewCfg));
|
||||||
|
|
||||||
systemd.services = mkMerge ((mapAttrsToList (name: site:
|
systemd.services = mkMerge ((mapAttrsToList (name: site:
|
||||||
let h = siteHelpers name site; in {
|
let h = siteHelpers name site; in {
|
||||||
|
|
@ -184,7 +237,63 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
) cfg) ++ [{
|
) cfg) ++ (mapAttrsToList (name: site:
|
||||||
|
let
|
||||||
|
h = siteHelpers name site;
|
||||||
|
previewDataDir = "/srv/${name}-preview";
|
||||||
|
previewUser = "${name}-preview";
|
||||||
|
in {
|
||||||
|
"${name}-preview-rebuild" = {
|
||||||
|
description = "Clone/pull and build preview of ${site.domain}";
|
||||||
|
after = [ "network-online.target" ] ++ site.afterServices;
|
||||||
|
path = [ pkgs.nodejs pkgs.bash ]
|
||||||
|
++ optional (site.packageManager == "pnpm") pkgs.pnpm;
|
||||||
|
environment = site.buildEnvironment;
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = false;
|
||||||
|
ExecStartPre = "+${pkgs.writeShellScript "prepare-${name}-preview" ''
|
||||||
|
mkdir -p ${previewDataDir}
|
||||||
|
chown -R ${previewUser}:${previewUser} ${previewDataDir}
|
||||||
|
''}";
|
||||||
|
ExecStart = pkgs.writeShellScript "rebuild-${name}-preview" ''
|
||||||
|
set -euo pipefail
|
||||||
|
if [ ! -d ${previewDataDir}/repo/.git ]; then
|
||||||
|
${pkgs.git}/bin/git clone ${site.repo} ${previewDataDir}/repo
|
||||||
|
fi
|
||||||
|
cd ${previewDataDir}/repo
|
||||||
|
${pkgs.git}/bin/git fetch origin
|
||||||
|
${pkgs.git}/bin/git reset --hard origin/${site.preview.branch}
|
||||||
|
${h.installCmd}
|
||||||
|
${h.pmBin} run build
|
||||||
|
'';
|
||||||
|
ExecStartPost = lib.mkIf (!site.static)
|
||||||
|
"+/run/current-system/sw/bin/systemctl restart ${previewUser}";
|
||||||
|
User = previewUser;
|
||||||
|
Group = previewUser;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // lib.optionalAttrs (!site.static) {
|
||||||
|
${previewUser} = {
|
||||||
|
description = "Preview of ${site.domain}";
|
||||||
|
environment = {
|
||||||
|
HOST = "127.0.0.1";
|
||||||
|
PORT = toString site.preview.port;
|
||||||
|
} // site.environment;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
WorkingDirectory = "${previewDataDir}/repo";
|
||||||
|
ExecStart = "${pkgs.nodejs}/bin/node ${site.entryPoint}";
|
||||||
|
Restart = "on-failure";
|
||||||
|
User = previewUser;
|
||||||
|
Group = previewUser;
|
||||||
|
ReadWritePaths = site.readWritePaths;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
) previewCfg) ++ [{
|
||||||
site-webhook = mkIf (cfg != {}) {
|
site-webhook = mkIf (cfg != {}) {
|
||||||
description = "Webhook listener for site rebuilds";
|
description = "Webhook listener for site rebuilds";
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
|
|
@ -192,13 +301,19 @@ in
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
ExecStart = let
|
ExecStart = let
|
||||||
allHooks = mapAttrsToList (name: site: {
|
allHooks = (mapAttrsToList (name: site: {
|
||||||
id = "${name}-rebuild";
|
id = "${name}-rebuild";
|
||||||
execute-command = "/run/current-system/sw/bin/touch";
|
execute-command = "/run/current-system/sw/bin/touch";
|
||||||
pass-arguments-to-command = [
|
pass-arguments-to-command = [
|
||||||
{ source = "string"; name = "/run/site-rebuild/${name}"; }
|
{ source = "string"; name = "/run/site-rebuild/${name}"; }
|
||||||
];
|
];
|
||||||
}) cfg;
|
}) cfg) ++ (mapAttrsToList (name: site: {
|
||||||
|
id = "${name}-preview-rebuild";
|
||||||
|
execute-command = "/run/current-system/sw/bin/touch";
|
||||||
|
pass-arguments-to-command = [
|
||||||
|
{ source = "string"; name = "/run/site-rebuild/${name}-preview"; }
|
||||||
|
];
|
||||||
|
}) previewCfg);
|
||||||
hooksFile = pkgs.writeText "site-hooks.json" (builtins.toJSON allHooks);
|
hooksFile = pkgs.writeText "site-hooks.json" (builtins.toJSON allHooks);
|
||||||
in "${pkgs.webhook}/bin/webhook -hooks ${hooksFile} -port ${toString webhookPort} -verbose";
|
in "${pkgs.webhook}/bin/webhook -hooks ${hooksFile} -port ${toString webhookPort} -verbose";
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
|
|
@ -208,7 +323,7 @@ in
|
||||||
};
|
};
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
systemd.paths = mkMerge (mapAttrsToList (name: site: {
|
systemd.paths = mkMerge ((mapAttrsToList (name: site: {
|
||||||
"${name}-rebuild-trigger" = {
|
"${name}-rebuild-trigger" = {
|
||||||
description = "Watch for ${name} rebuild trigger";
|
description = "Watch for ${name} rebuild trigger";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
@ -217,18 +332,35 @@ in
|
||||||
Unit = "${name}-rebuild.service";
|
Unit = "${name}-rebuild.service";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}) cfg);
|
}) cfg) ++ (mapAttrsToList (name: site: {
|
||||||
|
"${name}-preview-rebuild-trigger" = {
|
||||||
|
description = "Watch for ${name}-preview rebuild trigger";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
pathConfig = {
|
||||||
|
PathModified = "/run/site-rebuild/${name}-preview";
|
||||||
|
Unit = "${name}-preview-rebuild.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) previewCfg));
|
||||||
|
|
||||||
users.users = mkMerge (mapAttrsToList (name: site: {
|
users.users = mkMerge ((mapAttrsToList (name: site: {
|
||||||
${name} = {
|
${name} = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
group = name;
|
group = name;
|
||||||
home = site.dataDir;
|
home = site.dataDir;
|
||||||
};
|
};
|
||||||
}) cfg);
|
}) cfg) ++ (mapAttrsToList (name: site: {
|
||||||
|
"${name}-preview" = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "${name}-preview";
|
||||||
|
home = "/srv/${name}-preview";
|
||||||
|
};
|
||||||
|
}) previewCfg));
|
||||||
|
|
||||||
users.groups = mkMerge (mapAttrsToList (name: _: {
|
users.groups = mkMerge ((mapAttrsToList (name: _: {
|
||||||
${name} = {};
|
${name} = {};
|
||||||
}) cfg);
|
}) cfg) ++ (mapAttrsToList (name: _: {
|
||||||
|
"${name}-preview" = {};
|
||||||
|
}) previewCfg));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue