Compare commits

...

10 commits

Author SHA1 Message Date
alisceon
14ec1eca2e liberalize limits 2026-05-27 23:58:05 +02:00
alisceon
4cecd07602 regress to sane port 2026-05-27 23:26:48 +02:00
alisceon
3720f06e28 no sandbox :( 2026-05-27 23:23:41 +02:00
alisceon
a7683d40fd 421 and tor connection 2026-05-27 23:17:53 +02:00
alisceon
553e708795 oops 2026-05-27 22:48:07 +02:00
alisceon
18fdce9c16 lgtm ship it 2026-05-27 22:44:34 +02:00
alisceon
7b785cf1e5 rename dir 2026-05-27 21:37:24 +02:00
alisceon
04fbe6afb2 name change 2026-05-27 21:34:02 +02:00
alisceon
87cc464d1b add oci target 2026-05-27 16:39:26 +02:00
alisceon
9cb871275a vibed improved gc 2026-05-24 17:15:28 +02:00
9 changed files with 534 additions and 19 deletions

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
result
result*
.stfolder
flake.lock

View file

@ -31,7 +31,6 @@
...
}:
let
system = "x86_64-linux";
repoLocalPath =
let
fromEnv = builtins.getEnv "NIXOS_CONFIG_ROOT";
@ -42,26 +41,21 @@
inputs.nur.overlays.default
];
pkgs = import nixpkgs {
mkPkgs = system: import nixpkgs {
inherit system;
config.allowUnfree = true;
flake.setFlakeRegistry = true;
inherit overlays;
};
pkgs-unstable = import nixpkgs-unstable {
mkPkgsUnstable = system: import nixpkgs-unstable {
inherit system;
config.allowUnfree = true;
flake.setFlakeRegistry = true;
inherit overlays;
};
sharedSpecialArgs = {
inherit repoLocalPath pkgs-unstable;
repoRoot = self;
};
sharedModules = [
mkSharedModules = pkgs: pkgs-unstable: [
./nixos/modules/base.nix
inputs.home-manager.nixosModules.home-manager
({ ... }: {
@ -77,24 +71,32 @@
mkHost = {
hostName,
system,
nixosModules ? [ ],
hmModules ? [ ],
extraModules ? [ ],
}:
let
pkgs = mkPkgs system;
pkgs-unstable = mkPkgsUnstable system;
in
nixpkgs.lib.nixosSystem {
inherit system pkgs;
specialArgs = sharedSpecialArgs;
specialArgs = {
inherit repoLocalPath pkgs-unstable;
repoRoot = self;
};
modules =
sharedModules
(mkSharedModules pkgs pkgs-unstable)
++ [ (./nixos/hosts + "/${hostName}/configuration.nix") ]
++ nixosModules
++ extraModules
++ [
{
home-manager.users.alisceon.imports =
[
[
inputs.noctalia.homeModules.default
./home/profiles/base.nix
./home/profiles/base.nix
]
++ hmModules;
home-manager.users.root.imports = [
@ -125,6 +127,7 @@
nixosConfigurations = {
electra = mkHost {
hostName = "electra";
system = "x86_64-linux";
nixosModules = workstationModules;
hmModules = workstationHomeModules ++ [
./home/hosts/alisceon/electra.nix
@ -133,6 +136,7 @@
tower = mkHost {
hostName = "tower";
system = "x86_64-linux";
nixosModules = workstationModules;
hmModules = workstationHomeModules ++ [
./home/hosts/alisceon/tower.nix
@ -141,6 +145,7 @@
tesla-nixos = mkHost {
hostName = "tesla-nixos";
system = "x86_64-linux";
nixosModules = serverModules;
hmModules = serverHomeModules;
extraModules = [
@ -151,6 +156,14 @@
nuc = mkHost {
hostName = "nuc";
system = "x86_64-linux";
nixosModules = serverModules;
hmModules = serverHomeModules;
};
alisceon-core = mkHost {
hostName = "alisceon-core";
system = "aarch64-linux";
nixosModules = serverModules;
hmModules = serverHomeModules;
};

View file

@ -18,7 +18,7 @@
};
"alisceon-core" = {
hostname = "core.alisceon.com";
user = "opc";
user = "alisceon";
};
"blogbox-2" = {
hostname = "10.1.0.11";

View file

@ -1,6 +1,15 @@
{ pkgs }:
let
swaymsg = "${pkgs.sway}/bin/swaymsg";
systemNotify = pkgs.writeShellApplication {
name = "system-notify";
runtimeInputs = [
pkgs.coreutils
pkgs.libnotify
pkgs.util-linux
];
text = builtins.readFile ../util/system_notify.sh;
};
in
{
uwsm = "${pkgs.uwsm}/bin/uwsm-app --";
@ -9,6 +18,7 @@ in
lock = "${pkgs.swaylock}/bin/swaylock --daemonize";
term = "${pkgs.foot}/bin/footclient";
notify = "${pkgs.libnotify}/bin/notify-send";
"system-notify" = "${systemNotify}/bin/system-notify";
nag = "${pkgs.sway}/bin/swaynag --edge bottom";
dmenu = "${pkgs.rofi-unwrapped}/bin/rofi";
espanso = "${pkgs.espanso-wayland}/bin/espanso cmd";

View file

@ -0,0 +1,297 @@
{ lib, pkgs, modulesPath, ... }:
let
forgejoDomain = "git.alisceon.com";
forgejoRunnerTokenFile = "/var/lib/forgejo/runner_token";
fetchOciAuthorizedKeys = pkgs.writeShellApplication {
name = "fetch-oci-authorized-keys";
runtimeInputs = [
pkgs.coreutils
pkgs.curl
];
text = ''
install -d -m 0700 -o alisceon -g users /home/alisceon/.ssh
if [ -s /home/alisceon/.ssh/authorized_keys ]; then
echo "OCI authorized_keys already present for alisceon"
exit 0
fi
curl --fail --silent --show-error --location \
--header "Authorization: Bearer Oracle" \
--output /home/alisceon/.ssh/authorized_keys \
http://169.254.169.254/opc/v2/instance/metadata/ssh_authorized_keys
chown alisceon:users /home/alisceon/.ssh/authorized_keys
chmod 0600 /home/alisceon/.ssh/authorized_keys
'';
};
generateForgejoRunnerToken = pkgs.writeShellApplication {
name = "generate-forgejo-runner-token";
runtimeInputs = [
pkgs.coreutils
pkgs.util-linux
];
text = ''
token_file=${lib.escapeShellArg forgejoRunnerTokenFile}
if [ -s "$token_file" ]; then
chmod 0600 "$token_file"
chown root:root "$token_file"
exit 0
fi
install -d -m 0750 -o forgejo -g forgejo /var/lib/forgejo
token="$(runuser -u forgejo -- env \
FORGEJO_WORK_DIR=/var/lib/forgejo \
FORGEJO_CUSTOM=/var/lib/forgejo/custom \
${lib.getExe pkgs.forgejo-lts} actions generate-runner-token)"
umask 0077
printf 'TOKEN=%s\n' "$token" > "$token_file"
chown root:root "$token_file"
chmod 0600 "$token_file"
'';
};
in
{
imports = [
"${modulesPath}/virtualisation/oci-image.nix"
];
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
networking = {
hostName = "alisceon-core";
networkmanager.enable = lib.mkForce false;
firewall.allowedTCPPorts = [
22
80
443
24601
];
};
boot = {
initrd.availableKernelModules = [
"virtio_pci"
"virtio_blk"
"virtio_scsi"
"virtio_net"
"xhci_pci"
];
loader.systemd-boot.configurationLimit = lib.mkForce 3;
};
nix = {
settings = {
min-free = lib.mkForce (512 * 1024 * 1024);
max-free = lib.mkForce (2 * 1024 * 1024 * 1024);
};
gc = {
dates = lib.mkForce "daily";
options = lib.mkForce "--delete-older-than 3d";
};
};
virtualisation = {
docker.enable = lib.mkForce false;
podman = {
enable = true;
dockerSocket.enable = true;
autoPrune = {
enable = true;
dates = "daily";
flags = [ "--all" ];
};
};
};
users.users.alisceon.extraGroups = [ "systemd-journal" ];
security = {
acme = {
acceptTerms = true;
defaults.email = "acme@alisceon.com";
};
sudo-rs.wheelNeedsPassword = false;
};
services.openssh.settings = {
PasswordAuthentication = false;
PermitRootLogin = lib.mkForce "prohibit-password";
};
services.forgejo = {
enable = true;
package = pkgs.forgejo-lts;
database.type = "sqlite3";
lfs.enable = true;
settings = {
server = {
DOMAIN = forgejoDomain;
ROOT_URL = "https://${forgejoDomain}/";
HTTP_ADDR = "127.0.0.1";
HTTP_PORT = 3000;
SSH_DOMAIN = forgejoDomain;
SSH_PORT = 22;
DISABLE_SSH = false;
};
session.COOKIE_SECURE = true;
service = {
DISABLE_REGISTRATION = true;
REQUIRE_SIGNIN_VIEW = false;
};
actions.ENABLED = true;
repository = {
DEFAULT_PRIVATE = "private";
DISABLE_HTTP_GIT = false;
};
"cron.archive_cleanup" = {
ENABLED = true;
RUN_AT_START = true;
SCHEDULE = "@every 24h";
OLDER_THAN = "72h";
};
log.LEVEL = "Warn";
};
};
services.gitea-actions-runner = {
package = pkgs.forgejo-runner;
instances.alisceon-core-podman = {
enable = true;
name = "alisceon-core-podman";
url = "https://${forgejoDomain}";
tokenFile = forgejoRunnerTokenFile;
labels = [
"ubuntu-latest:docker://node:22-bookworm"
"debian-latest:docker://node:22-bookworm"
];
settings = {
container = {
network = "host";
privileged = false;
valid_volumes = [ ];
};
cache.enabled = false;
};
};
};
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts = {
"_" = {
default = true;
rejectSSL = true;
extraConfig = ''
return 421;
'';
};
${forgejoDomain} = {
serverName = forgejoDomain;
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://127.0.0.1:3000";
recommendedProxySettings = true;
};
};
};
};
services.tor = {
enable = true;
client.enable = false;
relay = {
enable = true;
role = "relay";
};
settings = {
Nickname = "alisceondotcom";
ORPort = 24601;
DataDirectory = "/var/lib/tor";
ExitRelay = false;
ExitPolicy = [ "reject *:*" ];
RelayBandwidthRate = "25 MBytes";
RelayBandwidthBurst = "25 MBytes";
BandwidthRate = "25 MBytes";
BandwidthBurst = "25 MBytes";
AccountingStart = "month 1 00:00";
AccountingMax = "8500 GBytes";
DirCache = true;
AvoidDiskWrites = 1;
Sandbox = false;
};
};
services.cloud-init = {
enable = true;
network.enable = true;
settings = {
datasource_list = [ "Oracle" "ConfigDrive" "NoCloud" ];
users = [ "default" ];
system_info.default_user = {
name = "alisceon";
gecos = "Alisceon";
groups = [ "wheel" "systemd-journal" ];
shell = "/run/current-system/sw/bin/xonsh";
lock_passwd = true;
};
};
};
systemd.services.fetch-oci-authorized-keys = {
description = "Fetch OCI metadata authorized_keys for alisceon";
wantedBy = [ "sshd.service" ];
before = [ "sshd.service" ];
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
StandardError = "journal+console";
StandardOutput = "journal+console";
};
script = lib.getExe fetchOciAuthorizedKeys;
};
systemd.services.fetch-ssh-keys.enable = false;
systemd.services.forgejo-runner-token = {
description = "Generate Forgejo runner registration token";
wantedBy = [ "multi-user.target" ];
after = [ "forgejo.service" ];
requires = [ "forgejo.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
StandardError = "journal+console";
StandardOutput = "journal+console";
};
script = lib.getExe generateForgejoRunnerToken;
};
systemd.services."gitea-runner-alisceon\\x2dcore\\x2dpodman" = {
after = [ "forgejo-runner-token.service" ];
requires = [ "forgejo-runner-token.service" ];
};
environment.systemPackages = with pkgs; [
curl
forgejo-lts
git
htop
jq
vim
wget
];
system.stateVersion = lib.mkForce "25.11";
}

View file

@ -2,6 +2,15 @@
let
autoUpgradeUser = "alisceon";
flakeRef = "path:${repoLocalPath}";
devFlakeGarbageCollect = pkgs.writeShellApplication {
name = "dev-flake-garbage-collect";
runtimeInputs = [
pkgs.coreutils
pkgs.findutils
pkgs.gnugrep
];
text = builtins.readFile ../../util/dev_flake_gc.sh;
};
in
{
boot = {
@ -34,9 +43,34 @@ in
runGarbageCollection = true;
};
systemd.services.nixos-upgrade.preStart = ''
${pkgs.util-linux}/bin/runuser -u ${autoUpgradeUser} -- ${lib.getExe config.nix.package} flake update --flake ${lib.escapeShellArg flakeRef}
'';
systemd = {
services = {
nixos-upgrade.preStart = ''
${pkgs.util-linux}/bin/runuser -u ${autoUpgradeUser} -- ${lib.getExe config.nix.package} flake update --flake ${lib.escapeShellArg flakeRef}
'';
dev-flake-garbage-collect = {
description = "Remove stale development flake caches and build symlinks";
wants = [ "nix-gc.service" ];
before = [ "nix-gc.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = lib.getExe devFlakeGarbageCollect;
Nice = 10;
IOSchedulingClass = "idle";
};
};
};
timers.dev-flake-garbage-collect = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "weekly";
Persistent = true;
RandomizedDelaySec = "3h";
};
};
};
nix = {
settings = {

View file

@ -1,4 +1,12 @@
{ pkgs, pkgs-unstable, ... }:
{ pkgs, pkgs-unstable, lib, ... }:
let
commands = import ../../../lib/commands.nix { inherit pkgs; };
systemNotify = commands."system-notify";
notify = urgency: title: body:
"${systemNotify} ${lib.escapeShellArgs [ urgency title body ]}";
notifyFailure = title: service:
"${systemNotify} ${lib.escapeShellArgs [ "critical" title ]} \"${service} ended with: $SERVICE_RESULT\"";
in
{
boot = {
plymouth = {
@ -11,6 +19,7 @@
"udev.log_level=3"
"systemd.show_status=auto"
];
binfmt.emulatedSystems = [ "aarch64-linux" ];
};
security.sudo.wheelNeedsPassword = false;
@ -53,6 +62,34 @@
8888
];
systemd.services = {
nixos-upgrade = {
preStart = lib.mkBefore ''
${notify "normal" "System update started" "Updating flake inputs and preparing the NixOS switch."}
'';
postStop = ''
if [ "$SERVICE_RESULT" = "success" ]; then
${notify "normal" "System update finished" "The automated NixOS update completed successfully."}
else
${notifyFailure "System update failed" "nixos-upgrade.service"}
fi
'';
};
nix-gc = {
preStart = ''
${notify "normal" "Garbage collection started" "Cleaning old Nix generations and unreferenced store paths."}
'';
postStop = ''
if [ "$SERVICE_RESULT" = "success" ]; then
${notify "normal" "Garbage collection finished" "Nix store garbage collection completed successfully."}
else
${notifyFailure "Garbage collection failed" "nix-gc.service"}
fi
'';
};
};
environment = {
systemPackages = [
pkgs-unstable.discord

101
util/dev_flake_gc.sh Normal file
View file

@ -0,0 +1,101 @@
set -o pipefail
retention_days="30"
scan_roots=(
/
/home
/root
/srv
/opt
/tmp
/var/tmp
/var/lib
)
root_seen() {
local candidate="$1"
local seen
for seen in "${seen_roots[@]}"; do
[ "$candidate" = "$seen" ] && return 0
done
return 1
}
has_recent_activity() {
local path="$1"
find "$path" \
-xdev \
\( -name .git -o -name .hg -o -name .svn -o -name node_modules -o -name target \) -prune \
-o -mindepth 1 -mtime "-$retention_days" -print -quit 2>/dev/null \
| grep -q .
}
is_nix_store_symlink() {
local link="$1"
local target
target="$(readlink "$link" 2>/dev/null || true)"
case "$target" in
/nix/store/*) return 0 ;;
*) return 1 ;;
esac
}
cleanup_direnv() {
local direnv_dir="$1"
local project_dir
project_dir="$(dirname "$direnv_dir")"
if [ ! -e "$project_dir/flake.nix" ] \
&& [ ! -e "$direnv_dir/flake-profile" ] \
&& [ ! -e "$direnv_dir/gcroots" ]; then
return
fi
if has_recent_activity "$project_dir"; then
return
fi
echo "Removing stale nix-direnv cache: $direnv_dir"
rm -rf --one-file-system "$direnv_dir"
}
cleanup_result_link() {
local link="$1"
if ! is_nix_store_symlink "$link"; then
return
fi
echo "Removing stale Nix build result symlink: $link"
rm -f "$link"
}
seen_roots=()
for root in "${scan_roots[@]}"; do
[ -d "$root" ] || continue
root="$(readlink -f "$root")"
root_seen "$root" && continue
seen_roots+=("$root")
find "$root" \
-xdev \
\( -path /nix -o -path /proc -o -path /sys -o -path /dev -o -path /run -o -path /boot \) -prune \
-o -type d -name .direnv -mtime "+$retention_days" -print0 2>/dev/null \
| while IFS= read -r -d "" direnv_dir; do
cleanup_direnv "$direnv_dir"
done
find "$root" \
-xdev \
\( -path /nix -o -path /proc -o -path /sys -o -path /dev -o -path /run -o -path /boot \) -prune \
-o -type l \( -name result -o -name "result-*" \) -mtime "+$retention_days" -print0 2>/dev/null \
| while IFS= read -r -d "" link; do
cleanup_result_link "$link"
done
done

23
util/system_notify.sh Normal file
View file

@ -0,0 +1,23 @@
set -o pipefail
target_user="${SYSTEM_NOTIFY_USER:-alisceon}"
urgency="${1:-normal}"
title="${2:-System task}"
body="${3:-}"
uid="$(id -u "$target_user" 2>/dev/null || true)"
[ -n "$uid" ] || exit 0
runtime_dir="/run/user/$uid"
bus="$runtime_dir/bus"
[ -S "$bus" ] || exit 0
runuser -u "$target_user" -- env \
XDG_RUNTIME_DIR="$runtime_dir" \
DBUS_SESSION_BUS_ADDRESS="unix:path=$bus" \
notify-send \
--app-name="NixOS maintenance" \
--urgency="$urgency" \
"$title" \
"$body" \
|| exit 0