feat: rewrite #1

Merged
sadorowo merged 18 commits from feature/server into main 2025-07-02 19:31:03 +02:00
110 changed files with 3062 additions and 178 deletions

1
.gitignore vendored
View file

@ -1,2 +1 @@
hardware-configuration.nix
calib-data.bin

110
README.md Executable file
View file

@ -0,0 +1,110 @@
# ❄️ my NixOS dotfiles
Configuration files for my NixOS **hosts**:
- *hulk* - main laptop
- *odin* - second Lenovo laptop
- *thor* - my old PC, now my home server
## Basic information
### hulk
- Terminal: **Alacritty**
- Window manager: **Hyprland**
- Windowing system: **Wayland**
- Shell: **fish**
- Editor: **vim**, **VSCodium**
- Browser: **Firefox**
- DE: **ags** with custom dotfiles
### thor
- Shell: **zsh**
- Editor: **vim**
### odin
- Terminal: **Konsole**
- DE: **KDE Plasma**
- Shell: **fish**
- Browser: **Firefox**
## Basic commands
1. Switch configuration
```
# nixos-rebuild switch --flake /etc/nixos#<hostname> --fast
```
2. Switch **Home Manager** configuration (if it's present)
```
home-manager switch --flake /etc/nixos
```
3. Connect to Wi-Fi if NetworkManager is enabled on the host
```
nmcli device wifi connect <ssid> password "<password>"
```
## How to install
> [!CAUTION]
>
> Please **DO NOT** use my **hardware-configuration.nix**! These files include settings that are specific for MY HOSTS. Yours will be different!
1. Clone the repo, for example to `~/.config/dotfiles`:
```
git clone https://git.sador.me/sadorowo/nixos ~/.config/dotfiles && cd ~/.config/dotfiles
```
2. Create a hardware configuration for your system:
```
sudo nixos-generate-config
```
3. Copy your hardware configuration to the desired host (we assume that you will be running my desktop host, called **hulk**):
```
cp /etc/nixos/hardware-configuration.nix ~/.config/nixos/hosts/hulk/
```
4. Finally, build your desired configuration using
```
sudo nixos-rebuild switch --flake /etc/nixos#hulk
```
## Directory structure
```
├── hosts
│   ├── base-configuration.nix
│   ├── default.nix
│   └── <host>
│ ├── secrets
│ │ └── *.age
│      ├── default.nix
│      ├── hardware-configuration.nix
│      ├── modules.nix
│      ├── users.nix
│      └── ...
├── modules
│   ├── derivations
│   │   └── ...
│   ├── desktop-environments
│   │   └── ...
│   ├── home-manager
│   │   └── ...
│   └── nixos
│   └── ...
├── profiles
│   ├── default.nix
│   └── <user profile>
│      └── ...
│   ├── secrets.nix
│   └── <host>
│   └── ...
├── shells
│   └── ...
├── flake.lock
├── flake.nix
├── overlay.nix
├── preferences.nix
└── TODO.md
```
- **hosts** - directory where system configurations live.
- **hosts/<host>/secrets** - place for host-specific Agenix secrets.
- **modules** - custom NixOS & Home Manager modules, also a place for my own derivations.
- **profiles** - Home Manager configs.
- **shells** - useful (for me!) shells, e.g. `nix develop /etc/nixos#android`.
- <ins>preferences.nix</ins> - a place for system-specific preferences that are NOT secrets.
- <ins>overlay.nix</ins> - my custom Nixpkgs overlay.
## Finally...
Hope you will enjoy!

3
TODO.md Normal file → Executable file
View file

@ -1,4 +1,5 @@
* [ ] Simplify config
* [ ] Deploy *sador.me* website using NixOS
* [x] Simplify config
* [x] Organize most common apps with modules
* [x] Migrate from pywal + apple-fonts to Stylix (theme, cursor, fonts, ...)
* [x] Remove clutter

251
flake.lock generated Normal file → Executable file
View file

@ -1,5 +1,26 @@
{
"nodes": {
"agenix": {
"inputs": {
"darwin": "darwin",
"home-manager": "home-manager",
"nixpkgs": "nixpkgs",
"systems": "systems"
},
"locked": {
"lastModified": 1747575206,
"narHash": "sha256-NwmAFuDUO/PFcgaGGr4j3ozG9Pe5hZ/ogitWhY+D81k=",
"owner": "ryantm",
"repo": "agenix",
"rev": "4835b1dc898959d8547a871ef484930675cb47f1",
"type": "github"
},
"original": {
"owner": "ryantm",
"repo": "agenix",
"type": "github"
}
},
"ags": {
"inputs": {
"astal": "astal",
@ -45,7 +66,7 @@
},
"apple-emoji": {
"inputs": {
"nixpkgs": "nixpkgs"
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1711624089,
@ -63,7 +84,7 @@
},
"apple-fonts": {
"inputs": {
"nixpkgs": "nixpkgs_2",
"nixpkgs": "nixpkgs_3",
"ny": "ny",
"sf-arabic": "sf-arabic",
"sf-armenian": "sf-armenian",
@ -175,6 +196,28 @@
"type": "github"
}
},
"darwin": {
"inputs": {
"nixpkgs": [
"agenix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1744478979,
"narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "43975d782b418ebf4969e9ccba82466728c2851b",
"type": "github"
},
"original": {
"owner": "lnl7",
"ref": "master",
"repo": "nix-darwin",
"type": "github"
}
},
"devshell": {
"inputs": {
"nixpkgs": [
@ -198,7 +241,7 @@
},
"fingerprint-sensor": {
"inputs": {
"nixpkgs": "nixpkgs_3"
"nixpkgs": "nixpkgs_4"
},
"locked": {
"lastModified": 1734692513,
@ -269,7 +312,7 @@
},
"flake-utils": {
"inputs": {
"systems": "systems"
"systems": "systems_2"
},
"locked": {
"lastModified": 1731533236,
@ -285,6 +328,26 @@
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": [
"piped",
"systems"
]
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"id": "flake-utils",
"type": "indirect"
}
},
"fromYaml": {
"flake": false,
"locked": {
@ -367,6 +430,27 @@
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
"agenix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1745494811,
"narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"home-manager_2": {
"inputs": {
"nixpkgs": [
"nixpkgs"
@ -387,7 +471,7 @@
"type": "github"
}
},
"home-manager_2": {
"home-manager_3": {
"inputs": {
"nixpkgs": [
"stylix",
@ -410,6 +494,22 @@
}
},
"nixpkgs": {
"locked": {
"lastModified": 1745391562,
"narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1711523803,
"narHash": "sha256-UKcYiHWHQynzj6CN/vTcix4yd1eCu1uFdsuarupdCQQ=",
@ -425,7 +525,7 @@
"type": "github"
}
},
"nixpkgs_2": {
"nixpkgs_3": {
"locked": {
"lastModified": 1740828860,
"narHash": "sha256-cjbHI+zUzK5CPsQZqMhE3npTyYFt9tJ3+ohcfaOF/WM=",
@ -441,7 +541,7 @@
"type": "github"
}
},
"nixpkgs_3": {
"nixpkgs_4": {
"locked": {
"lastModified": 1746055187,
"narHash": "sha256-3dqArYSMP9hM7Qpy5YWhnSjiqniSaT2uc5h2Po7tmg0=",
@ -456,18 +556,34 @@
"type": "indirect"
}
},
"nixpkgs_4": {
"nixpkgs_5": {
"locked": {
"lastModified": 1747953325,
"narHash": "sha256-y2ZtlIlNTuVJUZCqzZAhIw5rrKP4DOSklev6c8PyCkQ=",
"lastModified": 1751011381,
"narHash": "sha256-krGXKxvkBhnrSC/kGBmg5MyupUUT5R6IBCLEzx9jhMM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "55d1f923c480dadce40f5231feb472e81b0bab48",
"rev": "30e2e2857ba47844aa71991daa6ed1fc678bcbb7",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.05",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_6": {
"locked": {
"lastModified": 1750330365,
"narHash": "sha256-hJ7XMNVsTnnbV2NPmStCC07gvv5l2x7+Skb7hyUzazg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d883b6213afa179b58ba8bace834f1419707d0ad",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.11",
"repo": "nixpkgs",
"type": "github"
}
@ -510,15 +626,88 @@
"url": "https://devimages-cdn.apple.com/design/resources/download/NY.dmg"
}
},
"piped": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_6",
"piped-backend-src": "piped-backend-src",
"piped-frontend-src": "piped-frontend-src",
"piped-proxy-src": "piped-proxy-src",
"systems": "systems_3"
},
"locked": {
"lastModified": 1749623495,
"narHash": "sha256-pxlPXLxg1Kv3VY8xW7XIzBE5IE5+57ZfO2rRYAZ+puo=",
"owner": "squalus",
"repo": "piped-flake",
"rev": "1ccd541a318d9bef4143d33bd88b26c708228d1b",
"type": "github"
},
"original": {
"owner": "squalus",
"repo": "piped-flake",
"type": "github"
}
},
"piped-backend-src": {
"flake": false,
"locked": {
"lastModified": 1748680914,
"narHash": "sha256-alCbhGpJiXhtqlaXiVzuGfxhbL3EGkpLUPSMjDUXDAY=",
"owner": "TeamPiped",
"repo": "piped-backend",
"rev": "dc834a374713305fc8d1b9e058c3538b6e47ded9",
"type": "github"
},
"original": {
"owner": "TeamPiped",
"repo": "piped-backend",
"type": "github"
}
},
"piped-frontend-src": {
"flake": false,
"locked": {
"lastModified": 1748113384,
"narHash": "sha256-AOQ1z/A74Tg/LwLD5mzvKnTtNOFogv6MY+l67rtKD/4=",
"owner": "TeamPiped",
"repo": "Piped",
"rev": "30a0ce334ea81dcc8f9a30869fdf1654611f9963",
"type": "github"
},
"original": {
"owner": "TeamPiped",
"repo": "Piped",
"type": "github"
}
},
"piped-proxy-src": {
"flake": false,
"locked": {
"lastModified": 1749582520,
"narHash": "sha256-oiTaOD5vvOz35K7isMSkD1+oMBQm/1Gpv44nsFcPE7w=",
"owner": "TeamPiped",
"repo": "piped-proxy",
"rev": "d01f06ea0f0f716f51d8d0e541f6da994788c72b",
"type": "github"
},
"original": {
"owner": "TeamPiped",
"repo": "piped-proxy",
"type": "github"
}
},
"root": {
"inputs": {
"agenix": "agenix",
"ags": "ags",
"android-nixpkgs": "android-nixpkgs",
"apple-emoji": "apple-emoji",
"apple-fonts": "apple-fonts",
"fingerprint-sensor": "fingerprint-sensor",
"home-manager": "home-manager",
"nixpkgs": "nixpkgs_4",
"home-manager": "home-manager_2",
"nixpkgs": "nixpkgs_5",
"piped": "piped",
"stylix": "stylix"
}
},
@ -617,12 +806,12 @@
"flake-parts": "flake-parts",
"git-hooks": "git-hooks",
"gnome-shell": "gnome-shell",
"home-manager": "home-manager_2",
"home-manager": "home-manager_3",
"nixpkgs": [
"nixpkgs"
],
"nur": "nur",
"systems": "systems_2",
"systems": "systems_4",
"tinted-foot": "tinted-foot",
"tinted-kitty": "tinted-kitty",
"tinted-schemes": "tinted-schemes",
@ -674,6 +863,36 @@
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
"owner": "nix-systems",
"repo": "default-linux",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default-linux",
"type": "github"
}
},
"systems_4": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"tinted-foot": {
"flake": false,
"locked": {

13
flake.nix Normal file → Executable file
View file

@ -1,6 +1,6 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager/release-25.05";
apple-fonts.url = "github:Lyndeno/apple-fonts.nix";
@ -9,11 +9,14 @@
fingerprint-sensor.url = "github:ahbnr/nixos-06cb-009a-fingerprint-sensor/24.11";
android-nixpkgs.url = "github:tadfisher/android-nixpkgs";
piped.url = "github:squalus/piped-flake";
agenix.url = "github:ryantm/agenix";
ags.url = "github:Aylur/ags";
android-nixpkgs.inputs.nixpkgs.follows = "nixpkgs";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
stylix.inputs.nixpkgs.follows = "nixpkgs";
#piped.inputs.nixpkgs.follows = "nixpkgs";
ags.inputs.nixpkgs.follows = "nixpkgs";
};
@ -21,7 +24,6 @@
{
self,
nixpkgs,
android-nixpkgs,
...
}@inputs:
let
@ -34,11 +36,14 @@
in
{
nixosConfigurations = import ./hosts { inherit self prefs; };
homeConfigurations = import ./profiles { inherit self prefs; };
homeConfigurations = import ./profiles { inherit self prefs; };
devShells = forAllSystems (
system:
let pkgs = prefs.nixpkgs system; in {
let
pkgs = prefs.nixpkgs system;
in
{
ddt4all = import ./shells/ddt4all.nix { inherit pkgs; };
android = import ./shells/android.nix { inherit pkgs; };
dioxus = import ./shells/dioxus.nix { inherit pkgs; };

12
hosts/base-configuration.nix Normal file → Executable file
View file

@ -1,9 +1,19 @@
{ config, prefs, pkgs, ... }:
{
config,
pkgs,
...
}:
{
# DO NOT change this unless you know what you're doing!
system.stateVersion = "24.11";
boot.kernel.sysctl."net.ipv4.ip_forward" = 0;
networking.networkmanager = {
enable = true;
wifi.powersave = true;
};
# Enable cache
nix.settings = {
substituters = [

56
hosts/default.nix Normal file → Executable file
View file

@ -3,6 +3,33 @@
let
inherit (self) inputs;
lib = inputs.nixpkgs.lib;
mkUser = pkgs: host: let
inherit (prefs.users.${host})
username
fullname
isRoot
homeDirectory
preferredShell;
in
{
users.users.${username} = {
isNormalUser = lib.mkIf (!isRoot) true;
isSystemUser = lib.mkIf isRoot true;
description = fullname;
home = homeDirectory;
group = "users";
extraGroups = [
"wheel"
"networkmanager"
"plugdev"
"video"
];
ignoreShellProgramCheck = true;
shell = preferredShell pkgs;
};
};
mkSystem =
{
@ -10,26 +37,31 @@ let
hostname,
useHomeManager ? true,
modules ? [ ],
}: let pkgs = prefs.nixpkgs system; in lib.nixosSystem {
}:
let
pkgs = prefs.nixpkgs system;
in
lib.nixosSystem {
inherit pkgs;
specialArgs = { inherit inputs prefs; };
modules = modules
specialArgs = { inherit self inputs prefs; };
modules =
modules
++ [
./base-configuration.nix
./${hostname}
] ++ lib.lists.optionals useHomeManager [
(mkUser pkgs hostname)
]
++ lib.lists.optionals useHomeManager [
{ environment.systemPackages = [ pkgs.home-manager ]; }
inputs.home-manager.nixosModules.default {
inputs.home-manager.nixosModules.default
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
}
];
};
in
{
hulk = mkSystem {
system = "x86_64-linux";
hostname = "hulk";
};
}
in builtins.mapAttrs (name: config:
mkSystem (config // {
hostname = name;
})) prefs.hosts

19
hosts/hulk/default.nix Normal file → Executable file
View file

@ -1,13 +1,24 @@
{ pkgs, ... }:
{
config,
prefs,
pkgs,
lib,
...
}:
let
inherit (prefs.users.hulk) username;
in {
imports = [
./hardware-configuration.nix
./modules.nix
./users.nix
./networking.nix
];
users.users.${username}.extraGroups = lib.lists.optionals (config.modules
? nordvpn
&& config.modules.nordvpn.enable
) [ "nordvpn" ];
nix.settings = {
experimental-features = [
"nix-command"

0
hosts/hulk/hardware-configuration.nix Normal file → Executable file
View file

6
hosts/hulk/modules.nix Normal file → Executable file
View file

@ -12,15 +12,11 @@
modules.fingerprint.enable = true;
modules.bluetooth.enable = true;
modules.greetd.enable = true;
modules.nvidia.enable = true;
modules.audio.enable = true;
security.rtkit.enable = true;
modules.greetd = {
enable = true;
command = "Hyprland";
};
services = {
gvfs.enable = true;
upower.enable = true;

View file

@ -1,15 +0,0 @@
{ pkgs, ... }:
let
networkManagerEnabled = true;
wirelessEnabled = false;
in
{
networking.networkmanager.enable = pkgs.lib.mkIf networkManagerEnabled true;
networking.networkmanager.wifi.powersave = pkgs.lib.mkIf networkManagerEnabled true;
networking.wireless.enable = pkgs.lib.mkIf wirelessEnabled true;
networking.wireless.userControlled.enable = pkgs.lib.mkIf wirelessEnabled true;
boot.kernel.sysctl."net.ipv4.ip_forward" = 0;
}

View file

@ -1,32 +0,0 @@
{
pkgs,
prefs,
config,
...
}:
let
inherit (prefs.users.hulk)
username
fullname
isRoot
homeDirectory
preferredShell
;
optional = pkgs.lib.lists.optionals;
in
{
users.users.${username} = {
isNormalUser = !isRoot;
description = fullname;
home = homeDirectory;
extraGroups = [
"wheel"
"networkmanager"
"plugdev"
"adbusers"
] ++ optional (config.modules ? nordvpn && config.modules.nordvpn.enable) [ "nordvpn" ];
ignoreShellProgramCheck = true;
shell = preferredShell pkgs;
};
}

38
hosts/odin/default.nix Executable file
View file

@ -0,0 +1,38 @@
{ inputs, pkgs, ... }:
{
imports = [
./hardware-configuration.nix
./modules.nix
];
boot.plymouth.enable = true; # for silent boot
system.autoUpgrade = {
enable = true;
flags = [ "--update-input" "nixpkgs" ];
dates = "weekly";
randomizedDelaySec = "15min";
};
nix.settings = {
experimental-features = [
"nix-command"
"flakes"
];
auto-optimise-store = true;
};
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 7d";
};
swapDevices = [
{
device = "/swap";
size = 4096;
}
];
}

42
hosts/odin/modules.nix Executable file
View file

@ -0,0 +1,42 @@
{ pkgs, inputs, ... }:
{
imports = [
# Utilities
../../modules/nixos/nvidia-support.nix
../../modules/nixos/bluetooth.nix
../../modules/nixos/audio.nix
];
services.displayManager = {
autoLogin.enable = true;
autoLogin.user = "anna";
};
modules.bluetooth.enable = true;
modules.nvidia.enable = true;
modules.audio.enable = true;
security.rtkit.enable = true;
services = {
gvfs.enable = true;
upower.enable = true;
power-profiles-daemon.enable = true;
printing = {
enable = true;
drivers = with pkgs; [ hplipWithPlugin ];
};
};
programs = {
dconf.enable = true;
light.enable = true;
thunar.enable = true;
thunar.plugins = with pkgs.xfce; [
thunar-archive-plugin
thunar-volman
];
};
}

76
hosts/thor/default.nix Executable file
View file

@ -0,0 +1,76 @@
{
config,
inputs,
prefs,
pkgs,
lib,
...
}:
{
imports = [
inputs.agenix.nixosModules.default {
age.identityPaths = [ "/mnt/id_ed25519" ];
}
./hardware-configuration.nix
./nginx.nix
./services
];
age.secrets.networking.file = ./secrets/networking.age;
services.openssh = {
enable = true;
settings = {
PasswordAuthentication = false;
};
};
users.users.root.openssh.authorizedKeys.keys = lib.mapAttrsToList (
host: value:
"${value} ${host}"
) prefs.keys;
networking = {
networkmanager.enable = lib.mkForce false;
wireless = {
enable = true;
secretsFile = config.age.secrets.networking.path;
networks = {
"2.4tfd".pskRaw = "ext:psk_24ghz";
"5tfd".pskRaw = "ext:psk_5ghz";
};
};
interfaces.eth0.ipv4.addresses = [{
address = "192.168.100.100";
prefixLength = 24;
}];
defaultGateway = "192.168.100.1";
nameservers = [ "192.168.1.1" "192.168.100.1" ];
};
nix.settings = {
experimental-features = [
"nix-command"
"flakes"
];
auto-optimise-store = true;
};
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 7d";
};
swapDevices = [
{
device = "/swap";
size = 4096;
}
];
}

View file

@ -0,0 +1,43 @@
# 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.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ "amdgpu" ];
boot.kernelModules = [ "kvm-intel" "wl" ];
boot.extraModulePackages = [ config.boot.kernelPackages.broadcom_sta ];
fileSystems."/mnt/shared" =
{ device = "/dev/disk/by-uuid/531f09bb-518f-4354-a058-ca0e24d80b00";
fsType = "ext4";
};
fileSystems."/" =
{ device = "/dev/disk/by-uuid/452d75c8-8cc7-4e2d-b1a5-ae006c57201c";
fsType = "ext4";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/03CE-C861";
fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ];
};
swapDevices = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp0s25.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

16
hosts/thor/nginx.nix Executable file
View file

@ -0,0 +1,16 @@
{ prefs, ... }:
{
services.nginx = {
enable = true;
virtualHosts.${prefs.config.thor.domain} = {
enableACME = false;
forceSSL = false;
listen = [{ addr = "0.0.0.0"; port = 80; }];
locations."~ ^/\\.well-known/(host-meta|webfinger)$".proxyPass = "http://127.0.0.1:4000";
locations."~ ^/.well-known/matrix".proxyPass = "https://matrix.${prefs.config.thor.domain}";
locations."/".proxyPass = "http://127.0.0.1:8080";
};
};
}

View file

@ -0,0 +1,6 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ cahyTca0TSIZ0F6QdMq9/hWBfsmdnlmJKa10D8VkBgA
GHKg0WinzFIeH46i0AhlhcxN1GgDprYHS0PM2rHcO+w
--- XnQwJsdbow03DOjxR9c5c4d2oc8zNN6lDP62zBlBkxs
½g,ý9šóãM¥÷Õ;[ã@œ/Á=_i¨c„^ñ—ñO;̵Ÿ³¡á6<04>ú'<27>ê<EFBFBD>©á€}™GRe\kA ¤âØßr¿Dƒ0"”Gª
Ê€!¤ S°yÁÝæ…èU®G

View file

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ fUyIdWIY3EbrNspYEq1ZjJPQTQX+uWW+Ag5zWDVqb34
5M4iRPS5OZFNOlNuduhLH6CilZr4u9Ioq3uDvRBbCUc
--- wJFVmEmbS4ZxJccNFhJo1th/pKjVGATj6m5ywBMyvM4
ƒõO*-G[qbÃñÔݳ}³·o±¡SHÑãžšQ-54Ls<

View file

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ kA24bvfu2Yg4PnT+RvE1e6dTXFCWyHWInrydfQTs/Sg
FlYSH15E7YjcI01vf9+78ZlAP7avJx40zw5mKo3WopU
--- fT6GJLjsecXbz0GUll0AwBaPtu4aWm8PI4HeYXC610s
ìD•Ÿ4UE"DïI·@ž+ú$(ê<1E>"üOïH™2ÿ1Ùbðc"}®-H‡_í<5F>yLYˆfã/è¶7;÷êxï/Õâd«ði$†

Binary file not shown.

View file

@ -0,0 +1,8 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ zaXTnTLk48UWRVQtp1jSPtibDdE9KeqibpqYq1EP0Vs
0CB0iF18+kZE7JnZW1TBraLlfZxqCgSPuBPI4umry3c
--- +lZlhGUVWLm9ubFG4MVRH8hg01VT0KkxrBaUU+Em1fQ
Òd¨[d!-þü¡äøÍºßDg¸Cmpç{äÕ„‡š±¢>N/ºÅ¼Ð@ÄçG<1D>åG‡è=ã1¼Râœi“Q•ø®’“J^Ð%Ö¼rÔó<C394>V\i (Ç[¯\ÅÔå|
L™þ)<29>ÓhKÕºLNY¢Qj '>ÐÊ€­XNÊðádD´àcØlÜåìN#¬¾ C]»‡´ž+†v@ è§<C3A8>âwàp=Kø>&¸ªIk¢´Py=åçtcŠ0ö#ý˜]´©¢áÙ|ì pæêô
kgÁyYZ¤Ôp`í×½'AľÞQZ™ÏÔša<73>í¦³MkŠ\·E ÛyY@¬Ô þäi¤o;ñ C8“xC'EÆ#)òÇ<C3B2>DÚò1J7М0НcFÙº$…}‰f<05>
䜮¡Ë

View file

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ NgeUldoMIHy+UorsEhBJyo89ZenIfAopvuoLRMFSBmM
Gau9fYWcNy9QOG2t57vSkD1eSNk0TrERTwsS0vxoGtc
--- GNb7pNSEEVbZf5GhIxWno06LdX7HxWpCVIlCH6m//2k
)X®”B •,J¿túRª®9„vù2¡7b´|X⇠ËvìßWŽê‡gTþ(¸z U'ÍÂCgynÃ'˜™/I@dªœwŽ-¦3´ͦŒ•]ÓC]ÿ§³øgz¶Æ÷Ø"üBŽýuÇ*!õiS¼¹ËÁ¢oµ *Rh R¨7>è SJí¤%éÿ

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ q5thSnNrOtI6eUoXPTrHDwLBAUsAs2d5nwq5nXK9gBQ
p2gCv9kgUwXiblhRm7ZnKwlgQys+/7kVjAkamvgW0Io
--- DuW5ItLLsyFX+e8QjmViEUlQK53hYOL2Nu1d7zlfQDM
í>‡Î™‚"ÑÃ¥rÓ¥;¯%raþPV­<10>¶{% ú×Àƒþêgßi´Qçë'©0ÙÏ»l® Éî7Gô_PûÿlÃTõhåm”{

BIN
hosts/thor/secrets/frigate.age Executable file

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ 1bPMvnAEXgOfuNDrWaRl8CE1QrgH4cFzOIoB8vqDy3Y
oD+7S9OOPzzoe4978iemjhjwHSrU/y39T39H5WzP+o8
--- tBr0ON6jfAcIE0x/mx2K5gYJfFuM3Rfjc8X4++BddUI
u1Ê&ËPÞ:úú]rio¸¦Bœˆ+ž ° Ž“…Rët?ŒÚÎWËQïø<>O˜ ah=v5×; ±ó³ûÎ<C3BB>Xjé< <0A>

Binary file not shown.

View file

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ 2iRp9wpbd4NgMqC4hpycO3VfIXaASIr+YQWoFKMYmFU
8+gLThbQW3OMF5un8laUiP/4uFNO5f78BSv6szgqHjQ
--- e0mSnXZzoIw5ogcRTQq4BI0RnCDqjVIt/LZI2JpbLTI
Ìõ“2I BŸa²Ê%0„ž ;X9<58>v.¦öOK-}m¯'È/ŠfÆÿàÒü¿„Ý<E2809E>ÉÛDžA èÂóëHëàRI¢;;

BIN
hosts/thor/secrets/matrix.age Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
hosts/thor/secrets/mediaStack.age Executable file

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ RIds+9LKi8GoiJ2KK/dBPcFTn8dTs07FlQavqBTmSl8
M0Cd5vhJvxNMiEjYgJc5Js5McF/hCyLpeSLALL9qzxc
--- eRNwrgVs/6jv4JIkRJW+Q5uqEsAkj7164Oyc/Dkas/s
U4Ó5<C393>† \VKýŽ&t—@ñ_Åû'÷m+{=”…º"Û$]Ä™bE_§ÃÆBF Þ׌à•Ô¢»ƒâz˜öLê+ò¨¸c^3

View file

@ -0,0 +1,6 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ iQmE8ukJaEW3sxVh4s1/CPLLukesCTVCmNqtYSzSxkY
THo6jt+/lOb3QjGRWA+eZLJnaS7jT/nOxW7oXsF5NHk
--- xGunPCM9lX4YCmveDAMegYMJEpbj5991HovU+dc2KMY
Áç79Ö¹ˆƒÔL8»ãß°Z4•£ëZi&? UAØ9z
R<EFBFBD>\A2¾46û²b,L¿Vq¨Öl}¾ën×Ô‰‰ÝTÁi<C381>L8¼ORô”¯™]lÌw Kl é·ä<C2B7>ä_&ŸMÿÜðË ôâ—Ûîµµþjã+²<>ŸªXB¯Cæ<43><C3A6>C@ç}A «ŽZ]( ºâQ½ô

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,5 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ bGRVQTsOcaFkVZtHUlS0jq3OyureVZeP6mTsQOp0bSs
YUvOXm94rvZnFTao6l5K7a4a0txbG0E+Eleqs43hk0o
--- mfiGtKpUxM6TD9qZDhqKT4IIUk9AQFtKZUeGShRjbak
§ŹmáăŚěxC<EFBFBD>F?j 1Ś-@µťéě^}ĎşW“hG5łlť%Z6α»šůwłÁ˝m+üHxB¦ęf7U9$Ą Ú4_˝IęÄ [`0°Kű<4B>yŐq°'´1ŻtSŕ:¸‘ď'fô

View file

@ -0,0 +1,6 @@
age-encryption.org/v1
-> ssh-ed25519 4SrVlQ OFrtqnG724Xn8scAwEdmWjzZmCD4XPqAl1bRvFklgAQ
QLXQeVaArzEinGmNUQIuUXj6TWxE6MKsw2H6BXBemzo
--- 4tyPo2eEv69FJBEFE8AQ5p/r6TCtluFYUEnak+XU2XI
¹äÃ൩°4ž±¼ß´»íÍ·Ò0|f#?š ±uœš^Ѳ–R„&,þ˜û;NLa= T}÷Häš,uFŽ-F_HE-ÔQ{hj¡Ç÷´j“1Áp»îZM¬Nñ] åëÒ"co,v)ÿ™VêüžjÄ#q@_Âñó~#ID¥<44>"2 \¥j·—ô*hµ µÕ‚Œ"ØË咽ҿüÀÓf'ØzÀå‡<12>¸º3`Qç ÙÈjBøB³±#ä«>:þüwg|x~ u™ ô®îÝmà-ü*dÈC<©*Ïþ,^~Ž-Úÿ[ ¼ .â3ÿ¼¿ ™rY»A£³ÍµríÔ¡Ý$O¨î*/ÁÊéÑBWLÇ3S¶Ù0cï2)ª®
q„\¼<>çM5Ál/‡{Ð~1-}q5Å<35>÷•¼¡E43± V ©fzqÞw~»âGk

Binary file not shown.

73
hosts/thor/services/default.nix Executable file
View file

@ -0,0 +1,73 @@
{
config,
prefs,
pkgs,
...
}:
{
age.secrets.newtToken = {
file = ../secrets/newtToken.age;
owner = "newt";
};
imports = [
./fediverse
./frigate
./forgejo
./home_assistant
./immich
./jellyfin
./matrix
./matrix/bridges
./nextcloud
./piped
./vaultwarden
./wireguard
./healthcheck.nix
../../../modules/nixos/samba.nix
../../../modules/nixos/apps/newt.nix
];
services.postgresql = {
enable = true;
package = pkgs.postgresql_16;
authentication = ''
local all all trust
host all all 127.0.0.1/32 trust
host all all 0.0.0.0/0 reject
host all all ::/0 reject
'';
extensions = ps: with ps; [
pgvector # TODO: migrate to VectorChord
];
};
services.ntfy-sh = {
enable = true;
settings = {
base-url = "https://ntfy.${prefs.config.thor.domain}";
listen-http = "localhost:8118";
auth-default-access = "deny-all";
enable-login = true;
};
};
networking.firewall.allowedTCPPorts = [ 53 853 ];
services.adguardhome.enable = true;
modules.newt = {
enable = true;
id = prefs.config.thor.newtId;
secretFile = config.age.secrets.newtToken.path;
endpoint = "https://proxy.${prefs.config.thor.domain}";
};
modules.samba = {
enable = true;
shares = mkShares: mkShares {
"Shared" = "/mnt/shared";
};
};
}

View file

@ -0,0 +1,93 @@
{ config, prefs, pkgs, lib, ... }:
{
services.akkoma = {
enable = true;
group = "shared-secret";
extraPackages = builtins.attrValues {
inherit (pkgs) ffmpeg exiftool imagemagick;
};
nginx = {
locations."/" = {
proxyWebsockets = true;
recommendedProxySettings = true;
proxyPass = "http://unix:/run/akkoma/socket";
extraConfig = ''
proxy_hide_header Content-Security-Policy;
add_header Content-Security-Policy "upgrade-insecure-requests;script-src 'self';connect-src 'self' blob: https://social.sador.me wss://social.sador.me;media-src 'self' https:;img-src 'self' data: blob: https:;default-src 'none';base-uri 'self';frame-ancestors 'none';style-src 'self' 'unsafe-inline';font-src 'self';manifest-src 'self';" always;
'';
};
locations."/proxy" = {
proxyPass = "http://unix:/run/akkoma/socket";
extraConfig = ''
proxy_buffering on;
proxy_ignore_client_abort on;
'';
};
};
frontends = {
primary = {
package = pkgs.callPackage ./soapbox.nix { inherit pkgs; };
name = "soapbox";
ref = "stable";
};
admin = {
package = pkgs.akkoma-admin-fe;
name = "admin-fe";
ref = "stable";
};
};
config = let
inherit ((pkgs.formats.elixirConf { }).lib) mkRaw;
in {
":web_push_encryption".":vapid_details" = {
public_key._secret = config.age.secrets.akkomaPushPublicKey.path;
private_key._secret = config.age.secrets.akkomaPushPrivateKey.path;
};
":pleroma" = {
":instance" = {
name = "${prefs.config.thor.domain} Akkoma";
description = "Private Akkoma instance.";
email = "contact@${prefs.config.thor.domain}";
registrations_open = false;
invites_enabled = true;
federating = true;
};
"Pleroma.Web.Endpoint" = {
url.host = "social." + prefs.config.thor.domain;
secret_key_base._secret = config.age.secrets.akkomaEndpointKey.path;
signing_salt._secret = config.age.secrets.akkomaEndpointSalt.path;
};
"Pleroma.Captcha".enabled = false;
"Pleroma.Upload" = {
enabled = true;
base_url = "https://social.${prefs.config.thor.domain}/proxy";
};
":mrf".policies = map mkRaw [ "Pleroma.Web.ActivityPub.MRF.SimplePolicy" ];
":configurable_from_database" = false;
"Pleroma.Emails.Mailer" = with prefs.config.thor.emailConfig; {
enabled = true;
adapter = "Swoosh.Adapters.SMTP";
username = login;
relay = server;
password._secret = config.age.secrets.smtpPassword.path;
tls = ":always";
auth = ":always";
port = port;
};
};
};
};
}

View file

@ -0,0 +1,51 @@
{ config, prefs, pkgs, lib, ... }:
{
imports = [
./lemmy.nix
./peertube.nix
./pixelfed.nix
./akkoma.nix
];
users.groups.shared-secret = {};
age.secrets = {
smtpPassword = {
file = ../../secrets/smtpPassword.age;
group = "shared-secret";
mode = "640";
};
akkomaEndpointKey = {
file = ../../secrets/fediverse/akkoma/endpointKey.age;
owner = "akkoma";
};
akkomaEndpointSalt = {
file = ../../secrets/fediverse/akkoma/endpointSalt.age;
owner = "akkoma";
};
akkomaPushPublicKey = {
file = ../../secrets/fediverse/akkoma/pushPublicKey.age;
owner = "akkoma";
};
akkomaPushPrivateKey = {
file = ../../secrets/fediverse/akkoma/pushPrivateKey.age;
owner = "akkoma";
};
peertube = {
file = ../../secrets/fediverse/peertube.age;
owner = "peertube";
};
pixelfed = {
file = ../../secrets/fediverse/pixelfed.age;
owner = "pixelfed";
};
};
}

View file

@ -0,0 +1,26 @@
{ config, prefs, lib, ... }:
{
systemd.services.lemmy.serviceConfig.Group = "shared-secret";
services.pict-rs.enable = true;
services.lemmy = {
enable = true;
smtpPasswordFile = config.age.secrets.smtpPassword.path;
database.createLocally = true;
nginx.enable = true;
ui.port = 3000;
settings = {
hostname = "lemmy." + prefs.config.thor.domain;
email = with prefs.config.thor.emailConfig; {
smtp_server = "${server}:${toString port}";
smtp_login = login;
smtp_from_address = from;
tls_type = tls;
};
};
};
}

View file

@ -0,0 +1,57 @@
{ prefs, ... }:
{
services.nginx.virtualHosts."lemmy.${prefs.config.thor.domain}" = {
enableACME = false;
forceSSL = false;
extraConfig = ''
gzip on;
gzip_types text/css application/javascript image/svg+xml;
gzip_vary on;
client_max_body_size 20M;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
'';
locations = {
"/" = {
extraConfig = ''
set $proxpass http://127.0.0.1:3000;
if ($http_accept = "application/activity+json") {
set $proxpass http://127.0.0.1:8536;
}
if ($http_accept = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
set $proxpass http://127.0.0.1:8536;
}
if ($request_method = POST) {
set $proxpass http://127.0.0.1:8536;
}
proxy_pass $proxpass;
rewrite ^(.+)/+$ $1 permanent;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
'';
};
"~ ^/(api|pictrs|feeds|nodeinfo|version|.well-known)" = {
extraConfig = ''
proxy_pass http://127.0.0.1:8536;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
'';
};
};
};
}

View file

@ -0,0 +1,27 @@
{ config, prefs, lib, ... }:
{
services.peertube = {
enable = true;
group = "shared-secret";
redis.createLocally = true;
database.createLocally = true;
listenWeb = 443;
localDomain = "tube." + prefs.config.thor.domain;
secrets.secretsFile = config.age.secrets.peertube.path;
smtp.passwordFile = config.age.secrets.smtpPassword.path;
settings = {
smtp = with prefs.config.thor.emailConfig; {
inherit port;
hostname = server;
username = login;
from_address = from;
tle = true;
};
};
};
}

View file

@ -0,0 +1,57 @@
{ config, prefs, pkgs, lib, ... }:
{
services.pixelfed = {
enable = true;
database.type = "pgsql";
domain = "pix." + prefs.config.thor.domain;
secretFile = config.age.secrets.pixelfed.path;
nginx.listen = [
{
addr = "0.0.0.0";
port = 80;
}
];
settings = let
cfg = config.services.pixelfed;
in lib.mkMerge [
{
APP_ENV = "production";
APP_DEBUG = false;
APP_URL = "https://${cfg.domain}";
ADMIN_DOMAIN = cfg.domain;
APP_DOMAIN = cfg.domain;
SESSION_DOMAIN = cfg.domain;
SESSION_SECURE_COOKIE = true;
OPEN_REGISTRATION = false;
}
{
ACTIVITY_PUB = true;
AP_REMOTE_FOLLOW = true;
AP_INBOX = true;
AP_OUTBOX = true;
AP_SHAREDINBOX = true;
WEBFINGER = true;
IMAGE_DRIVER = "imagick";
PF_OPTIMIZE_IMAGES = true;
}
{
DB_PORT = lib.mkForce 5432;
}
(lib.mkIf (cfg.redis.createLocally) {
BROADCAST_DRIVER = "redis";
CACHE_DRIVER = "redis";
QUEUE_DRIVER = "redis";
SESSION_DRIVER = "redis";
WEBSOCKET_REPLICATION_MODE = "redis";
REDIS_SCHEME = "unix";
REDIS_HOST = config.services.redis.servers.pixelfed.unixSocket;
REDIS_PATH = config.services.redis.servers.pixelfed.unixSocket;
})
];
};
}

View file

@ -0,0 +1,20 @@
{ pkgs }: pkgs.stdenv.mkDerivation rec {
pname = "soapbox";
version = "v3.2.0";
dontBuild = true;
dontConfigure = true;
src = pkgs.fetchurl {
name = "soapbox";
url = "https://gitlab.com/soapbox-pub/soapbox/-/jobs/artifacts/${version}/download?job=build-production";
sha256 = "sha256-AdW6JK7JkIKLZ8X+N9STeOHqmGNUdhcXyC9jsQPTa9o=";
};
nativeBuildInputs = [ pkgs.unzip ];
unpackPhase = ''
unzip $src -d .
'';
installPhase = ''
mv ./static $out
'';
}

View file

@ -0,0 +1,99 @@
{
config,
prefs,
pkgs,
lib,
...
}:
let
theme = pkgs.fetchzip {
url = "https://github.com/catppuccin/gitea/releases/download/v1.0.2/catppuccin-gitea.tar.gz";
sha256 = "sha256-rZHLORwLUfIFcB6K9yhrzr+UwdPNQVSadsw6rg8Q7gs=";
stripRoot = false;
};
in {
age.secrets.forgejo = {
file = ../../secrets/forgejo.age;
owner = "forgejo";
};
services.forgejo = {
enable = true;
group = "shared-secret";
database.type = "postgres";
database.socket = "/run/postgresql";
secrets.mailer.PASSWD = config.age.secrets.smtpPassword.path;
settings = {
default.APP_NAME = "sador.me Forgejo";
"cron.update_checker".ENABLED = false;
actions.ENABLED = true;
service = {
DISABLE_REGISTRATION = true;
REQUIRE_SIGNIN_VIEW = false;
REGISTER_EMAIL_CONFIRM = true;
ENABLE_NOTIFY_MAIL = true;
ALLOW_ONLY_EXTERNAL_REGISTRATION = false;
DEFAULT_KEEP_EMAIL_PRIVATE = false;
DEFAULT_ALLOW_CREATE_ORGANIZATION = true;
DEFAULT_ENABLE_TIMETRACKING = true;
};
security = {
INSTALL_LOCK = true;
REVERSE_PROXY_LIMIT = 1;
REVERSE_PROXY_TRUSTED_PROXIES = "127.0.0.1";
PASSWORD_HASH_ALGO = "pbkdf2";
};
server = {
DOMAIN = "git." + prefs.config.thor.domain;
ROOT_URL = "https://git." + prefs.config.thor.domain;
HTTP_PORT = 3428;
DISABLE_SSH = true;
};
mailer = with prefs.config.thor.emailConfig; {
ENABLED = true;
SMTP_ADDR = server;
SMTP_PORT = port;
PROTOCOL = "smtp+${tls}";
FROM = from;
USER = login;
};
ui = {
DEFAULT_THEME = "gitea-auto";
THEMES = import ./theming.nix;
};
};
};
# setup Catppuccin theme
systemd.services.forgejo.preStart = ''
mkdir -p ${config.services.forgejo.customDir}/public/assets/css
cp -rf ${theme}/* ${config.services.forgejo.customDir}/public/assets/css
'';
systemd.services.gitea-runner-primary.serviceConfig.User = lib.mkForce "forgejo";
services.gitea-actions-runner = {
package = pkgs.forgejo-runner;
instances.primary = {
enable = true;
name = config.networking.hostName;
url = "https://git.${prefs.config.thor.domain}";
tokenFile = config.age.secrets.forgejo.path;
labels = [
"ubuntu-latest:docker://node:16-bullseye"
"ubuntu-22.04:docker://node:16-bullseye"
"native:host"
];
};
};
# Docker is needed for Actions
virtualisation.docker.enable = true;
}

View file

@ -0,0 +1,18 @@
let
variants = [ "frappe" "latte" "macchiato" "mocha" ];
accents = [
"blue" "flamingo" "green" "lavender" "maroon" "mauve" "peach" "pink"
"red" "rosewater" "sapphire" "sky" "teal" "yellow"
];
catppuccinThemes =
builtins.concatLists (map (variant:
map (accent: "catppuccin-${variant}-${accent}") accents
) variants);
baseThemes = [
"gitea-auto" "gitea-light" "gitea-dark"
];
allThemes = baseThemes ++ catppuccinThemes;
in builtins.concatStringsSep "," allThemes

View file

@ -0,0 +1,122 @@
{
streams = {
gate_lq = "rtsp://\${FRIGATE_CAM1_USERNAME}:\${FRIGATE_CAM1_PASSWORD}@\${FRIGATE_CAM1_HOST}:554/cam/realmonitor?channel=1&subtype=1";
gate_hq = "rtsp://\${FRIGATE_CAM1_USERNAME}:\${FRIGATE_CAM1_PASSWORD}@\${FRIGATE_CAM1_HOST}:554/cam/realmonitor?channel=1&subtype=0";
};
frigate = {
mqtt.enabled = false;
auth = {
# 6 months
session_length = 15552000;
refresh_time = 15552000;
};
ffmpeg = {
input_args = [
"-avoid_negative_ts"
"make_zero"
"-flags"
"low_delay"
"-rtsp_transport"
"tcp"
];
hwaccel_args = "preset-vaapi";
output_args.record = "preset-record-generic-audio-copy";
};
detectors.ov_1.type = "openvino";
detectors.ov_2.type = "openvino";
model = {
model_type = "yolonas";
width = 320;
height = 320;
input_tensor = "nchw";
input_pixel_format = "bgr";
path = "/var/lib/frigate/models/yolo_nas_s.onnx";
};
record = {
enabled = true;
retain = {
days = 3;
mode = "motion";
};
alerts = {
retain = {
days = 7;
mode = "motion";
};
};
detections = {
retain = {
days = 3;
mode = "motion";
};
};
};
snapshots = {
enabled = true;
retain = {
default = 7;
};
};
objects.track = [ "person" "car" ];
audio = {
enabled = true;
listen = [ "fire_alarm" "scream" "speech" "yell" "sing" "hands" ];
};
cameras = {
gate = {
enabled = true;
ffmpeg.inputs = [
{
path = "rtsp://127.0.0.1:8554/gate_hq";
roles = [ "record" "detect" "audio" ];
}
];
detect.fps = 5;
#live.streams = {
# gate_hq = "gate_hq";
# gate_lq = "gate_lq";
#};
review.alerts.required_zones = [ "ogrod" "zakret" "podworko" ];
} // (import ./masks.nix);
};
version = "0.16-0";
notifications = {
enabled = false;
};
semantic_search = {
enabled = true;
reindex = false;
model_size = "small";
};
detect = {
enabled = true;
};
#face_recognition = {
# enabled = true;
# model_size = "small";
#};
#lpr = {
# enabled = true;
#};
};
}

View file

@ -0,0 +1,55 @@
{
config,
prefs,
pkgs,
...
}:
let
settings = import ./config.nix;
in {
age.secrets.frigate = {
file = ../../secrets/frigate.age;
owner = "go2rtc";
};
# hardware acceleration
services.xserver = {
enable = true;
videoDrivers = ["amdgpu"];
};
hardware.graphics = {
enable = true;
extraPackages = with pkgs; [
vaapiVdpau
libvdpau-va-gl
];
};
services.go2rtc = {
enable = true;
settings.streams = settings.streams;
};
services.frigate = {
enable = true;
vaapiDriver = "radeonsi";
settings = settings.frigate;
hostname = "cam.${prefs.config.thor.domain}";
};
systemd.services.go2rtc.serviceConfig.EnvironmentFile = config.age.secrets.frigate.path;
systemd.services.frigate = {
environment = {
VDPAU_DRIVER = "radeonsi";
LIBVA_DRIVER_NAME = "radeonsi";
HSA_OVERRIDE_GFX_VERSION = "9.0.0";
};
serviceConfig = {
SupplementaryGroups = ["render" "video"] ; # for access to /dev/dri
AmbientCapabilities = "CAP_PERFMON";
};
};
}

View file

@ -0,0 +1,32 @@
{
motion.mask = "0,0.613,0.14,0.607,0.206,0.638,0.232,0.625,0.248,0.66,0.45,0.636,0.458,0.645,0.478,0.642,0.506,0.632,0.517,0.607,0.527,0.565,0.548,0.537,0.562,0.506,0.578,0.473,0.587,0.429,0.605,0.392,0.625,0.374,0.642,0.375,0.647,0.41,0.651,0.449,0.651,0.482,0.652,0.524,0.648,0.559,0.653,0.603,0.665,0.626,0.665,0.685,0.669,0.713,0.664,0.747,0.649,0.764,0.668,0.786,0.694,0.826,0.722,0.848,0.772,0.908,0.793,0.94,0.852,1,0,1";
zones = {
ogrod = {
coordinates = "0,0.204,0.096,0.193,0.09,0.256,0.09,0.305,0.09,0.367,0.088,0.42,0.088,0.444,0.087,0.47,0.081,0.519,0.083,0.606,0,0.611";
loitering_time = 0;
inertia = 3;
};
zakret = {
coordinates = "0.129,0.188,0.147,0.204,0.18,0.21,0.21,0.213,0.23,0.214,0.245,0.215,0.247,0.185,0.253,0.174,0.266,0.174,0.276,0.184,0.288,0.205,0.358,0.218,0.414,0.236,0.451,0.246,0.478,0.256,0.502,0.266,0.541,0.285,0.572,0.3,0.615,0.316,0.647,0.332,0.679,0.346,0.751,0.384,0.763,0.384,0.696,0.323,0.686,0.311,0.666,0.293,0.69,0.339,0.637,0.311,0.579,0.281,0.447,0.232,0.373,0.205,0.292,0.192,0.256,0.134,0.163,0.115,0.159,0.132,0.124,0.131,0.13,0.161";
loitering_time = 0;
};
podworko = {
coordinates = "0.127,0.192,0.129,0.21,0.154,0.383,0.173,0.409,0.183,0.486,0.205,0.477,0.242,0.486,0.26,0.51,0.368,0.498,0.473,0.507,0.249,0.182,0.25,0.217,0.144,0.202";
loitering_time = 0;
};
pole_1 = {
coordinates = "0.264,0.056,0.257,0.131,0.292,0.189,0.378,0.204,0.471,0.239,0.38,0.15,0.316,0.088,0.298,0.08";
loitering_time = 0;
};
pole_2 = {
coordinates = "0.297,0.21,0.347,0.276,0.399,0.342,0.5,0.467,0.504,0.433,0.512,0.427,0.524,0.438,0.538,0.45,0.53,0.505,0.558,0.512,0.572,0.485,0.578,0.462,0.585,0.429,0.603,0.392,0.625,0.374,0.644,0.374,0.651,0.424,0.653,0.506,0.65,0.564,0.656,0.606,0.667,0.625,0.706,0.681,0.722,0.709,0.759,0.735,0.786,0.772,0.811,0.809,0.844,0.835,0.873,0.795,0.868,0.725,0.881,0.681,0.897,0.649,0.911,0.62,0.925,0.577,0.927,0.525,0.888,0.489,0.808,0.427,0.783,0.412,0.76,0.389,0.58,0.304,0.468,0.256,0.367,0.223";
loitering_time = 0;
};
skrot = {
coordinates = "0.003,0.162,0.049,0.157,0.095,0.148,0.105,0.118,0.114,0.11,0.114,0.096,0.116,0.058,0.119,0.044,0.017,0.06,0.022,0.035,0.002,0.04";
loitering_time = 0;
};
};
objects.filters.car.mask = "0.808,0.19,0.751,0.384,0.927,0.525,0.936,0.281";
}

View file

@ -0,0 +1,94 @@
{
config,
prefs,
pkgs,
...
}:
let
theme = pkgs.fetchzip {
url = "https://github.com/catppuccin/gitea/releases/download/v1.0.2/catppuccin-gitea.tar.gz";
sha256 = "sha256-rZHLORwLUfIFcB6K9yhrzr+UwdPNQVSadsw6rg8Q7gs=";
stripRoot = false;
};
in {
age.secrets.gitea = {
file = ../../secrets/gitea/gitea.age;
owner = "gitea";
};
age.secrets.giteaRunnerToken = {
file = ../../secrets/gitea/runnerToken.age;
owner = "gitea";
};
services.gitea = {
enable = true;
group = "shared-secret";
appName = "sador.me Gitea";
database.type = "postgres";
database.socket = "/run/postgresql";
mailerPasswordFile = config.age.secrets.smtpPassword.path;
settings = {
"cron.update_checker".ENABLED = false;
service = {
DISABLE_REGISTRATION = true;
REQUIRE_SIGNIN_VIEW = false;
REGISTER_EMAIL_CONFIRM = true;
ENABLE_NOTIFY_MAIL = true;
ALLOW_ONLY_EXTERNAL_REGISTRATION = false;
DEFAULT_KEEP_EMAIL_PRIVATE = false;
DEFAULT_ALLOW_CREATE_ORGANIZATION = true;
DEFAULT_ENABLE_TIMETRACKING = true;
};
security = {
INSTALL_LOCK = true;
REVERSE_PROXY_LIMIT = 1;
REVERSE_PROXY_TRUSTED_PROXIES = "127.0.0.1";
PASSWORD_HASH_ALGO = "pbkdf2";
};
server = {
DOMAIN = "git." + prefs.config.thor.domain;
DISABLE_SSH = true;
};
mailer = with prefs.config.thor.emailConfig; {
ENABLED = true;
SMTP_ADDR = server;
SMTP_PORT = port;
PROTOCOL = "smtp+${tls}";
FROM = from;
USER = login;
};
ui = {
DEFAULT_THEME = "auto";
THEMES = import ./theming.nix;
};
};
};
# setup Catppuccin theme
systemd.services.gitea.preStart = ''
mkdir -p ${config.services.gitea.customDir}/public/assets
cp -rf ${theme}/* ${config.services.gitea.customDir}/public/assets/css
'';
services.gitea-actions-runner.instances.default = {
enable = true;
name = "primary-1";
url = "https://git.${prefs.config.thor.domain}";
tokenFile = config.age.secrets.giteaRunnerToken.path;
labels = [
"ubuntu-latest:docker://node:16-bullseye"
"ubuntu-22.04:docker://node:16-bullseye"
"native:host"
];
};
# Docker is needed for Gitea Actions
virtualisation.docker.enable = true;
}

View file

@ -0,0 +1,19 @@
let
variants = [ "frappe" "latte" "macchiato" "mocha" ];
accents = [
"blue" "flamingo" "green" "lavender" "maroon" "mauve" "peach" "pink"
"red" "rosewater" "sapphire" "sky" "teal" "yellow"
];
catppuccinThemes =
builtins.concatLists (map (variant:
map (accent: "catppuccin-${variant}-${accent}") accents
) variants);
baseThemes = [
"gitea-auto" "gitea-light" "gitea-dark"
"auto" "light" "dark"
];
allThemes = baseThemes ++ catppuccinThemes;
in builtins.concatStringsSep " " allThemes

View file

@ -0,0 +1,51 @@
{
config,
pkgs,
lib,
...
}:
let
mkHealthCheck = service: var: {
systemd.services."${service}-healthcheck" = {
description = "Healthcheck for ${service}";
after = [ "network-online.target" "${service}.service" ];
wants = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
EnvironmentFile = config.age.secrets.healthcheck.path;
ExecStart = pkgs.writeShellScript "${service}-healthcheck" ''
set -euo pipefail
if systemctl is-active --quiet ${service}.service && \
systemctl show -p Result ${service}.service \
| grep -q 'Result=success'; then
${pkgs.curl}/bin/curl -fsS "${"$"}${var}"
else
exit 0
fi
'';
};
};
systemd.timers."${service}-healthcheck" = {
description = "Timer for ${service} healthcheck";
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "5m";
OnUnitActiveSec = "5m";
AccuracySec = "1m";
};
};
};
in lib.mkMerge [
{
age.secrets.healthcheck.file = ../secrets/healthcheck.age;
}
(mkHealthCheck "mautrix-meta-messenger" "META_HEALTHCHECK_URL")
(mkHealthCheck "mautrix-signal" "SIGNAL_HEALTHCHECK_URL")
(mkHealthCheck "mautrix-whatsapp" "WHATSAPP_HEALTHCHECK_URL")
(mkHealthCheck "flaresolverr" "FLARESOLVERR_HEALTHCHECK_URL")
]

View file

@ -0,0 +1,69 @@
{ config, pkgs, ... }:
{
age.secrets.home-assistant = {
file = ../../secrets/homeAssistant.age;
path = "${config.services.home-assistant.configDir}/secrets.yaml";
owner = "hass";
group = "hass";
};
services.home-assistant = {
enable = true;
customComponents = with pkgs.home-assistant-custom-components; [
ntfy
samsungtv-smart
];
customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
mushroom
mini-graph-card
mini-media-player
];
extraComponents = [ "default_config" "samsungtv" "webdav" "lg_netcast" ];
extraPackages = ps: with ps; [ psycopg2 ];
config = {
recorder.db_url = "postgresql://@/hass";
homeassistant = {
name = "Home";
latitude = "!secret latitude";
longitude = "!secret longitude";
country = "PL";
temperature_unit = "C";
unit_system = "metric";
time_zone = config.time.timeZone;
};
frontend = {
themes = "!include_dir_merge_named themes";
extra_module_url = [
"/hacsfiles/material-you-utilities/material-you-utilities.min.js"
"/hacsfiles/keep-texts-in-tabs/keep-texts-in-tabs.js"
"/hacsfiles/kiosk-mode/kiosk-mode.js"
];
};
http = {
trusted_proxies = ["0.0.0.0" "127.0.0.1" "::1"];
login_attempts_threshold = 5;
use_x_forwarded_for = true;
};
panel_custom = [
{
name = "material-you-panel";
url_path = "material-you-configuration";
sidebar_title = "Material You Utilities";
sidebar_icon = "mdi:material-design";
module_url = "/hacsfiles/material-you-utilities/material-you-utilities.min.js";
}
];
# this loads some integrations
default_config = {};
bluetooth = {};
};
};
}

View file

@ -0,0 +1,97 @@
{
"backup": {
"database": {
"cronExpression": "0 02 * * *",
"enabled": true,
"keepLastAmount": 1
}
},
"ffmpeg": {
"accel": "vaapi",
"acceptedAudioCodecs": ["aac", "mp3", "libopus", "pcm_s16le"],
"acceptedContainers": ["mov", "ogg", "webm"],
"acceptedVideoCodecs": ["h264", "hevc"],
"crf": 23,
"preset": "ultrafast",
"targetAudioCodec": "aac",
"targetResolution": "720",
"targetVideoCodec": "h264",
"tonemap": "hable",
"transcode": "required"
},
"job": {
"backgroundTask": { "concurrency": 5 },
"faceDetection": { "concurrency": 2 },
"library": { "concurrency": 5 },
"metadataExtraction": { "concurrency": 5 },
"migration": { "concurrency": 5 },
"notifications": { "concurrency": 5 },
"search": { "concurrency": 5 },
"sidecar": { "concurrency": 5 },
"smartSearch": { "concurrency": 2 },
"thumbnailGeneration": { "concurrency": 3 },
"videoConversion": { "concurrency": 1 }
},
"library": {
"scan": {
"cronExpression": "0 0 * * *",
"enabled": true
}
},
"machineLearning": {
"clip": {
"enabled": true,
"modelName": "ViT-B-32__openai"
},
"duplicateDetection": {
"enabled": true,
"maxDistance": 0.01
},
"enabled": true,
"facialRecognition": {
"enabled": true,
"maxDistance": 0.5,
"minFaces": 3,
"minScore": 0.7,
"modelName": "buffalo_l"
}
},
"map": {
"enabled": true,
"darkStyle": "https://tiles.immich.cloud/v1/style/dark.json",
"lightStyle": "https://tiles.immich.cloud/v1/style/light.json"
},
"notifications": {
"smtp": {
"enabled": true
}
},
"passwordLogin": {
"enabled": true
},
"reverseGeocoding": {
"enabled": true
},
"server": {
"publicUsers": true
},
"storageTemplate": {
"enabled": true,
"hashVerificationEnabled": true,
"template": "{{y}}/{{MM}}/{{filename}}"
},
"templates": {
"email": {
"albumInviteTemplate": "<h1>Witaj, <b>{recipientName}</b>!</h1>\n<p><b>{senderName}</b> dodał Cię do członków albumu <b>{albumName}</b>!</p>\n<p>Aby zobaczyć album i treści w nim, kliknij w <a href=\"{baseUrl}/albums/{albumId}\">ten link</a>.</p>",
"albumUpdateTemplate": "<h1>Witaj, <b>{recipientName}</b>!</h1>\n<p>Do albumu <b>{albumName}</b> zostały dodane nowe treści.</p>\n<p>Aby je zobaczyć, kliknij w <a href=\"{baseUrl}/albums/{albumId}\">ten link</a>.</p>",
"welcomeTemplate": "<h1>Witaj, <b>{displayName}</b>!</h1>\n<p>Oto dane Twojego konta na platfomie Immich serwera <b>{baseUrl}</b>:</p>\n<p><b>Nazwa użytkownika</b>: {username}</p>\n<p><b>Hasło</b>: {password}</p>\n<p>Dziękujemy za rejestrację na naszym serwerze!</p>"
}
},
"trash": {
"days": 30,
"enabled": true
},
"user": {
"deleteDelay": 7
}
}

View file

@ -0,0 +1,30 @@
{
config,
prefs,
lib,
...
}:
let
baseImmichConfig = builtins.fromJSON (builtins.readFile ./config.json);
in {
services.immich = {
enable = true;
host = "0.0.0.0";
#acelerationDevices = [
# "/dev/dri/card1"
# "/dev/dri/renderD128"
#];
settings = lib.recursiveUpdate baseImmichConfig {
notifications.smtp = with prefs.config.thor.emailConfig; {
inherit from;
transport = {
inherit port;
host = server;
username = login;
ignoreCert = false;
};
};
};
};
}

View file

@ -0,0 +1,61 @@
{ config, self, ... }:
{
imports = [
../../../../modules/nixos/apps/qbittorrent.nix
./nginx.nix
];
users.groups.media-stack = {};
age.secrets.mediaStack = {
file = ../../secrets/mediaStack.age;
group = "media-stack";
};
modules.qbittorrent = {
enable = true;
port = 3427;
group = "media-stack";
};
services.flaresolverr.enable = true;
services.jellyfin = {
enable = true;
group = "media-stack";
};
services.lidarr = {
enable = true;
group = "media-stack";
settings.server.urlbase = "/lidarr/";
environmentFiles = [ config.age.secrets.mediaStack.path ];
};
services.prowlarr = {
enable = true;
#group = "media-stack";
settings.server.urlbase = "/prowlarr/";
environmentFiles = [ config.age.secrets.mediaStack.path ];
};
services.radarr = {
enable = true;
group = "media-stack";
settings.server.urlbase = "/radarr/";
environmentFiles = [ config.age.secrets.mediaStack.path ];
};
services.readarr = {
enable = true;
group = "media-stack";
settings.server.urlbase = "/readarr/";
environmentFiles = [ config.age.secrets.mediaStack.path ];
};
services.sonarr = {
enable = true;
group = "media-stack";
settings.server.urlbase = "/sonarr/";
environmentFiles = [ config.age.secrets.mediaStack.path ];
};
}

View file

@ -0,0 +1,21 @@
{ prefs, ... }:
{
services.nginx.virtualHosts."jellyfin.${prefs.config.thor.domain}" = {
listen = [ { addr = "0.0.0.0"; port = 80; } ];
locations = {
"/".proxyPass = "http://127.0.0.1:8096";
"/radarr".proxyPass = "http://127.0.0.1:7878";
"/readarr".proxyPass = "http://127.0.0.1:8787";
"/sonarr".proxyPass = "http://127.0.0.1:8989";
"/prowlarr".proxyPass = "http://127.0.0.1:9696";
"/lidarr".proxyPass = "http://127.0.0.1:8686";
"/tv" = {
proxyPass = "http://127.0.0.1:34400";
extraConfig = ''
rewrite ^/tv(.*)$ /$1 break;
'';
};
};
};
}

View file

@ -0,0 +1,60 @@
{ prefs }: let
encryption = {
allow = true;
default = true;
require = true;
delete_keys = {
ratchet_on_decrypt = true;
dont_store_outbound = true;
delete_on_device_delete = true;
delete_outdated_inbound = true;
delete_prev_on_new_session = true;
periodically_delete_expired = true;
delete_fully_used_on_decrypt = true;
};
verification_levels = {
receive = "cross-signed-tofu";
send = "cross-signed-tofu";
share = "cross-signed-tofu";
};
};
in rec {
inherit encryption;
homeserver = {
domain = prefs.config.thor.domain;
address = "http://localhost:8008";
};
matrix = {
message_status_events = true;
message_error_notices = true;
sync_direct_chat_list = true;
delivery_receipts = true;
federate_rooms = true;
};
bridge = {
inherit encryption; # for older bridges
login_shared_secret_map.${homeserver.domain} = "as_token:$DOUBLEPUPPET_AS_TOKEN"; # for older bridges too
permissions = {
"*" = "relay";
${homeserver.domain} = "user";
"@boss:${homeserver.domain}" = "admin";
};
};
backfill = {
enabled = true;
max_initial_messages = 50;
max_catchup_messages = 500;
unread_hours_threshold = 720;
};
double_puppet = {
secrets.${homeserver.domain} = "as_token:$DOUBLEPUPPET_AS_TOKEN";
allow_discovery = false;
};
}

View file

@ -0,0 +1,73 @@
{
prefs,
config,
lib,
...
}:
let
commons = import ./common.nix { inherit prefs; };
in {
users.groups.mautrix = {
members = [ "mautrix-meta-messenger" "mautrix-whatsapp" "mautrix-signal" ];
};
age.secrets.mautrix = {
file = ../../../secrets/matrix/mautrix.age;
group = "mautrix";
};
services.mautrix-meta = {
instances.messenger = {
enable = true;
environmentFile = config.age.secrets.mautrix.path;
settings = lib.recursiveUpdate commons {
database.type = "postgres";
database.uri = "postgres:///mautrix-meta?host=/run/postgresql/";
network.mode = "messenger";
appservice.id = "metabot";
appservice.bot = {
username = "metabot";
displayname = "Messenger";
};
encryption.pickle_key = "$META_PICKLE_KEY";
};
};
};
services.mautrix-whatsapp = {
enable = true;
environmentFile = config.age.secrets.mautrix.path;
settings = lib.recursiveUpdate commons {
database.type = "postgres";
database.uri = "postgres:///mautrix-whatsapp?host=/run/postgresql/";
appservice.id = "whatsappbot";
appservice.bot = {
username = "whatsappbot";
displayname = "WhatsApp";
};
encryption.pickle_key = "$WHATSAPP_PICKLE_KEY";
};
};
services.mautrix-signal = {
enable = true;
environmentFile = config.age.secrets.mautrix.path;
settings = lib.recursiveUpdate commons {
database.type = "postgres";
database.uri = "postgres:///mautrix-signal?host=/run/postgresql/";
appservice.id = "signalbot";
appservice.bot = {
username = "signalbot";
displayname = "Signal";
};
encryption.pickle_key = "$SIGNAL_PICKLE_KEY";
};
};
}

View file

@ -0,0 +1,11 @@
{ prefs, ... }: let
domain = prefs.config.thor.domain;
in {
defaultHomeserver = 0;
homeserverList = [ domain ];
allowCustomHomeservers = false;
hashRouter = {
enabled = true;
basename = "/";
};
}

View file

@ -0,0 +1,77 @@
{
config,
prefs,
...
}:
{
imports = [ ./nginx.nix ];
age.secrets.doublepuppet = {
file = ../../secrets/matrix/doublepuppet.age;
owner = "matrix-synapse";
};
services.matrix-synapse = {
enable = true;
configureRedisLocally = true;
settings = rec {
no_tls = true;
server_name = prefs.config.thor.domain;
public_baseurl = "https://matrix.${server_name}/";
database = {
name = "psycopg2";
allow_unsafe_locale = true;
args = {
cp_min = 5;
cp_max = 10;
};
};
app_service_config_files = [
config.age.secrets.doublepuppet.path
];
listeners = [
{
port = 8008;
type = "http";
tls = false;
resources = [
{ names = ["client"]; compress = true; }
{ names = ["federation"]; compress = false; }
];
}
];
experimental_features = {
faster_event_fetching = true;
faster_room_joins = true;
msc3083_enabled = true;
msc2716_enabled = true;
msc3246_enabled = true;
msc3266_enabled = true;
msc4222_enabled = true;
msc4140_enabled = true;
};
rc_message = {
per_second = 0.5;
burst_count = 30;
};
rc_delayed_event_mgmt = {
per_second = 1;
burst_count = 20;
};
report_stats = false;
enable_metrics = false;
enable_registration = false;
suppress_key_server_warning = true;
forgotten_room_retention_period = "30d";
media_retention.remote_media_lifetime = "14d";
};
};
}

View file

@ -0,0 +1,39 @@
{ prefs, pkgs, ... }:
{
services.nginx.virtualHosts."matrix.${prefs.config.thor.domain}" = {
listen = [ { addr = "0.0.0.0"; port = 80; } ];
locations = {
"/".root = pkgs.cinny.override {
conf = import ./cinny-config.nix { inherit prefs; };
};
"~ ^(/_matrix|/_synapse)" = {
proxyPass = "http://127.0.0.1:8008";
extraConfig = "client_max_body_size 50M;";
};
"~ ^/.well-known/matrix/server" = {
extraConfig = ''
default_type application/json;
add_header Access-Control-Allow-Origin *;
return 200 '{ "m.server": "matrix.${prefs.config.thor.domain}:443" }';
'';
};
"~ ^/.well-known/matrix/client" = {
extraConfig = ''
default_type application/json;
add_header Access-Control-Allow-Origin *;
return 200 '{
"m.homeserver": { "base_url": "https://matrix.${prefs.config.thor.domain}" },
"org.matrix.msc4143.rtc_foci": [
{ "type": "livekit", "livekit_service_url": "https://rtc.matrix.${prefs.config.thor.domain}" },
{ "type": "nextgen_new_foci_type", "props_for_nextgen_foci": "val" }
]
}';
'';
};
};
};
}

View file

@ -0,0 +1,112 @@
{
config,
prefs,
pkgs,
...
}:
let
domain = prefs.config.thor.domain;
in {
age.secrets.nextcloud = {
file = ../../secrets/nextcloud/nextcloud.age;
owner = "nextcloud";
};
age.secrets.nextcloudPassword = {
file = ../../secrets/nextcloud/adminPassword.age;
owner = "nextcloud";
};
age.secrets.whiteboard = {
file = ../../secrets/nextcloud/whiteboard.age;
owner = "cool";
};
services.nextcloud = {
enable = true;
caching.redis = true;
configureRedis = true;
hostName = "cloud.${domain}";
database.createLocally = true;
secretFile = config.age.secrets.nextcloud.path;
package = pkgs.nextcloud31;
config = {
dbtype = "pgsql";
adminpassFile = config.age.secrets.nextcloudPassword.path;
};
settings = {
mail_smtpmode = "smtp";
mail_sendmailmode = "smtp";
mail_smtpport = 587;
mail_smtpauth = true;
"memcache.local" = "\\OC\\Memcache\\Redis";
"memcache.distributed" = "\\OC\\Memcache\\Redis";
"memcache.locking" = "\\OC\\Memcache\\Redis";
"opcache.memory_consumption" = 4096;
"opcache.revalidate_freq" = 60;
trusted_domains = [
"cloud.${domain}"
];
};
extraApps = {
inherit (config.services.nextcloud.package.packages.apps)
app_api
contacts
calendar
tasks
richdocuments
notes
deck
end_to_end_encryption
forms
mail
twofactor_admin
twofactor_webauthn
whiteboard;
};
};
services.nextcloud-whiteboard-server = {
enable = true;
secrets = [
config.age.secrets.whiteboard.path
];
};
services.collabora-online = {
enable = true;
aliasGroups = [
{
host = "https://office.cloud.${prefs.config.thor.domain}";
aliases = [ "https://${config.services.nextcloud.hostName}" ];
}
];
settings = {
ssl = {
enable = false;
termination = true;
};
net = {
proto = "IPv4";
listen = "loopback";
post_allow.host = [ "127.0.0.1" ];
};
storage.wopi = {
"@allow" = true;
host = [ "cloud.${domain}" ];
};
server_name = "office.cloud.${domain}";
};
};
}

View file

@ -0,0 +1,39 @@
{
inputs,
prefs,
...
}:
let
frontendUrl = "piped.${prefs.config.thor.domain}";
proxyUrl = "proxy.${frontendUrl}";
backendUrl = "api.${frontendUrl}";
in {
imports = [
inputs.piped.nixosModules.default
];
services.piped-backend = {
enable = true;
settings = {
PORT = 14302;
DISABLE_REGISTRATION = true;
API_URL = "https://${backendUrl}";
PROXY_PART = "https://${proxyUrl}";
FRONTEND_URL = "https://${frontendUrl}";
};
};
services.piped-frontend = {
enable = true;
listenPort = 14301;
listenHost = "127.0.0.1";
publicBackendUrl = "https://${backendUrl}";
publicFrontendUrl = "https://${frontendUrl}";
};
services.piped-proxy = {
enable = true;
listenAddress = "127.0.0.1:14300";
};
}

View file

@ -0,0 +1,36 @@
{
config,
prefs,
lib,
...
}:
let
cfg = config.services.vaultwarden;
in {
age.secrets.vaultwarden = {
file = ../../secrets/vaultwarden.age;
owner = "vaultwarden";
};
services.vaultwarden = {
enable = true;
dbBackend = "postgresql";
environmentFile = config.age.secrets.vaultwarden.path;
config = lib.mkMerge [
{
WEBSOCKET_ENABLED = true;
SIGNUPS_ALLOWED = false;
ORG_GROUPS_ENABLED = true;
DOMAIN = "https://passwords." + prefs.config.thor.domain;
EXPERIMENTAL_CLIENT_FEATURE_FLAGS = "fido2-vault-credentials,autofill-overlay,ssh-key-vault-item,ssh-agent";
}
(with prefs.config.thor.emailConfig; {
SMTP_HOST = server;
SMTP_PORT = port;
SMTP_FROM = from;
SMTP_USERNAME = login;
})
];
};
}

View file

@ -0,0 +1,58 @@
{
config,
pkgs,
...
}:
{
age.secrets.wireguardPrivateKey.file = ../../secrets/wireguardPrivateKey.age;
networking.nat = {
enable = true;
externalInterface = "eth0";
internalInterfaces = [ "wg0" ];
};
networking.firewall.allowedUDPPorts = [ 666 ];
networking.wireguard.interfaces.wg0 = {
ips = [ "10.13.13.1/24" ];
listenPort = 666;
postSetup = ''
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.13.13.0/24 -o eth0 -j MASQUERADE
'';
postShutdown = ''
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.13.13.0/24 -o eth0 -j MASQUERADE
'';
privateKeyFile = config.age.secrets.wireguardPrivateKey.path;
peers = [
{
name = "mobile";
publicKey = "k6MnUITosyGeSwdfZZCLrEnjFqvdda6Sg171EXzZGyg=";
allowedIPs = [ "10.13.13.7/32" ];
}
{
name = "pc";
publicKey = "63/Z327qKgP53Dw+0/+84o42kGtiT/u/gdL53PeM8W4=";
allowedIPs = [ "10.13.13.8/32" ];
}
{
name = "backup";
publicKey = "Bs/71KdoxwUbM+M03k9tDGfnjdtCwb6WllVDklXgbR4=";
allowedIPs = [ "10.13.13.9/32" ];
}
{
name = "tv1";
publicKey = "gPjN0VUA/LJ49Xxh53NkgUSasyo8pW4ylr5/ggWromk=";
allowedIPs = [ "10.13.13.10/32" ];
}
{
name = "tv2";
publicKey = "D5U5F4+XwyU1SuC//PtVnKc3WpGMF6sRoadB/LHGAg8=";
allowedIPs = [ "10.13.13.11/32" ];
}
];
};
}

0
modules/derivations/nordvpn.nix Normal file → Executable file
View file

30
modules/desktop-environments/hyprland.nix Normal file → Executable file
View file

@ -38,6 +38,18 @@
]
++ config.modules.hyprland.additionalPackages;
# set Wayland-specific environment variables
home.sessionVariables = {
NIXOS_OZONE_WL = "1";
XWAYLAND_NO_GLAMOR = "0";
GDK_BACKEND = "wayland";
SDL_VIDEODRIVER = "wayland";
QT_QPA_PLATFORM = "wayland";
LIBVA_DRIVER_NAME = "nvidia";
__GLX_VENDOR_LIBRARY_NAME = "nvidia";
ELECTRON_OZONE_PLATFORM_HINT = "auto";
};
wayland.windowManager.hyprland = {
enable = true;
plugins = config.modules.hyprland.plugins;
@ -45,13 +57,17 @@
};
xdg.portal = {
extraPortals = with pkgs; [ xdg-desktop-portal-wlr ];
config.hyprland = {
"default" = [ "hyprland" "wlr" ];
"org.freedesktop.impl.portal.ScreenCast" = "wlr";
"org.freedesktop.impl.portal.Screenshot" = "wlr";
"org.freedesktop.impl.portal.Settings" = "darkman";
};
extraPortals = with pkgs; [ xdg-desktop-portal-wlr ];
config.hyprland = {
"default" = [
"hyprland"
"wlr"
];
"org.freedesktop.impl.portal.ScreenCast" = "hyprland";
"org.freedesktop.impl.portal.Settings" = "darkman";
"org.freedesktop.impl.portal.Screenshot" = "wlr";
};
};
systemd.user.services.authentication-agent = {

View file

@ -0,0 +1,42 @@
{ pkgs, config, lib, ... }:
{
options.modules.plasma6 = {
enable = lib.mkEnableOption "Enable KDE Plasma 6";
additionalPackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
description = "Additional Plasma-related packages to install";
default = [ ];
};
};
config = lib.mkIf config.modules.plasma6.enable {
home.packages =
with pkgs.kdePackages;
[
plasma-workspace
kdeconnect-kde
spectacle
dolphin
konsole
kwalletmanager
]
++ config.modules.plasma6.additionalPackages;
home.sessionVariables = {
QT_QPA_PLATFORM = "wayland";
QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
XDG_SESSION_TYPE = "wayland";
XDG_CURRENT_DESKTOP = "KDE";
GDK_BACKEND = "wayland,x11";
};
xdg.portal = {
enable = true;
config.kde.default = [ "kde" ];
extraPortals = with pkgs; [
kdePackages.xdg-desktop-portal-kde
];
};
};
}

0
modules/home-manager/ags.nix Normal file → Executable file
View file

0
modules/home-manager/apple-style.nix Normal file → Executable file
View file

3
modules/home-manager/darkman.nix Normal file → Executable file
View file

@ -26,7 +26,8 @@ let
done
'';
switch-theme = theme: "$(${find-generation})/${theme}/activate && systemctl restart --user hyprpaper";
switch-theme =
theme: "$(${find-generation})/${theme}/activate && systemctl restart --user hyprpaper";
in
{
options.modules.darkman = {

10
modules/home-manager/fish.nix Normal file → Executable file
View file

@ -1,4 +1,9 @@
{ config, pkgs, lib, ... }:
{
config,
pkgs,
lib,
...
}:
{
options.modules.fish = {
@ -17,6 +22,7 @@
functions = lib.mkOption {
type = with lib.types; attrsOf str;
default = {};
description = "Fish function definitions";
};
};
@ -42,7 +48,7 @@
".." = "cd ..";
"..." = "cd ../..";
"...." = "cd ../../../";
"....." = "cd ../../../../";
"....." = "cd self + ./";
"cp" = "cp -v";
"ddf" = "df -h";

0
modules/home-manager/stylix.nix Normal file → Executable file
View file

73
modules/nixos/apps/newt.nix Executable file
View file

@ -0,0 +1,73 @@
{
config,
lib,
pkgs,
...
}:
let
mkStr = description: default: lib.mkOption {
inherit description default;
type = lib.types.str;
};
in {
options.modules.newt = {
enable = lib.mkEnableOption "Enable Newt client used to securely expose services for Pangolin";
id = mkStr "Newt ID generated by Pangolin for this client" null;
endpoint = mkStr "The URL of Pangolin server dashboard" null;
group = mkStr "The group Newt should run as" "newt";
user = mkStr "The user Newt should run as" "newt";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.newt-go;
description = ''
The Newt package to use
'';
};
secretFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Path to the file containing Newt connection token
'';
};
};
config = lib.mkIf config.modules.newt.enable {
systemd.services.newt = with config.modules.newt; {
description = "Newt, a user space tunnel client to securely expose services for Pangolin";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
script = ''
NEWT_SECRET=$(cat "$CREDENTIALS_DIRECTORY/SECRET")
exec ${lib.getExe package} \
--secret "$NEWT_SECRET" \
--id ${id} \
--endpoint ${endpoint}
'';
serviceConfig = {
DynamicUser = true;
User = user;
Group = group;
Restart = "always";
RestartSec = "10s";
StateDirectory = "newt";
WorkingDirectory = "%S/newt";
LoadCredential = "SECRET:${secretFile}";
CapabilityBoundingSet = [
"~CAP_MKNOD"
"~CAP_NET_RAW"
"~CAP_PERFMON"
"~CAP_SYS_MODULE"
"~CAP_SYS_TIME"
];
};
};
};
}

View file

View file

@ -0,0 +1,90 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkEnableOption mkOption mkIf types literalExpression;
in {
options.modules.qbittorrent = {
enable = mkEnableOption ("Headless qBittorrent daemon");
dataDir = mkOption {
type = types.path;
default = "/var/lib/qbittorrent";
description = "Directory to store qBittorrent configuration and data.";
};
user = mkOption {
type = types.str;
default = "qbittorrent";
description = "The system user under which qBittorrent runs.";
};
group = mkOption {
type = types.str;
default = "qbittorrent";
description = "The system group associated with the qBittorrent user.";
};
port = mkOption {
type = types.port;
default = 8080;
description = "Port for the qBittorrent Web UI.";
};
openFirewall = mkOption {
type = types.bool;
default = false;
description = "Whether to open the firewall for the Web UI port.";
};
package = mkOption {
type = types.package;
default = pkgs.qbittorrent-nox;
description = "The qBittorrent package to use.";
};
};
config = let
cfg = config.modules.qbittorrent;
in mkIf cfg.enable {
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [
cfg.port
];
users.groups.${cfg.group} = {};
users.users.${cfg.user} = {
isNormalUser = true;
group = cfg.group;
};
systemd.services.qbittorrent = {
description = "qBittorrent Headless Service";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
Type = "simple";
User = cfg.user;
Group = cfg.group;
ExecStartPre = let
prestart = pkgs.writeScript "prepare-qbittorrent-dir" ''
#!${pkgs.runtimeShell}
if [ ! -d "$QBT_DATA_DIR" ]; then
echo "Initializing qBittorrent directory at: $QBT_DATA_DIR"
install -d -m 0755 -o '${cfg.user}' \
-g '${cfg.group}' "$QBT_DATA_DIR"
fi
'';
in "!${prestart}";
ExecStart = "${cfg.package}/bin/qbittorrent-nox";
UMask = "0002";
};
environment = {
QBT_DATA_DIR = cfg.dataDir;
QBT_WEBUI_PORT = toString cfg.port;
};
};
};
}

0
modules/nixos/audio.nix Normal file → Executable file
View file

0
modules/nixos/bluetooth.nix Normal file → Executable file
View file

0
modules/nixos/fingerprint.nix Normal file → Executable file
View file

40
modules/nixos/greetd.nix Normal file → Executable file
View file

@ -9,7 +9,8 @@
options.modules.greetd = {
enable = lib.mkEnableOption "Enable GreetD with TUI-based login.";
command = lib.mkOption {
type = lib.types.str;
type = with lib.types; nullOr str;
default = null;
description = "Command to run after successful login";
};
};
@ -17,14 +18,35 @@
config = lib.mkIf config.modules.greetd.enable {
services.greetd = {
enable = true;
settings = {
terminal.vt = 1;
default_session.command = ''
${pkgs.greetd.tuigreet}/bin/tuigreet
--time
--cmd ${config.modules.greetd.command}
'';
};
settings =
let
cmd =
if config.modules.greetd.command != null then
config.modules.greetd.command
else
lib.getExe pkgs.hyprland;
in
{
terminal.vt = 1;
default_session.command = builtins.toString [
"${lib.getExe pkgs.greetd.tuigreet}"
"--remember"
"--remember-user-session"
"--time"
"--cmd ${cmd}"
];
};
};
systemd.services.greetd.serviceConfig = {
Type = "idle";
StandardInput = "tty";
StandardOutput = "tty";
# Disable bootlog spam on tty1
StandardError = "journal";
TTYVHangup = true;
TTYVTDisallocate = true;
};
};
}

19
modules/nixos/nvidia-support.nix Normal file → Executable file
View file

@ -1,29 +1,28 @@
{ config, pkgs, lib, prefs, ... }:
{
config,
pkgs,
lib,
prefs,
...
}:
{
options.modules.nvidia.enable = lib.mkEnableOption "Enable NVIDIA kernel and modprobe configurations.";
config = lib.mkIf config.modules.nvidia.enable {
environment.systemPackages = with pkgs; [
libva
nvidia-vaapi-driver
];
hardware.graphics = {
enable = true;
enable32Bit = true;
};
services.xserver.videoDrivers = [ "nvidia" ];
boot.kernelParams = ["nvidia.NVreg_PreserveVideoMemoryAllocations=1"];
hardware.nvidia = {
modesetting.enable = true;
powerManagement.finegrained = true;
prime = {
offload.enable = true;
intelBusId = prefs.hosts.hulk.intelBusId;
nvidiaBusId = prefs.hosts.hulk.nvidiaBusId;
intelBusId = prefs.config.hulk.intelBusId;
nvidiaBusId = prefs.config.hulk.nvidiaBusId;
};
package = config.boot.kernelPackages.nvidiaPackages.legacy_470;

56
modules/nixos/samba.nix Executable file
View file

@ -0,0 +1,56 @@
{ config, lib, ... }:
let
cfg = config.modules.samba;
mkSamba = entries: builtins.mapAttrs (_: path: {
inherit path;
"browseable" = "yes";
"read only" = "no";
"guest ok" = "no";
"create mask" = "0644";
"directory mask" = "0755";
}) entries;
in {
options.modules.samba = {
enable = lib.mkEnableOption "Enable Samba file share";
user = lib.mkOption {
type = lib.types.str;
default = "samba";
description = "Default Samba user name";
};
group = lib.mkOption {
type = lib.types.str;
default = "samba";
description = "Default Samba group name";
};
shares = lib.mkOption {
type = lib.types.functionTo lib.types.attrs;
default = _: {};
description = "Samba shares (created by a helper)";
};
};
config = lib.mkIf cfg.enable {
users.groups.${cfg.group} = {};
users.users.${cfg.user} = {
isNormalUser = true;
group = cfg.group;
};
services.samba = {
enable = true;
openFirewall = true;
settings = builtins.mapAttrs (_: value: value // {
"force group" = cfg.group;
}) (config.modules.samba.shares mkSamba);
};
services.samba-wsdd = {
enable = true;
openFirewall = true;
};
};
}

4
overlay.nix Normal file → Executable file
View file

@ -1,5 +1,5 @@
inputs: final: prev: {
android-sdk = prev.callPackage inputs.android-sdk {};
android-sdk = prev.callPackage inputs.android-sdk { };
vscodium-wayland = prev.vscodium.override {
commandLineArgs = [
"--enable-features=UseOzonePlatform"
@ -7,4 +7,4 @@ inputs: final: prev: {
"--ozone-platform=wayland"
];
};
}
}

81
preferences.nix Normal file → Executable file
View file

@ -1,4 +1,5 @@
{ inputs }: rec {
{ inputs }:
rec {
users = {
hulk = {
username = "sadorowo";
@ -7,6 +8,22 @@
preferredShell = pkgs: pkgs.fish;
isRoot = false;
};
thor = {
username = "thor";
fullname = "Thor SuperAdmin";
homeDirectory = "/home/${users.thor.username}";
preferredShell = pkgs: pkgs.bash;
isRoot = true;
};
odin = {
username = "anna";
fullname = "Anna";
homeDirectory = "/home/${users.thor.username}";
preferredShell = pkgs: pkgs.fish;
isRoot = false;
};
};
nixpkgs = system: import inputs.nixpkgs {
@ -18,26 +35,64 @@
"fluffychat-linux-1.22.1"
"olm-3.2.16"
];
allowUnfreePredicate = pkg: builtins.elem (inputs.nixpkgs.lib.getName pkg) [
"davinci-resolve"
"anydesk"
"nvidia-settings"
"nvidia-x11"
"nordvpn"
"hplip"
];
allowUnfreePredicate =
pkg:
builtins.elem (inputs.nixpkgs.lib.getName pkg) [
"davinci-resolve"
"broadcom-sta"
"anydesk"
"nvidia-settings"
"nvidia-x11"
"nordvpn"
"hplip"
];
};
};
config = {
hulk = {
nvidiaBusId = "PCI:2:0:0";
intelBusId = "PCI:0:2:0";
};
thor = {
domain = "sador.me";
newtId = "91ozwbod2yokhut";
emailConfig = {
server = "smtp.purelymail.com";
port = 587;
login = "cloud@sador.me";
from = "sador.me cloud services <cloud@sador.me>";
tls = "starttls";
};
};
};
hosts = {
hulk = {
nvidiaBusId = "PCI:2:0:0";
intelBusId = "PCI:0:2:0";
system = "x86_64-linux";
useHomeManager = true;
};
odin = {
system = "x86_64-linux";
useHomeManager = true;
};
thor = {
system = "x86_64-linux";
useHomeManager = false;
};
};
homes = {
sadorowo = ./profiles/sadorowo;
anna = ./profiles/anna;
};
keys = {
hulk = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBTfnrtXWMpoqDcKvs3pc7M9BhP7SmzBsBA9RLc5TCRY";
thor = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINgXw/wzKYuv4BNFAGvO+c7TvQRRKvay54qc2Y/vk6Ii";
};
}

39
profiles/anna/apps/firefox.nix Executable file
View file

@ -0,0 +1,39 @@
{
programs.firefox = {
enable = true;
profiles = {
anna = {
isDefault = true;
settings = {
"media.videocontrols.picture-in-picture.enabled" = false;
"widget.wayland-dmabuf-vaapi.enabled" = true;
"browser.ctrlTab.recentlyUsedOrder" = false;
"extensions.pocket.enabled" = false;
"gfx.webrender.all" = true;
};
};
};
policies = {
DisableTelemetry = true;
DisableFirefoxStudies = true;
EnableTrackingProtection = {
Value = true;
Locked = true;
Cryptomining = true;
Fingerprinting = true;
};
SearchEngines.Default = "DuckDuckGo";
DisablePocket = true;
DisableFirefoxScreenshots = true;
OverrideFirstRunPage = "";
OverridePostUpdatePage = "";
DontCheckDefaultBrowser = true;
DisplayBookmarksToolbar = "always";
DisplayMenuBar = "never";
SearchBar = "unified";
};
};
}

18
profiles/anna/default.nix Executable file
View file

@ -0,0 +1,18 @@
{
pkgs,
prefs,
inputs,
...
}:
{
imports = [ ./modules.nix ];
home = {
inherit (prefs.users.odin) username homeDirectory;
packages = import ./packages.nix { inherit pkgs inputs; };
stateVersion = "25.05";
};
programs.home-manager.enable = true;
}

19
profiles/anna/modules.nix Executable file
View file

@ -0,0 +1,19 @@
{ inputs, pkgs, ... }:
{
imports = [
# DE + style
../../modules/desktop-environments/kde-plasma.nix
# Utilities + apps
../../modules/home-manager/fish.nix
./apps/firefox.nix
];
modules.plasma6.enable = true;
modules.fish = {
enable = true;
enableStarship = true;
enableDefaultAliases = false;
};
}

10
profiles/anna/packages.nix Executable file
View file

@ -0,0 +1,10 @@
{ pkgs, ... }:
with pkgs;
[
element-desktop
libreoffice-qt6-fresh
anydesk
fastfetch
adwaita-icon-theme
]

27
profiles/default.nix Normal file → Executable file
View file

@ -7,11 +7,22 @@
let
inherit (self) inputs;
mkHome = system: profile: inputs.home-manager.lib.homeManagerConfiguration {
pkgs = prefs.nixpkgs system;
extraSpecialArgs = { inherit self inputs prefs; };
modules = [ profile ];
};
in {
sadorowo = mkHome "x86_64-linux" ./sadorowo;
}
mkHome =
profile:
inputs.home-manager.lib.homeManagerConfiguration {
pkgs = prefs.nixpkgs "x86_64-linux";
extraSpecialArgs = { inherit self inputs prefs; };
modules = [
profile
{
manual = {
html.enable = false;
manpages.enable = false;
json.enable = false;
};
}
];
};
in builtins.mapAttrs (name: path:
mkHome path
) prefs.homes

2
profiles/sadorowo/apps/firefox.nix Normal file → Executable file
View file

@ -35,5 +35,5 @@
DisplayMenuBar = "never";
SearchBar = "unified";
};
};
};
}

104
profiles/sadorowo/apps/fish/functions.nix Normal file → Executable file
View file

@ -1,32 +1,86 @@
{
webcopy = ''
set -l domain (string trim $argv)
wget --recursive \
--level 5 \
--no-clobber \
--page-requisites \
--adjust-extension \
--span-hosts \
--convert-links \
--domains $domain \
--no-parent \
$domain
'';
set -l domain (string trim $argv)
wget --recursive \
--level 5 \
--no-clobber \
--page-requisites \
--adjust-extension \
--span-hosts \
--convert-links \
--domains $domain \
--no-parent \
$domain
'';
venv = ''
if [ -d .venv ]; then
source .venv/bin/activate.fish
else
python -m venv .venv
source .venv/bin/activate.fish
fi
'';
if [ -d .venv ]; then
source .venv/bin/activate.fish
else
python -m venv .venv
source .venv/bin/activate.fish
fi
'';
thunderbird = ''
if pgrep -x birdtray > /dev/null
birdtray -s
else
birdtray &
end
'';
if pgrep -x birdtray > /dev/null
birdtray -s
else
birdtray &
end
'';
ls = ''
set opts
set paths
for arg in $argv
if string match -qr '^-' -- $arg
set opts $opts $arg
else
set paths $paths $arg
end
end
if test (count $paths) -eq 0
set paths .
end
for path in $paths
if test -d "$path"
command ls $opts $path
else if test -f "$path"
command cat $path
else
echo "ls: cannot access '$path': No such file or directory"
end
end
'';
cat = ''
set opts
set paths
for arg in $argv
if string match -qr '^-' -- $arg
set opts $opts $arg
else
set paths $paths $arg
end
end
if test (count $paths) -eq 0
set paths .
end
for path in $paths
if test -d "$path"
command ls $opts $path
else if test -f "$path"
command cat $path
else
echo "cat: $path: No such file or directory"
end
end
'';
}

0
profiles/sadorowo/default.nix Normal file → Executable file
View file

Some files were not shown because too many files have changed in this diff Show more