bucur/modules/services/static-sites/default.nix
randogoth 3ae266293f Add zonetoast.com Pelican site
Wire up flake input, Pelican build, deploy service, webhook trigger, and
Caddy virtual host for zonetoast.com.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:22:54 +03:00

280 lines
10 KiB
Nix

{ inputs, pkgs, ... }:
let
buildPelicanSite = { name, src, subdir ? "", pluginSources ? [ ] }:
let
workdir = if subdir == "" then "." else subdir;
pythonEnv = pkgs.python3.withPackages (ps: [
ps.pelican
ps.markdown
ps.pygments
]);
copyPlugins = pkgs.lib.concatStringsSep "\n" (map (plugin: ''
mkdir -p "${workdir}/${plugin.dest}"
cp -a "${plugin.src}${if plugin ? subdir then "/${plugin.subdir}" else ""}/." "${workdir}/${plugin.dest}/"
'') pluginSources);
in
pkgs.stdenvNoCC.mkDerivation {
pname = name;
version = "git";
src = src;
nativeBuildInputs = [ pythonEnv ];
buildPhase = ''
runHook preBuild
cd ${workdir}
${copyPlugins}
if [ -d content ]; then
# Drop draft content before building (Pelican draft detection can be inconsistent).
(grep -RIl '^status:[[:space:]]*draft' content || true) | xargs -r rm -f
fi
# nfc-web's `geohash` Pelican plugin imports `geohash_tools`, but that module
# isn't shipped in the repo. Provide a tiny implementation at build time.
if [ -d plugins ] && [ -f plugins/geohash/geohash.py ] && [ ! -f plugins/geohash_tools.py ]; then
cat > plugins/geohash_tools.py <<'PY'
BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz"
def encode(latitude, longitude, precision=12):
lat_interval = [-90.0, 90.0]
lon_interval = [-180.0, 180.0]
geohash = []
bit = 0
ch = 0
even = True
bits = [16, 8, 4, 2, 1]
while len(geohash) < precision:
if even:
mid = (lon_interval[0] + lon_interval[1]) / 2.0
if longitude >= mid:
ch |= bits[bit]
lon_interval[0] = mid
else:
lon_interval[1] = mid
else:
mid = (lat_interval[0] + lat_interval[1]) / 2.0
if latitude >= mid:
ch |= bits[bit]
lat_interval[0] = mid
else:
lat_interval[1] = mid
even = not even
if bit < 4:
bit += 1
else:
geohash.append(BASE32[ch])
bit = 0
ch = 0
return "".join(geohash)
PY
fi
if [ -f pelicanconf.py ]; then
${pythonEnv}/bin/pelican content -o "$out" -s pelicanconf.py
else
${pythonEnv}/bin/pelican content -o "$out"
fi
runHook postBuild
'';
installPhase = "true";
};
buildJekyllSite = { name, src, gemset }:
let
bundlerEnv = pkgs.bundlerEnv {
name = "${name}-bundler-env";
gemdir = src;
gemset = gemset;
};
in
pkgs.stdenvNoCC.mkDerivation {
pname = name;
version = "git";
src = src;
nativeBuildInputs = [ bundlerEnv ];
buildPhase = ''
runHook preBuild
JEKYLL_ENV=production bundle exec jekyll build -s . -d "$out"
runHook postBuild
'';
installPhase = "true";
};
buildStaticSite = { name, src, subdir ? "" }:
let
srcPath = if subdir == "" then src else "${src}/${subdir}";
in
pkgs.stdenvNoCC.mkDerivation {
pname = name;
version = "git";
src = src;
dontUnpack = true;
installPhase = ''
runHook preInstall
mkdir -p "$out"
cp -a ${srcPath}/. "$out/"
runHook postInstall
'';
};
mkDeployService = { name, src, dest }:
{
description = "Deploy ${name} site";
path = [ pkgs.coreutils pkgs.rsync ];
serviceConfig = {
Type = "oneshot";
};
script = ''
install -d -m 755 ${dest}
rsync -a --delete ${src}/ ${dest}/
'';
};
sublunarSite = buildPelicanSite {
name = "sublunar";
src = inputs.sublunar;
};
tobiasRaayoniLastSite = buildPelicanSite {
name = "tobias-raayoni-last";
src = inputs.flux_vision;
subdir = "web";
};
nmnsSite = buildPelicanSite {
name = "nmns";
src = inputs.nfc_web;
subdir = "web";
};
scopesessionsSite = buildJekyllSite {
name = "scopesessions";
src = inputs.scopesessions;
gemset = ./scopesessions-gemset.nix;
};
almanacSite = buildStaticSite {
name = "sublunar-almanac";
src = inputs.sublunar_almanac;
};
praxisSite = buildStaticSite {
name = "praxis";
src = inputs.praxis;
};
zonetoastSite = buildPelicanSite {
name = "zonetoast";
src = inputs.zonetoast;
};
isNixBuild = builtins.getEnv "IN_NIX_BUILD" == "1";
in
{
sops.secrets.codeberg_id_ed25519 = {
owner = "root";
group = "root";
mode = "0400";
path = "/etc/ssh/codeberg_id_ed25519";
};
systemd.services."deploy-sublunar" = mkDeployService {
name = "sublunar";
src = sublunarSite;
dest = "/var/www/sublunar.space/public";
};
systemd.services."deploy-tobias-raayoni-last" = mkDeployService {
name = "tobias-raayoni-last";
src = tobiasRaayoniLastSite;
dest = "/var/www/raayoni-last.com/tobias/public";
};
systemd.services."deploy-nmns" = mkDeployService {
name = "nmns";
src = nmnsSite;
dest = "/var/www/nmns.place/public";
};
systemd.services."deploy-scopesessions" = mkDeployService {
name = "scopesessions";
src = scopesessionsSite;
dest = "/var/www/scopesessions.org/public";
} // {
path = [ pkgs.coreutils pkgs.rsync pkgs.curl ];
script = ''
install -d -m 755 /var/www/scopesessions.org/public
rsync -a --delete ${scopesessionsSite}/ /var/www/scopesessions.org/public/
# Restore legacy bower_components assets expected by the theme.
install -d -m 755 /var/www/scopesessions.org/public/bower_components
# jQuery 2.1.1
install -d -m 755 /var/www/scopesessions.org/public/bower_components/jquery/dist
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js \
-o /var/www/scopesessions.org/public/bower_components/jquery/dist/jquery.min.js
# Bootstrap 3.3.1
install -d -m 755 /var/www/scopesessions.org/public/bower_components/bootstrap/dist/css
install -d -m 755 /var/www/scopesessions.org/public/bower_components/bootstrap/dist/js
install -d -m 755 /var/www/scopesessions.org/public/bower_components/bootstrap/dist/fonts
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.min.css \
-o /var/www/scopesessions.org/public/bower_components/bootstrap/dist/css/bootstrap.min.css
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/js/bootstrap.min.js \
-o /var/www/scopesessions.org/public/bower_components/bootstrap/dist/js/bootstrap.min.js
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/fonts/glyphicons-halflings-regular.eot \
-o /var/www/scopesessions.org/public/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/fonts/glyphicons-halflings-regular.svg \
-o /var/www/scopesessions.org/public/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/fonts/glyphicons-halflings-regular.ttf \
-o /var/www/scopesessions.org/public/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/fonts/glyphicons-halflings-regular.woff \
-o /var/www/scopesessions.org/public/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
# Font Awesome 4.3.0
install -d -m 755 /var/www/scopesessions.org/public/bower_components/fontawesome/css
install -d -m 755 /var/www/scopesessions.org/public/bower_components/fontawesome/fonts
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/css/font-awesome.min.css \
-o /var/www/scopesessions.org/public/bower_components/fontawesome/css/font-awesome.min.css
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/fonts/fontawesome-webfont.eot \
-o /var/www/scopesessions.org/public/bower_components/fontawesome/fonts/fontawesome-webfont.eot
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/fonts/fontawesome-webfont.svg \
-o /var/www/scopesessions.org/public/bower_components/fontawesome/fonts/fontawesome-webfont.svg
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/fonts/fontawesome-webfont.ttf \
-o /var/www/scopesessions.org/public/bower_components/fontawesome/fonts/fontawesome-webfont.ttf
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/fonts/fontawesome-webfont.woff \
-o /var/www/scopesessions.org/public/bower_components/fontawesome/fonts/fontawesome-webfont.woff
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.3.0/fonts/fontawesome-webfont.woff2 \
-o /var/www/scopesessions.org/public/bower_components/fontawesome/fonts/fontawesome-webfont.woff2
# Vegas 1.3.5
install -d -m 755 /var/www/scopesessions.org/public/bower_components/vegas/dist
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/vegas/1.3.5/jquery.vegas.min.css \
-o /var/www/scopesessions.org/public/bower_components/vegas/dist/jquery.vegas.min.css
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/vegas/1.3.5/jquery.vegas.min.js \
-o /var/www/scopesessions.org/public/bower_components/vegas/dist/jquery.vegas.min.js
# Isotope 3.0.1
install -d -m 755 /var/www/scopesessions.org/public/bower_components/isotope/dist
curl -fsSL https://cdnjs.cloudflare.com/ajax/libs/jquery.isotope/3.0.1/isotope.pkgd.min.js \
-o /var/www/scopesessions.org/public/bower_components/isotope/dist/isotope.pkgd.min.js
'';
};
systemd.services."deploy-almanac" = mkDeployService {
name = "almanac";
src = almanacSite;
dest = "/var/www/sublunar.space/almanac/public";
};
systemd.services."deploy-privatpraxis" = mkDeployService {
name = "privatpraxis";
src = praxisSite;
dest = "/var/www/privatpraxis-last-heidelberg.de/public";
};
systemd.services."deploy-zonetoast" = mkDeployService {
name = "zonetoast";
src = zonetoastSite;
dest = "/var/www/zonetoast.com/public";
};
}