Compare commits

..

6 Commits

Author SHA1 Message Date
9bfc71f9ac Add daily auto-update workflow with shared build script
All checks were successful
Check Flake / check-flake (push) Successful in 4m38s
2026-02-21 16:10:54 -08:00
d61d56bf0f Add ntfy push notification server on ponyo 2026-02-21 16:10:54 -08:00
592d0a8f8d Remove phil machine and aarch64 ISO/kexec 2026-02-21 16:10:54 -08:00
04fe2d36a9 Disable SMB3 directory leases to fix stale listings from local file changes 2026-02-21 16:10:54 -08:00
382b2c374d Update inputs + move to nixos-unstable 2026-02-21 16:10:54 -08:00
58d54d1f17 Add Attic binary cache and containerize gitea runner
Replace nix-serve-only setup with Attic for managed binary caching with
upstream filtering and GC. Move gitea actions runner from host into an
isolated NixOS container with private networking. nix-serve kept alongside
Attic during migration.
2026-02-21 16:10:47 -08:00
13 changed files with 137 additions and 113 deletions

View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
# Configure Attic cache
attic login local "$ATTIC_ENDPOINT" "$ATTIC_TOKEN"
attic use local:nixos
# Check flake
nix flake check --all-systems --print-build-logs --log-format raw --show-trace
# Build all systems
nix eval .#nixosConfigurations --apply 'cs: builtins.attrNames cs' --json \
| jq -r '.[]' \
| xargs -I{} nix build ".#nixosConfigurations.{}.config.system.build.toplevel" \
--no-link --print-build-logs --log-format raw
# Push to cache (only locally-built paths >= 0.5MB)
toplevels=$(nix eval .#nixosConfigurations \
--apply 'cs: map (n: "${cs.${n}.config.system.build.toplevel}") (builtins.attrNames cs)' \
--json | jq -r '.[]')
echo "Found $(echo "$toplevels" | wc -l) system toplevels"
paths=$(echo "$toplevels" \
| xargs nix path-info -r --json \
| jq -r '[to_entries[] | select(
(.value.signatures | all(startswith("cache.nixos.org") | not))
and .value.narSize >= 524288
) | .key] | unique[]')
echo "Pushing $(echo "$paths" | wc -l) unique paths to cache"
echo "$paths" | xargs attic push local:nixos

View File

@@ -0,0 +1,42 @@
name: Auto Update Flake
on:
schedule:
- cron: '0 6 * * *'
workflow_dispatch: {}
env:
DEBIAN_FRONTEND: noninteractive
PATH: /run/current-system/sw/bin/
XDG_CONFIG_HOME: ${{ runner.temp }}/.config
ATTIC_ENDPOINT: ${{ vars.ATTIC_ENDPOINT }}
ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }}
jobs:
auto-update:
runs-on: nixos
steps:
- name: Checkout the repository
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: master
- name: Update flake inputs
run: nix flake update --commit-lock-file
- name: Build and cache
run: bash .gitea/scripts/build-and-cache.sh
- name: Push updated lockfile
run: git push
- name: Notify on failure
if: failure()
run: |
curl -s \
-H "Authorization: Bearer ${{ secrets.NTFY_TOKEN }}" \
-H "Title: Flake auto-update failed" \
-H "Priority: high" \
-H "Tags: warning" \
-d "Auto-update workflow failed. Check: ${{ gitea.server_url }}/${{ gitea.repository }}/actions/runs/${{ gitea.run_id }}" \
ntfy.neet.dev/nix-flake-updates

View File

@@ -6,6 +6,8 @@ env:
DEBIAN_FRONTEND: noninteractive
PATH: /run/current-system/sw/bin/
XDG_CONFIG_HOME: ${{ runner.temp }}/.config
ATTIC_ENDPOINT: ${{ vars.ATTIC_ENDPOINT }}
ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN }}
jobs:
check-flake:
@@ -16,34 +18,5 @@ jobs:
with:
fetch-depth: 0
- name: Configure Attic cache
run: |
attic login local "${{ vars.ATTIC_ENDPOINT }}" "${{ secrets.ATTIC_TOKEN }}"
attic use local:nixos
- name: Check Flake
run: nix flake check --all-systems --print-build-logs --log-format raw --show-trace
- name: Build all systems
run: |
nix eval .#nixosConfigurations --apply 'cs: builtins.attrNames cs' --json \
| jq -r '.[]' \
| xargs -I{} nix build ".#nixosConfigurations.{}.config.system.build.toplevel" --no-link --print-build-logs --log-format raw
- name: Push to cache
run: |
set -euo pipefail
# Get all system toplevel store paths
toplevels=$(nix eval .#nixosConfigurations --apply 'cs: map (n: "${cs.${n}.config.system.build.toplevel}") (builtins.attrNames cs)' --json | jq -r '.[]')
echo "Found $(echo "$toplevels" | wc -l) system toplevels"
# Expand to full closures, deduplicate, and filter out paths that are:
# - already signed by cache.nixos.org (available upstream)
# - smaller than 0.5MB (insignificant build artifacts)
paths=$(echo "$toplevels" \
| xargs nix path-info -r --json \
| jq -r '[to_entries[] | select(
(.value.signatures | all(startswith("cache.nixos.org") | not))
and .value.narSize >= 524288
) | .key] | unique[]')
echo "Pushing $(echo "$paths" | wc -l) unique paths to cache"
echo "$paths" | xargs attic push local:nixos
- name: Build and cache
run: bash .gitea/scripts/build-and-cache.sh

View File

@@ -10,7 +10,7 @@
];
trusted-public-keys = [
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"nixos:SnTTQutdOJbAmxo6AQ3cbRt5w9f4byMXQODCieBH3PQ="
"nixos:e5AMCUWWEX9MESWAAMjBkZdGUpl588NhgsUO3HsdhFw="
];
# Allow substituters to be offline

View File

@@ -4,8 +4,8 @@ let
builderUserName = "nix-builder";
builderRole = "nix-builder";
builders = config.machines.withRole.${builderRole};
thisMachineIsABuilder = config.thisMachine.hasRole.${builderRole};
builders = config.machines.withRole.${builderRole} or [];
thisMachineIsABuilder = config.thisMachine.hasRole.${builderRole} or false;
# builders don't include themselves as a remote builder
otherBuilders = lib.filter (hostname: hostname != config.networking.hostName) builders;

View File

@@ -16,5 +16,6 @@
./librechat.nix
./actualbudget.nix
./unifi.nix
./ntfy.nix
];
}

40
common/server/ntfy.nix Normal file
View File

@@ -0,0 +1,40 @@
{ lib, config, ... }:
let
cfg = config.services.ntfy-sh;
in
{
options.services.ntfy-sh = {
hostname = lib.mkOption {
type = lib.types.str;
example = "ntfy.example.com";
};
};
config = lib.mkIf cfg.enable {
services.ntfy-sh.settings = {
base-url = "https://${cfg.hostname}";
listen-http = "127.0.0.1:2586";
auth-default-access = "deny-all";
auth-file = "/var/lib/ntfy-sh/user.db";
behind-proxy = true;
enable-login = true;
attachment-cache-dir = "/var/lib/ntfy-sh/attachments";
};
# backups
backup.group."ntfy".paths = [
"/var/lib/ntfy-sh"
];
services.nginx.enable = true;
services.nginx.virtualHosts.${cfg.hostname} = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:2586";
proxyWebsockets = true;
};
};
};
}

View File

@@ -26,6 +26,16 @@
"printcap name" = "cups";
"hide files" = "/.nobackup/.DS_Store/._.DS_Store/";
# Samba 4.22+ enables SMB3 directory leases by default, allowing clients
# to cache directory listings locally. When files are created locally on
# the server (bypassing Samba), these cached listings go stale because
# kernel oplocks — the mechanism that would break leases on local
# changes — is incompatible with smb2 leases. Enabling kernel oplocks
# would fix this but forces Samba to disable smb2 leases, durable
# handles, and level2 oplocks, losing handle caching performance.
# https://wiki.samba.org/index.php/Editing_files_locally_on_server:_interoperability
"smb3 directory leases" = "no";
};
public = {
path = "/data/samba/Public";

View File

@@ -175,10 +175,10 @@
kexec = (mkEphemeral "x86_64-linux").config.system.build.images.kexec;
iso = (mkEphemeral "x86_64-linux").config.system.build.images.iso;
};
"aarch64-linux" = {
kexec = (mkEphemeral "aarch64-linux").config.system.build.images.kexec;
iso = (mkEphemeral "aarch64-linux").config.system.build.images.iso;
};
# "aarch64-linux" = {
# kexec = (mkEphemeral "aarch64-linux").config.system.build.images.kexec;
# iso = (mkEphemeral "aarch64-linux").config.system.build.images.iso;
# };
};
overlays.default = import ./overlays { inherit inputs; };

View File

@@ -1,9 +0,0 @@
{ lib, ... }:
{
imports = [
./hardware-configuration.nix
];
networking.hostName = "phil";
}

View File

@@ -1,46 +0,0 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ lib, modulesPath, ... }:
{
imports =
[
(modulesPath + "/profiles/qemu-guest.nix")
];
# because grub just doesn't work for some reason
boot.loader.systemd-boot.enable = true;
remoteLuksUnlock.enable = true;
remoteLuksUnlock.enableTorUnlock = false;
boot.initrd.availableKernelModules = [ "xhci_pci" ];
boot.initrd.kernelModules = [ "dm-snapshot" ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
boot.initrd.luks.devices."enc-pv" = {
device = "/dev/disk/by-uuid/d26c1820-4c39-4615-98c2-51442504e194";
allowDiscards = true;
};
fileSystems."/" =
{
device = "/dev/disk/by-uuid/851bfde6-93cd-439e-9380-de28aa87eda9";
fsType = "btrfs";
};
fileSystems."/boot" =
{
device = "/dev/disk/by-uuid/F185-C4E5";
fsType = "vfat";
};
swapDevices =
[{ device = "/dev/disk/by-uuid/d809e3a1-3915-405a-a200-4429c5efdf87"; }];
networking.interfaces.enp0s6.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
}

View File

@@ -1,20 +0,0 @@
{
hostNames = [
"phil"
"phil.neet.dev"
];
arch = "aarch64-linux";
systemRoles = [
"server"
"nix-builder"
];
hostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBlgRPpuUkZqe8/lHugRPm/m2vcN9psYhh5tENHZt9I2";
remoteUnlock = {
hostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0RodotOXLMy/w70aa096gaNqPBnfgiXR5ZAH4+wGzd";
clearnetHost = "unlock.phil.neet.dev";
};
}

View File

@@ -108,4 +108,8 @@
# librechat
services.librechat-container.enable = true;
services.librechat-container.host = "chat.neet.dev";
# push notifications
services.ntfy-sh.enable = true;
services.ntfy-sh.hostname = "ntfy.neet.dev";
}