Compare commits

...

5 Commits

Author SHA1 Message Date
998ebc1164 feat(programs): add jujutsu(jj) package
All checks were successful
Flake checker / Build Nix targets (push) Successful in 9m41s
2026-02-19 13:51:12 +05:30
9acb378e5f feat: disable some services and disable root login from ssh altogether 2026-02-19 13:41:40 +05:30
dca434c0ba Enable Audacity and add local Ollama provider configuration
- Remove comment from audacity.nix to enable Audacity application
- Add Ollama provider configuration for local LLM access
- Configure glm-4.7-flash model with custom base URL
2026-02-19 00:19:08 +05:30
c22ff38874 feat: Added affine 2026-02-18 18:03:06 +05:30
0591868be3 feat: Added affine server 2026-02-18 17:23:05 +05:30
15 changed files with 337 additions and 39 deletions

9
home/apps/affine.nix Normal file
View File

@@ -0,0 +1,9 @@
{
pkgs,
lib,
...
}: {
home.packages = lib.optionals pkgs.stdenv.isLinux [
pkgs.affine
];
}

View File

@@ -3,9 +3,9 @@
device, device,
... ...
}: }:
lib.optionalAttrs device.hasGui { lib.optionalAttrs device.hasGui {
imports = [ imports = [
# ./audacity.nix ./audacity.nix
# ./bottles.nix # ./bottles.nix
# ./cursor.nix # ./cursor.nix
# ./gimp.nix # ./gimp.nix
@@ -22,6 +22,7 @@ lib.optionalAttrs device.hasGui {
# ./vial.nix # ./vial.nix
# ./vscode.nix # ./vscode.nix
./affine.nix
./blueman.nix ./blueman.nix
./chromium.nix ./chromium.nix
./discord.nix ./discord.nix

View File

@@ -8,20 +8,20 @@
loop-playlist = "inf"; loop-playlist = "inf";
}; };
profiles = { profiles = {
hdr = { # hdr = {
vo = "gpu-next"; # vo = "gpu-next";
gpu-api = "vulkan"; # gpu-api = "vulkan";
hdr-compute-peak = "yes"; # hdr-compute-peak = "yes";
hdr-peak-detect = "yes"; # hdr-peak-detect = "yes";
target-peak = 400; # target-peak = 400;
target-prim = "bt.2020"; # target-prim = "bt.2020";
target-trc = "pq"; # target-trc = "pq";
inverse-tone-mapping = "yes"; # inverse-tone-mapping = "yes";
tone-mapping = "spline"; # tone-mapping = "spline";
tone-mapping-mode = "auto"; # tone-mapping-mode = "auto";
target-colorspace-hint = "auto"; # target-colorspace-hint = "auto";
gamut-mapping = "desaturate"; # gamut-mapping = "desaturate";
}; # };
}; };
}; };
} }

View File

@@ -13,6 +13,7 @@
}; };
}; };
home.packages = with pkgs; [ home.packages = with pkgs; [
pulseaudio # pulseaudio
playerctl
]; ];
} }

View File

@@ -80,5 +80,6 @@
./zoxide.nix ./zoxide.nix
./attic.nix ./attic.nix
./cfcli.nix ./cfcli.nix
./jujutsu.nix
]; ];
} }

View File

@@ -0,0 +1 @@
{pkgs, ...}: {home.packages = [pkgs.jujutsu];}

View File

@@ -6,5 +6,20 @@
lib.optionalAttrs (device.is "ryu" || device.is "kuro") { lib.optionalAttrs (device.is "ryu" || device.is "kuro") {
programs.opencode = { programs.opencode = {
enable = true; enable = true;
settings.provider = {
ollama = {
models = {
"glm-4.7-flash" = {
# "_launch" = true;
name = "glm-4.7-flash";
};
};
name = "Ollama (local)";
npm = "@ai-sdk/openai-compatible";
options = {
baseURL = "https://ollama.darksailor.dev/v1";
};
};
};
}; };
} }

166
modules/nixos/affine.nix Normal file
View File

@@ -0,0 +1,166 @@
{
config,
lib,
...
}:
with lib; let
cfg = config.services.affine;
dbName = "affine";
dbUser = "affine";
in {
options.services.affine = {
enable = mkEnableOption "AFFiNE self-hosted workspace";
port = mkOption {
type = types.port;
default = 3010;
description = "Port for the AFFiNE server to listen on";
};
domain = mkOption {
type = types.str;
description = "Public domain for AFFiNE (e.g. notes.darksailor.dev)";
};
imageTag = mkOption {
type = types.str;
default = "stable";
description = "Docker image tag for AFFiNE (stable, beta, canary)";
};
dataDir = mkOption {
type = types.str;
default = "/var/lib/affine";
description = "Base data directory for AFFiNE storage";
};
environmentFiles = mkOption {
type = types.listOf types.path;
default = [];
description = "Environment files containing secrets (DB password, etc.)";
};
};
config = mkIf cfg.enable {
# Create data directories
systemd.tmpfiles.rules = [
"d ${cfg.dataDir} 0755 root root -"
"d ${cfg.dataDir}/storage 0755 root root -"
"d ${cfg.dataDir}/config 0755 root root -"
"d ${cfg.dataDir}/postgres 0700 root root -"
"d ${cfg.dataDir}/redis 0755 root root -"
];
virtualisation.oci-containers = {
backend = "docker";
containers = {
affine-postgres = {
image = "pgvector/pgvector:pg16";
volumes = [
"${cfg.dataDir}/postgres:/var/lib/postgresql/data"
];
environment = {
POSTGRES_USER = dbUser;
POSTGRES_DB = dbName;
POSTGRES_INITDB_ARGS = "--data-checksums";
POSTGRES_HOST_AUTH_METHOD = "trust";
};
environmentFiles = cfg.environmentFiles;
extraOptions = [
"--network=affine-net"
"--health-cmd=pg_isready -U ${dbUser} -d ${dbName}"
"--health-interval=10s"
"--health-timeout=5s"
"--health-retries=5"
];
};
affine-redis = {
image = "redis:7";
volumes = [
"${cfg.dataDir}/redis:/data"
];
extraOptions = [
"--network=affine-net"
"--health-cmd=redis-cli --raw incr ping"
"--health-interval=10s"
"--health-timeout=5s"
"--health-retries=5"
];
};
affine = {
image = "ghcr.io/toeverything/affine:${cfg.imageTag}";
ports = ["127.0.0.1:${toString cfg.port}:3010"];
dependsOn = [
"affine-postgres"
"affine-redis"
"affine-migration"
];
volumes = [
"${cfg.dataDir}/storage:/root/.affine/storage"
"${cfg.dataDir}/config:/root/.affine/config"
];
environment = {
AFFINE_SERVER_PORT = "3010";
AFFINE_SERVER_HOST = cfg.domain;
AFFINE_SERVER_HTTPS = "true";
AFFINE_SERVER_EXTERNAL_URL = "https://${cfg.domain}";
REDIS_SERVER_HOST = "affine-redis";
DATABASE_URL = "postgresql://${dbUser}:$${AFFINE_DB_PASSWORD:-affine}@affine-postgres:5432/${dbName}";
AFFINE_INDEXER_ENABLED = "false";
};
environmentFiles = cfg.environmentFiles;
extraOptions = [
"--network=affine-net"
];
};
affine-migration = {
image = "ghcr.io/toeverything/affine:${cfg.imageTag}";
dependsOn = [
"affine-postgres"
"affine-redis"
];
volumes = [
"${cfg.dataDir}/storage:/root/.affine/storage"
"${cfg.dataDir}/config:/root/.affine/config"
];
cmd = ["sh" "-c" "node ./scripts/self-host-predeploy.js"];
environment = {
REDIS_SERVER_HOST = "affine-redis";
DATABASE_URL = "postgresql://${dbUser}:$${AFFINE_DB_PASSWORD:-affine}@affine-postgres:5432/${dbName}";
AFFINE_INDEXER_ENABLED = "false";
};
environmentFiles = cfg.environmentFiles;
extraOptions = [
"--network=affine-net"
];
};
};
};
# Create the Docker network
systemd.services.affine-network = {
description = "Create AFFiNE Docker network";
after = ["docker.service"];
wantedBy = ["multi-user.target"];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${config.virtualisation.docker.package}/bin/docker network create affine-net";
ExecStop = "${config.virtualisation.docker.package}/bin/docker network remove affine-net";
};
};
# Ensure containers start after the network is created
systemd.services.docker-affine.after = ["affine-network.service"];
systemd.services.docker-affine.requires = ["affine-network.service"];
systemd.services.docker-affine-postgres.after = ["affine-network.service"];
systemd.services.docker-affine-postgres.requires = ["affine-network.service"];
systemd.services.docker-affine-redis.after = ["affine-network.service"];
systemd.services.docker-affine-redis.requires = ["affine-network.service"];
systemd.services.docker-affine-migration.after = ["affine-network.service"];
systemd.services.docker-affine-migration.requires = ["affine-network.service"];
};
}

View File

@@ -2,6 +2,7 @@
pkgs, pkgs,
lib, lib,
device, device,
config,
... ...
}: { }: {
imports = [ imports = [
@@ -47,6 +48,7 @@
auto-optimise-store = true; auto-optimise-store = true;
extra-experimental-features = "nix-command flakes auto-allocate-uids"; extra-experimental-features = "nix-command flakes auto-allocate-uids";
trusted-users = [device.user]; trusted-users = [device.user];
extra-sandbox-paths = [config.programs.ccache.cacheDir];
}; };
extraOptions = '' extraOptions = ''
build-users-group = nixbld build-users-group = nixbld

View File

@@ -0,0 +1,6 @@
{...}: {
programs.ccache = {
enable = true;
packageNames = ["ollama" "orca-slicer" "opencv" "onnxruntime" "obs-studio" "llama-cpp"];
};
}

View File

@@ -0,0 +1,89 @@
{config, ...}: let
domain = "notes.darksailor.dev";
in {
imports = [
../../../modules/nixos/affine.nix
];
# SOPS secrets
sops = {
secrets = {
"affine/db_password" = {};
"authelia/oidc/affine/client_id" = {
owner = config.systemd.services.authelia-darksailor.serviceConfig.User;
mode = "0440";
restartUnits = ["authelia-darksailor.service"];
};
"authelia/oidc/affine/client_secret" = {
owner = config.systemd.services.authelia-darksailor.serviceConfig.User;
mode = "0440";
restartUnits = ["authelia-darksailor.service"];
};
};
templates."affine.env".content = ''
AFFINE_DB_PASSWORD=${config.sops.placeholder."affine/db_password"}
POSTGRES_PASSWORD=${config.sops.placeholder."affine/db_password"}
AFFINE_SERVER_EXTERNAL_URL=https://${domain}
'';
};
# Enable AFFiNE service
services.affine = {
enable = true;
inherit domain;
environmentFiles = [
config.sops.templates."affine.env".path
];
};
# Caddy reverse proxy with SSO forward auth
services.caddy.virtualHosts."${domain}".extraConfig = ''
reverse_proxy localhost:${toString config.services.affine.port}
'';
# Authelia access control rules
services.authelia.instances.darksailor.settings = {
access_control.rules = [
{
inherit domain;
policy = "bypass";
resources = [
"^/api/(sync|awareness)([/?].*)?$"
"^/socket\\.io([/?].*)?$"
];
}
{
inherit domain;
policy = "one_factor";
}
];
# OIDC client for AFFiNE
identity_providers.oidc.clients = [
{
client_name = "AFFiNE: Darksailor";
client_id = ''{{ secret "${config.sops.secrets."authelia/oidc/affine/client_id".path}" }}'';
client_secret = ''{{ secret "${config.sops.secrets."authelia/oidc/affine/client_secret".path}" }}'';
public = false;
authorization_policy = "one_factor";
require_pkce = false;
redirect_uris = [
"https://${domain}/oauth/callback"
];
scopes = [
"openid"
"email"
"profile"
];
response_types = ["code"];
grant_types = ["authorization_code"];
userinfo_signed_response_alg = "none";
token_endpoint_auth_method = "client_secret_post";
}
];
};
# Ensure containers start after secrets are available
systemd.services.docker-affine.after = ["sops-install-secrets.service"];
systemd.services.docker-affine-migration.after = ["sops-install-secrets.service"];
systemd.services.docker-affine-postgres.after = ["sops-install-secrets.service"];
}

View File

@@ -1,31 +1,33 @@
{...}: { {...}: {
imports = [ imports = [
./attic.nix
./atuin.nix ./atuin.nix
./authelia.nix ./authelia.nix
./caddy.nix ./caddy.nix
./excalidraw.nix
./fail2ban.nix ./fail2ban.nix
./flaresolverr.nix
./games
./gitea.nix
./homepage.nix ./homepage.nix
./immich.nix
./kellnr.nix
./lldap.nix ./lldap.nix
./llms.nix
./matrix
./monitoring.nix
./navidrome.nix ./navidrome.nix
./nextcloud.nix ./nextcloud.nix
./openssh.nix ./openssh.nix
./prowlarr.nix
./resolved.nix ./resolved.nix
./searxng.nix
./shitpost.nix
./tailscale.nix ./tailscale.nix
./gitea.nix
./affine.nix
./attic.nix
./excalidraw.nix
./flaresolverr.nix
# ./games
# ./headscale.nix # ./headscale.nix
./immich.nix
./kellnr.nix
# ./llms.nix
./matrix
# ./monitoring.nix
# ./paperless.nix # ./paperless.nix
./prowlarr.nix
# ./searxng.nix
# ./shitpost.nix
]; ];
services = { services = {
nix-serve = { nix-serve = {

View File

@@ -34,12 +34,12 @@
}; };
}; };
}; };
# headplane = { headplane = {
# enable = true; enable = true;
# settings = { settings = {
# server.port = 42562; server.port = 42562;
# }; };
# }; };
caddy = { caddy = {
virtualHosts."headscale.darksailor.dev".extraConfig = '' virtualHosts."headscale.darksailor.dev".extraConfig = ''
reverse_proxy localhost:${toString config.services.headplane.settings.server.port} reverse_proxy localhost:${toString config.services.headplane.settings.server.port}

View File

@@ -2,6 +2,6 @@
services.openssh = { services.openssh = {
enable = true; enable = true;
settings.PasswordAuthentication = false; settings.PasswordAuthentication = false;
settings.PermitRootLogin = "prohibit-password"; settings.PermitRootLogin = "no";
}; };
} }

View File

@@ -53,6 +53,9 @@ authelia:
excalidraw: excalidraw:
client_id: ENC[AES256_GCM,data:ANaCFTiPnR/bP51lSMfiTRX7ZGZ2pmX3Guamsyj7KRzD34G18E+UUgXi0YdbDfmFxcEj+nvoerf7wWhtvIzO1Q==,iv:CyNiLA0PH0p1Zwdf8B6/Ysb6GODClnXkPctbtZnoddw=,tag:X3kAkBKD407QFg/Se33Flg==,type:str] client_id: ENC[AES256_GCM,data:ANaCFTiPnR/bP51lSMfiTRX7ZGZ2pmX3Guamsyj7KRzD34G18E+UUgXi0YdbDfmFxcEj+nvoerf7wWhtvIzO1Q==,iv:CyNiLA0PH0p1Zwdf8B6/Ysb6GODClnXkPctbtZnoddw=,tag:X3kAkBKD407QFg/Se33Flg==,type:str]
client_secret: ENC[AES256_GCM,data:VHIbKjHWXfQCUp3wh2dsMpMaDdCabmVlLMHcMnTCXPr5ZNIS1zpyGD6keapoOYywwvDFenICf73vpHun5aFhLw==,iv:HjRTwREC2jMsW1VrVYe4iywGc9apWZWLwh5aHOjvde0=,tag:Jl9kDI8C9VjSm6SiePk7Ow==,type:str] client_secret: ENC[AES256_GCM,data:VHIbKjHWXfQCUp3wh2dsMpMaDdCabmVlLMHcMnTCXPr5ZNIS1zpyGD6keapoOYywwvDFenICf73vpHun5aFhLw==,iv:HjRTwREC2jMsW1VrVYe4iywGc9apWZWLwh5aHOjvde0=,tag:Jl9kDI8C9VjSm6SiePk7Ow==,type:str]
affine:
client_id: ENC[AES256_GCM,data:riwC/9GuHamkV7U80+qCXP/F2wP0volVmRXtkVOQu7NfBb9OlSnamMvVh1pRNHj4c3AZWHpYIIHpkhuNKUuD+A==,iv:gi70CRZqRYfvHq7JhY+N3rX3Trb7eLqgmUlFqLk7p+4=,tag:M6MzyKRTJpZsznXzvxQINQ==,type:str]
client_secret: ENC[AES256_GCM,data:/4+606H4s50+E25LOaVRi5Vt0rpzg9mAHSonYaLASPW/jEwAxwTNunWGvOg4ydjF+D9VBUbYcp1krZnlrhDp9sRR81vf+1G9aA69mWVPF7aMjBx5wA44tBszjLc/KKx804qbopG1m4y828aPrFvknx2d7Rox/YkvhLoq5jPjyVU=,iv:9s4OQNTtPBcN+7kvtH9u9kkPadFG7MG0LdlHAhMR5sw=,tag:BV0G1f/5qGAfrdRMshHzYw==,type:str]
lldap: lldap:
jwt: ENC[AES256_GCM,data:61dwC1ElOOGaf0CmalzXZnxImEyufKjUUWcNaEcOuv3TEODhQyHK7g==,iv:CVEJVuaCc2gDmSYWHS3fPL8FjbvblF6IladAzGoGb0o=,tag:OMm/OdKjliHjsGqJripLbg==,type:str] jwt: ENC[AES256_GCM,data:61dwC1ElOOGaf0CmalzXZnxImEyufKjUUWcNaEcOuv3TEODhQyHK7g==,iv:CVEJVuaCc2gDmSYWHS3fPL8FjbvblF6IladAzGoGb0o=,tag:OMm/OdKjliHjsGqJripLbg==,type:str]
seed: ENC[AES256_GCM,data:jJPutPkhFVFxLbbQNZznHHiilP/cN2r+/vT4ArQVRQSqPMnkkwgc3LNk4sUTrT9V,iv:LD1IJ1CgtDfYf1gSyyaU+hir0InuDEq0u7ppMmwGJRY=,tag:cK4l4Evr7V9WEUEL7V9jtQ==,type:str] seed: ENC[AES256_GCM,data:jJPutPkhFVFxLbbQNZznHHiilP/cN2r+/vT4ArQVRQSqPMnkkwgc3LNk4sUTrT9V,iv:LD1IJ1CgtDfYf1gSyyaU+hir0InuDEq0u7ppMmwGJRY=,tag:cK4l4Evr7V9WEUEL7V9jtQ==,type:str]
@@ -101,6 +104,8 @@ livekit:
key_secret: ENC[AES256_GCM,data:n0SH6SLYXOwdjJ5nNku0Pg6/DZxmYG7iLfNNDbKlvF9DiCDxfn2ag1fToxWGz0qrAvqV6b3PdD123BURDzJ+gQ==,iv:1Pix12Pxr/kX/SqRWHOaSdccIZTQsSoFVGXYNyx2Rfo=,tag:QG1qDJPBUUtlih+TcXXsRQ==,type:str] key_secret: ENC[AES256_GCM,data:n0SH6SLYXOwdjJ5nNku0Pg6/DZxmYG7iLfNNDbKlvF9DiCDxfn2ag1fToxWGz0qrAvqV6b3PdD123BURDzJ+gQ==,iv:1Pix12Pxr/kX/SqRWHOaSdccIZTQsSoFVGXYNyx2Rfo=,tag:QG1qDJPBUUtlih+TcXXsRQ==,type:str]
coturn: coturn:
static_auth_secret: ENC[AES256_GCM,data:osEBYgWGZl+SnqVV1G9IxMys/qDm6WTtj4nILYVw0klDjiB6vd21yA0ik/rLv9E6Y539uMCk3oB0NS7I72U1hQ==,iv:jruS3vfe0fVHY67qNhEgaCEp/9cR57UIu8a/LhdTC1o=,tag:vhxXhh9u4bOSu/lxINjvew==,type:str] static_auth_secret: ENC[AES256_GCM,data:osEBYgWGZl+SnqVV1G9IxMys/qDm6WTtj4nILYVw0klDjiB6vd21yA0ik/rLv9E6Y539uMCk3oB0NS7I72U1hQ==,iv:jruS3vfe0fVHY67qNhEgaCEp/9cR57UIu8a/LhdTC1o=,tag:vhxXhh9u4bOSu/lxINjvew==,type:str]
affine:
db_password: ENC[AES256_GCM,data:AbpoEbmeihtVIoRaWxVL8+v3oCk5iiia9qZLKgyy98qTuNZruiaV3kQN6clYvWgHbzJta5/H9e+xocrEtw8C/A==,iv:2vPeDAJuVujPgM+kr6AFAvat2MCJnsblebx23Ey7YNA=,tag:ukuK30aZ//MKabhSRtLNXw==,type:str]
sops: sops:
age: age:
- recipient: age1pw7kluxp7872c63ne4jecq75glj060jkmqwzkk6esatuyck9egfswufdpk - recipient: age1pw7kluxp7872c63ne4jecq75glj060jkmqwzkk6esatuyck9egfswufdpk
@@ -112,7 +117,7 @@ sops:
VGZKdHpVeFRpQUxtSEkyaEhLMlBJcGsKLb0DvPNZosPBUuiX6qz1s5IO5INQh8CK VGZKdHpVeFRpQUxtSEkyaEhLMlBJcGsKLb0DvPNZosPBUuiX6qz1s5IO5INQh8CK
ZtXTVClwMSmaUYhdSB2gKFrKVZHXTJZ4oAL5t/BpC0pOHyr+o96T3Q== ZtXTVClwMSmaUYhdSB2gKFrKVZHXTJZ4oAL5t/BpC0pOHyr+o96T3Q==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2026-02-12T13:19:01Z" lastmodified: "2026-02-18T10:39:02Z"
mac: ENC[AES256_GCM,data:IVU1PbDwH1JKG3qPOtmfMZr7BJ7zR/UGQ167Tyf62w5V1gaiVoeqjD8/MR6OSvhMDNYxjJXRKg9E9N8q4JRxok34v5zOfqWchnXEP9wIS39kgsYJ1Hra7hOryd5n49/Xkwyen6f1VSe1nkKtldWS9XHwDBZRrSE+kaXcZTQmKIY=,iv:WLRVIEzR0MFsY6EAgyXZCHQz/xD4cSaeikA8nZqHy38=,tag:+TyOvwWkHa4fHYonKBfxyg==,type:str] mac: ENC[AES256_GCM,data:fz+15A9C6G4x3OUzoKY3yvUt75dx2aql2GEmnuJcPM1YC9KN083PodKQR1axr23w7C9S2/iTXEnYJhx3X+dfoJbTRWKVvraGHWQ9w5jbjVMVfU+97JxrtykdwXKmwlzTbF4lakHd4dWRv5e9aR7vN2JX1NUd9EuazQ0/xPeIVOQ=,iv:l4/r/poWY5IdKrM0IxbdWfg6JB7r+tssh9LIZDSNr8w=,tag:HE3C7LzWrzCKE91VdZnqXg==,type:str]
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.11.0 version: 3.11.0