Compare commits
64 Commits
d25ad73b3b
...
matrix-rtc
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ac96316ea | |||
| 8d636ce194 | |||
| bbeed99f43 | |||
| 7e6ece1b0d | |||
| 60952a0e7f | |||
| 738013df66 | |||
| 34160d0de4 | |||
| 02b8a16f41 | |||
| 684f6fdea5 | |||
| 7ef1785a0f | |||
| 49c0c607d8 | |||
| ab52b423ee | |||
| f852a73d47 | |||
| 998ebc1164 | |||
| 9acb378e5f | |||
| dca434c0ba | |||
| c22ff38874 | |||
| 0591868be3 | |||
| e249f13313 | |||
| 4ecf045deb | |||
| 05d1890b01 | |||
| 2babff5576 | |||
| aa7c26516c | |||
| a1369cbb41 | |||
| 54c5cf932d | |||
| bb68711814 | |||
| 6b31922615 | |||
| 21e779c304 | |||
| e718da413b | |||
| 98989afdec | |||
| 3a97de6af2 | |||
| 66b7a31943 | |||
| ddb53d879e | |||
| e403e47c28 | |||
| d8b3d6fb09 | |||
| 91d6863d60 | |||
| 618e5593e7 | |||
| e1c9a27ca3 | |||
| 7a58571c03 | |||
| 768caf9882 | |||
| e07d6a44a3 | |||
| 97d8c17436 | |||
| 89fd861c20 | |||
| cf30dc9f6c | |||
| b88704bf1f | |||
| eb63ef2585 | |||
| d688fc0eef | |||
| 63a4fba675 | |||
| 8fedc57570 | |||
| dd322cb71c | |||
| 23b5917620 | |||
| 5cecce74e8 | |||
| 15853f918a | |||
| 22d619b3ce | |||
| d5396917c3 | |||
| a7d4a88741 | |||
| 2f901052f1 | |||
| 56f1ba896c | |||
| 9607e8f3a4 | |||
| 41f5da953a | |||
| a444694054 | |||
| 62dd4d3713 | |||
| da8f61ca5d | |||
| 1bb14d4c62 |
198
AGENTS.md
Normal file
198
AGENTS.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# Agent Guidelines for NixOS/nix-darwin Dotfiles
|
||||
|
||||
This repository contains NixOS, nix-darwin, and Home Manager configurations in Nix. You are a sysadmin managing server configurations and deployments.
|
||||
|
||||
## Build, Test, and Deployment Commands
|
||||
|
||||
### Build and Apply Configurations
|
||||
|
||||
**Linux (NixOS):**
|
||||
```bash
|
||||
just build # Build configuration
|
||||
just install cores='32' # Apply with 32 cores
|
||||
sudo nixos-rebuild test --fast --flake . # Test without activation
|
||||
sudo nixos-rebuild switch --rollback --flake . # Rollback
|
||||
```
|
||||
|
||||
**macOS (nix-darwin):**
|
||||
```bash
|
||||
just build # Build configuration
|
||||
just install # Apply configuration
|
||||
```
|
||||
|
||||
**Home Manager:**
|
||||
```bash
|
||||
just home
|
||||
```
|
||||
|
||||
### Deploy to Remote Machines (deploy-rs)
|
||||
|
||||
```bash
|
||||
deploy -s .#ryu # Desktop (x86_64-linux)
|
||||
deploy -s .#tako # Server (x86_64-linux)
|
||||
deploy -s .#tsuba # Raspberry Pi (aarch64-linux)
|
||||
deploy -s .#kuro # MacBook M4 Pro (aarch64-darwin)
|
||||
deploy -s .#shiro # Mac Mini M4 (aarch64-darwin)
|
||||
```
|
||||
|
||||
### Validation and Formatting
|
||||
|
||||
```bash
|
||||
nix flake check --show-trace # Check flake for errors
|
||||
alejandra fmt . # Format all files
|
||||
alejandra fmt <file>.nix # Format single file
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
- `flake.nix` - Main entry point, device definitions
|
||||
- `nixos/` - NixOS machine configs (ryu, tako, tsuba)
|
||||
- `darwin/` - macOS machine configs (kuro, shiro)
|
||||
- `home/` - Home Manager modules (programs/, services/, apps/)
|
||||
- `modules/` - Custom modules (nixos/, darwin/, home/)
|
||||
- `secrets/` - SOPS encrypted secrets
|
||||
- `overlays.nix`, `deploy.nix`, `sops.nix`, `stylix.nix` - Config files
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### Nix Language Conventions
|
||||
|
||||
**File Structure:**
|
||||
```nix
|
||||
{inputs, config, pkgs, lib, device, ...}: {
|
||||
# Configuration here
|
||||
}
|
||||
```
|
||||
|
||||
**Imports:**
|
||||
- Order: `inputs`, `config`, `pkgs`, `lib`, `device`, custom params, `...`
|
||||
- Use set destructuring for clarity
|
||||
|
||||
**Formatting:**
|
||||
- Use `alejandra` formatter (run before committing)
|
||||
- 2-space indentation
|
||||
- Trailing commas in lists and attribute sets
|
||||
|
||||
**Naming Conventions:**
|
||||
- Files: lowercase-with-hyphens (e.g., `my-module.nix`)
|
||||
- Attributes: camelCase (e.g., `enableMyFeature`)
|
||||
- Functions: camelCase (e.g., `mkDevice`)
|
||||
- Constants: UPPER_SNAKE_CASE (e.g., `API_KEY`)
|
||||
- Device names: lowercase (e.g., `ryu`, `tako`)
|
||||
|
||||
**Let Expressions:**
|
||||
```nix
|
||||
with lib; let
|
||||
cfg = config.programs.myProgram;
|
||||
in {
|
||||
options = { ... };
|
||||
config = mkIf cfg.enable { ... };
|
||||
}
|
||||
```
|
||||
|
||||
**Conditionals:**
|
||||
- Use `mkIf` for config options
|
||||
- Use `lib.optionalAttrs` for attribute sets
|
||||
- Use `lib.optionals` for lists
|
||||
|
||||
### Module Patterns
|
||||
|
||||
**Simple Package Module:**
|
||||
```nix
|
||||
{pkgs, ...}: {
|
||||
home.packages = [pkgs.myPackage];
|
||||
}
|
||||
```
|
||||
|
||||
**Program Configuration Module:**
|
||||
```nix
|
||||
{config, pkgs, lib, ...}:
|
||||
with lib; let
|
||||
cfg = config.programs.myProgram;
|
||||
in {
|
||||
options.programs.myProgram = {
|
||||
enable = mkEnableOption "myProgram";
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [pkgs.myProgram];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
**Device-Specific Logic:**
|
||||
```nix
|
||||
home.packages = lib.optionals device.isLinux [pkgs.linuxPackage]
|
||||
++ lib.optionals device.isDarwin [pkgs.macPackage];
|
||||
|
||||
sessionVariables.BROWSER = if device.isDarwin then "open" else "xdg-open";
|
||||
```
|
||||
|
||||
## Important Rules
|
||||
|
||||
1. **NEVER create markdown files** unless explicitly requested
|
||||
2. **DO NOT add shell scripts** - use Nix expressions
|
||||
3. **All configurations must use Nix expressions** when possible
|
||||
4. **Follow existing naming conventions** and directory structure
|
||||
5. Create custom application entries in `~/.local/share/applications/{appname}.desktop`
|
||||
|
||||
## Secrets Management
|
||||
|
||||
- Secrets are managed with SOPS in `secrets/` directory
|
||||
- Encrypted secrets in `secrets/` directory
|
||||
- Configuration in `.sops.yaml`
|
||||
- Access via `config.sops.secrets."secret/value".path`
|
||||
```yaml
|
||||
foo:
|
||||
bar: somesecret
|
||||
```
|
||||
The path is the file that contains `somesecret`
|
||||
- Add new secrets using `sops set`
|
||||
Example
|
||||
```bash
|
||||
openssl rand -hex 32 | tr -d '\n' | jq -sR | sops set --value-stdin secrets/secrets.yaml '["foo"]["bar"]'
|
||||
```
|
||||
This will add a randomly generated secret to the sops file
|
||||
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Adding a New Program
|
||||
|
||||
```bash
|
||||
just add program myprogram # Creates home/programs/myprogram.nix and adds import
|
||||
```
|
||||
|
||||
### Adding a new dns entry
|
||||
```bash
|
||||
cfcli add --type A foobar.bazbar.biz 192.168.0.1
|
||||
```
|
||||
|
||||
### Creating a Module
|
||||
|
||||
1. Determine location: `modules/nixos/`, `modules/darwin/`, or `modules/home/`
|
||||
2. Create file with proper structure
|
||||
3. Add to `modules/default.nix` imports
|
||||
|
||||
### Device Configuration
|
||||
|
||||
Devices are defined in `flake.nix` using `mkDevice`. Properties available:
|
||||
- `device.isLinux`, `device.isDarwin`, `device.isArm`
|
||||
- `device.isServer`, `device.hasGui`, `device.isDesktopLinux`
|
||||
- `device.name`, `device.user`, `device.home`
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Use `mkIf` to conditionally enable configurations
|
||||
- Handle both Linux and macOS cases when adding cross-platform features
|
||||
|
||||
## Testing Changes
|
||||
|
||||
1. Build first: `just build` or `nixos-rebuild build --flake .`
|
||||
2. Check for errors with `--show-trace` flag
|
||||
|
||||
## Version Information
|
||||
|
||||
- Nix Version: 2.32+
|
||||
- Flakes: Enabled (required)
|
||||
- Formatter: alejandra
|
||||
- State Version: (varies by machine & never change this)
|
||||
@@ -1,7 +0,0 @@
|
||||
# {
|
||||
# hostName = "mirai.darksailor.dev";
|
||||
# sshUser = "remotebuilder";
|
||||
# systems = ["x86_64-linux" "aarch64-linux"];
|
||||
# protocol = "ssh-ng";
|
||||
# supportedFeatures = ["nixos-test" "benchmark" "big-parallel" "kvm"];
|
||||
# }
|
||||
16
deploy.nix
16
deploy.nix
@@ -55,13 +55,13 @@
|
||||
user = "root";
|
||||
};
|
||||
};
|
||||
# deck = {
|
||||
# hostname = "steamdeck";
|
||||
# profiles.system = {
|
||||
# sshUser = "deck";
|
||||
# path = deploy-rs.lib.x86_64-linux.activate.home-manager self.homeConfigurations.deck;
|
||||
# user = "deck";
|
||||
# };
|
||||
# };
|
||||
deck = {
|
||||
hostname = "sdeck";
|
||||
profiles.system = {
|
||||
sshUser = "deck";
|
||||
path = deploy-rs.lib.x86_64-linux.activate.home-manager self.homeConfigurations.deck;
|
||||
user = "deck";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
609
flake.lock
generated
609
flake.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -155,9 +155,9 @@
|
||||
};
|
||||
zen-browser = {
|
||||
url = "github:0xc000022070/zen-browser-flake";
|
||||
# IMPORTANT: we're using "libgbm" and is only available in unstable so ensure
|
||||
# to have it up-to-date or simply don't specify the nixpkgs input
|
||||
# IMPORTANT: To ensure compatibility with the latest Firefox version, use nixpkgs-unstable.
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.home-manager.follows = "home-manager";
|
||||
};
|
||||
|
||||
anyrun = {
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
}: {
|
||||
sops = {
|
||||
secrets."accounts/mail/fastmail" = {};
|
||||
secrets."accounts/calendar/fastmail" = {};
|
||||
};
|
||||
accounts.email = {
|
||||
accounts = {
|
||||
email = {
|
||||
maildirBasePath = "Mail";
|
||||
accounts = {
|
||||
fastmail = rec {
|
||||
@@ -29,9 +31,6 @@
|
||||
port = 465;
|
||||
tls.enable = true;
|
||||
};
|
||||
imapnotify = {
|
||||
enable = true;
|
||||
};
|
||||
passwordCommand = ["cat" "${config.sops.secrets."accounts/mail/fastmail".path}"];
|
||||
mbsync = {
|
||||
enable = true;
|
||||
@@ -40,8 +39,27 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
programs.mbsync.enable = true;
|
||||
services.mbsync.enable = pkgs.stdenv.isLinux;
|
||||
calendar = {
|
||||
basePath = "Calendar";
|
||||
accounts = {
|
||||
fastmail = {
|
||||
remote = {
|
||||
url = "https://caldav.fastmail.com/dav/calendars/user/email@uttarayan.me";
|
||||
userName = "email@uttarayan.me";
|
||||
passwordCommand = ["cat" "${config.sops.secrets."accounts/calendar/fastmail".path}"];
|
||||
type = "caldav";
|
||||
};
|
||||
khal = {
|
||||
enable = true;
|
||||
addresses = ["email@uttarayan.me"];
|
||||
};
|
||||
vdirsyncer = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
# accounts.email.accounts.<name>.mbsync.create
|
||||
# services.mbsync.enable = true;
|
||||
}
|
||||
|
||||
9
home/apps/affine.nix
Normal file
9
home/apps/affine.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
home.packages = lib.optionals pkgs.stdenv.isLinux [
|
||||
pkgs.affine
|
||||
];
|
||||
}
|
||||
@@ -6,38 +6,41 @@
|
||||
lib.optionalAttrs device.hasGui {
|
||||
imports = [
|
||||
# ./audacity.nix
|
||||
# ./blueman.nix
|
||||
# ./bottles.nix
|
||||
./chromium.nix
|
||||
# ./cursor.nix
|
||||
./discord.nix
|
||||
./firefox.nix
|
||||
./ghostty.nix
|
||||
# ./gimp.nix
|
||||
# ./guitarix.nix
|
||||
./hyprpicker.nix
|
||||
# ./ida.nix
|
||||
# ./jellyflix.nix
|
||||
# ./kicad.nix
|
||||
./kitty.nix
|
||||
./lmstudio.nix
|
||||
./mpv.nix
|
||||
# ./lmstudio.nix
|
||||
# ./neovide.nix
|
||||
./nextcloud.nix
|
||||
./obs-studio.nix
|
||||
# ./openscad.nix
|
||||
./orcaslicer.nix
|
||||
# ./orcaslicer.nix
|
||||
# ./pcsx2.nix
|
||||
./prismlauncher.nix
|
||||
# ./prismlauncher.nix
|
||||
# ./rpcs3.nix
|
||||
./shadps4.nix
|
||||
./slack.nix
|
||||
# ./shadps4.nix
|
||||
# ./thunderbird.nix
|
||||
# ./tsukimi.nix
|
||||
# ./vial.nix
|
||||
./vicinae.nix
|
||||
./vlc.nix
|
||||
# ./vlc.nix
|
||||
# ./vscode.nix
|
||||
|
||||
./affine.nix
|
||||
./blueman.nix
|
||||
./chromium.nix
|
||||
./discord.nix
|
||||
./firefox.nix
|
||||
./ghostty.nix
|
||||
./hyprpicker.nix
|
||||
./kitty.nix
|
||||
./matrix.nix
|
||||
./mpv.nix
|
||||
./nextcloud.nix
|
||||
./obs-studio.nix
|
||||
./slack.nix
|
||||
./vicinae.nix
|
||||
./wezterm.nix
|
||||
./zathura.nix
|
||||
./zed.nix
|
||||
|
||||
12
home/apps/matrix.nix
Normal file
12
home/apps/matrix.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
device,
|
||||
...
|
||||
}: {
|
||||
home.packages = lib.optionals (device.is "ryu") [
|
||||
pkgs.fluffychat
|
||||
pkgs.fractal
|
||||
# pkgs.quaternion
|
||||
];
|
||||
}
|
||||
@@ -8,20 +8,20 @@
|
||||
loop-playlist = "inf";
|
||||
};
|
||||
profiles = {
|
||||
hdr = {
|
||||
vo = "gpu-next";
|
||||
gpu-api = "vulkan";
|
||||
hdr-compute-peak = "yes";
|
||||
hdr-peak-detect = "yes";
|
||||
target-peak = 400;
|
||||
target-prim = "bt.2020";
|
||||
target-trc = "pq";
|
||||
inverse-tone-mapping = "yes";
|
||||
tone-mapping = "spline";
|
||||
tone-mapping-mode = "auto";
|
||||
target-colorspace-hint = "auto";
|
||||
gamut-mapping = "desaturate";
|
||||
};
|
||||
# hdr = {
|
||||
# vo = "gpu-next";
|
||||
# gpu-api = "vulkan";
|
||||
# hdr-compute-peak = "yes";
|
||||
# hdr-peak-detect = "yes";
|
||||
# target-peak = 400;
|
||||
# target-prim = "bt.2020";
|
||||
# target-trc = "pq";
|
||||
# inverse-tone-mapping = "yes";
|
||||
# tone-mapping = "spline";
|
||||
# tone-mapping-mode = "auto";
|
||||
# target-colorspace-hint = "auto";
|
||||
# gamut-mapping = "desaturate";
|
||||
# };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
autoStart = true;
|
||||
};
|
||||
};
|
||||
home.packages = with pkgs; [
|
||||
pulseaudio
|
||||
home.packages = with pkgs;
|
||||
lib.optionals (device.is "ryu") [
|
||||
# pulseaudio
|
||||
playerctl
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
pkgs,
|
||||
inputs,
|
||||
device,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
@@ -10,6 +11,47 @@
|
||||
programs.zen-browser = {
|
||||
enable = device.isLinux;
|
||||
profiles.default = {
|
||||
containersForce = true;
|
||||
containers = {
|
||||
Personal = {
|
||||
color = "purple";
|
||||
icon = "fingerprint";
|
||||
id = 1;
|
||||
};
|
||||
Work = {
|
||||
color = "blue";
|
||||
icon = "briefcase";
|
||||
id = 2;
|
||||
};
|
||||
Shopping = {
|
||||
color = "yellow";
|
||||
icon = "dollar";
|
||||
id = 3;
|
||||
};
|
||||
};
|
||||
spacesForce = true;
|
||||
spaces = let
|
||||
containers = config.programs.zen-browser.profiles."default".containers;
|
||||
in {
|
||||
"Personal" = {
|
||||
id = "";
|
||||
icon = "👤";
|
||||
container = containers."Personal".id;
|
||||
position = 1000;
|
||||
};
|
||||
"Work" = {
|
||||
id = "00bdd434-e31b-4e2b-b8f5-fa7055631a64";
|
||||
icon = "💼";
|
||||
container = containers."Work".id;
|
||||
position = 2000;
|
||||
};
|
||||
"Shopping" = {
|
||||
id = "77452260-56e6-4c9e-8d5f-417958bc4fa4";
|
||||
icon = "💸";
|
||||
container = containers."Shopping".id;
|
||||
position = 3000;
|
||||
};
|
||||
};
|
||||
extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [
|
||||
privacy-badger
|
||||
violentmonkey
|
||||
@@ -42,5 +84,6 @@
|
||||
Fingerprinting = true;
|
||||
};
|
||||
};
|
||||
suppressXdgMigrationWarning = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
home-manager = {
|
||||
enable = true;
|
||||
};
|
||||
man.generateCaches = true;
|
||||
};
|
||||
|
||||
fonts.fontconfig.enable = true;
|
||||
|
||||
@@ -33,6 +33,16 @@
|
||||
name = "gpt-oss:20b";
|
||||
type = "chat";
|
||||
}
|
||||
# {
|
||||
# name = "gpt-oss:20b-instruct";
|
||||
# type = "chat";
|
||||
# real_name = "gpt-oss:20b";
|
||||
# patch = {
|
||||
# body = {
|
||||
# think = "low";
|
||||
# };
|
||||
# };
|
||||
# }
|
||||
{
|
||||
name = "qwen3:30b-a3b";
|
||||
type = "chat";
|
||||
|
||||
35
home/programs/attic.nix
Normal file
35
home/programs/attic.nix
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
attic-unwrapped = pkgs.attic-client.overrideAttrs (oldAttrs: {
|
||||
patches =
|
||||
(oldAttrs.patches or [])
|
||||
++ [
|
||||
# PR #309: Add environment variable support for login
|
||||
# https://github.com/zhaofengli/attic/pull/309
|
||||
(pkgs.fetchpatch {
|
||||
url = "https://github.com/zhaofengli/attic/pull/309.patch";
|
||||
hash = "sha256-mDoxA+e2bBZDvERp03SyYvkEdtH/bfWtZqKZv0uCS0M=";
|
||||
})
|
||||
];
|
||||
});
|
||||
in {
|
||||
sops.secrets."attic/token" = {};
|
||||
home.packages = [
|
||||
(pkgs.stdenv.mkDerivation {
|
||||
pname = "attic-client";
|
||||
version = "0.1.0";
|
||||
src = attic-unwrapped;
|
||||
buildInputs = [];
|
||||
nativeBuildInputs = [pkgs.makeWrapper];
|
||||
installPhase = ''
|
||||
install -Dm755 $src/bin/attic $out/bin/attic
|
||||
wrapProgram $out/bin/attic \
|
||||
--run "export ATTIC_LOGIN_TOKEN=\`cat -v ${config.sops.secrets."attic/token".path}\`"
|
||||
'';
|
||||
})
|
||||
];
|
||||
}
|
||||
@@ -1 +1,8 @@
|
||||
{pkgs, ...}: {home.packages = [pkgs.blobdrop];}
|
||||
{
|
||||
pkgs,
|
||||
device,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
home.packages = lib.optionals (device.name == "ryu") [pkgs.blobdrop];
|
||||
}
|
||||
|
||||
6
home/programs/calendar.nix
Normal file
6
home/programs/calendar.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{pkgs, ...}: {
|
||||
programs.khal.enable = true;
|
||||
programs.qcal.enable = true;
|
||||
programs.vdirsyncer.enable = true;
|
||||
accounts.calendar.accounts.fastmail.qcal.enable = true;
|
||||
}
|
||||
@@ -1,13 +1,8 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
device,
|
||||
...
|
||||
}: {
|
||||
{...}: {
|
||||
programs.
|
||||
carapace = {
|
||||
enable = false;
|
||||
enableFishIntegration = true;
|
||||
enableFishIntegration = false;
|
||||
enableNushellIntegration = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
device,
|
||||
cratesNix,
|
||||
...
|
||||
}:
|
||||
}: let
|
||||
cargo-credential-1password = cratesNix.buildCrate "cargo-credential-1password" {};
|
||||
in
|
||||
lib.mkIf (!device.isServer) {
|
||||
home.file.".cargo/config.toml".text =
|
||||
# toml
|
||||
@@ -11,6 +13,7 @@ lib.mkIf (!device.isServer) {
|
||||
[alias]
|
||||
lldb = ["with", "rust-lldb", "--"]
|
||||
t = ["nextest", "run"]
|
||||
pkgs = ["metadata", "--no-deps", "--format-version", "1"]
|
||||
|
||||
[net]
|
||||
git-fetch-with-cli = true
|
||||
@@ -19,9 +22,9 @@ lib.mkIf (!device.isServer) {
|
||||
index = "sparse+https://crates.darksailor.dev/api/v1/crates/"
|
||||
|
||||
[registry]
|
||||
global-credential-providers = ["cargo:token", "/etc/profiles/per-user/fs0c131y/bin/cargo-credential-1password --account my.1password.com"]
|
||||
global-credential-providers = ["cargo:token", "${lib.getExe cargo-credential-1password} --account my.1password.com"]
|
||||
'';
|
||||
home.packages = [
|
||||
(cratesNix.buildCrate "cargo-credential-1password" {})
|
||||
cargo-credential-1password
|
||||
];
|
||||
}
|
||||
|
||||
27
home/programs/cfcli.nix
Normal file
27
home/programs/cfcli.nix
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
sops.secrets."cloudflare/darksailor_dev_api_key" = {};
|
||||
home.packages = [
|
||||
# (pkgs.stdenv.mkDerivation {
|
||||
# pname = "cfcli";
|
||||
# version = "0.1.0";
|
||||
# buildInputs = [pkgs.cloudflare-cli];
|
||||
# nativeBuildInputs = [pkgs.makeWrapper];
|
||||
# installPhase = ''
|
||||
# $out/bin/cfcli \
|
||||
# --run "export CF_API_KEY=\`cat -v ${config.sops.secrets."cloudflare/darksailor_dev_api_key".path}\`"
|
||||
# '';
|
||||
# })
|
||||
(pkgs.writeShellScriptBin
|
||||
"cfcli"
|
||||
''
|
||||
#!/bin/sh
|
||||
export CF_API_KEY="$(cat -v ${config.sops.secrets."cloudflare/darksailor_dev_api_key".path})"
|
||||
exec ${pkgs.cloudflare-cli}/bin/cfcli "$@"
|
||||
'')
|
||||
];
|
||||
}
|
||||
@@ -4,22 +4,47 @@
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
# ./bluetui.nix
|
||||
# ./goread.nix
|
||||
# ./helix.nix
|
||||
# ./magika.nix
|
||||
# ./mpd.nix
|
||||
# ./mpris-scrobbler.nix
|
||||
# ./ncmpcpp.nix
|
||||
# ./newsboat.nix
|
||||
# ./nh.nix
|
||||
# ./ryujinx.nix
|
||||
# ./sxiv.nix
|
||||
# ./tea.nix
|
||||
# ./template.nix
|
||||
# ./tuifeed.nix
|
||||
# ./xh.nix
|
||||
# ./zellij.nix
|
||||
|
||||
../../modules
|
||||
|
||||
./1password-cli.nix
|
||||
./aichat.nix
|
||||
./alejandra.nix
|
||||
./aria2.nix
|
||||
./ast-grep.nix
|
||||
./attic.nix
|
||||
./atuin.nix
|
||||
./bat.nix
|
||||
./binwalk.nix
|
||||
./blobdrop.nix
|
||||
./bottom.nix
|
||||
./btop.nix
|
||||
./cachix.nix
|
||||
./calendar.nix
|
||||
./carapace.nix
|
||||
./cargo.nix
|
||||
./cfcli.nix
|
||||
./ddcbacklight.nix
|
||||
./deploy-rs.nix
|
||||
./direnv.nix
|
||||
./dust.nix
|
||||
./dysk.nix
|
||||
./eilmeldung.nix
|
||||
./eza.nix
|
||||
./fastfetch.nix
|
||||
@@ -33,15 +58,18 @@
|
||||
./himalaya.nix
|
||||
./hyprshade.nix
|
||||
./jq.nix
|
||||
./jujutsu.nix
|
||||
./just.nix
|
||||
./ncpamixer.nix
|
||||
./neomutt.nix
|
||||
./neovim.nix
|
||||
./nix-index.nix
|
||||
./nushell.nix
|
||||
./omnix.nix
|
||||
./opencode.nix
|
||||
./p7zip.nix
|
||||
./pkg-config.nix
|
||||
./retroarch.nix
|
||||
./ripgrep.nix
|
||||
./rustup.nix
|
||||
./sd.nix
|
||||
@@ -54,27 +82,6 @@
|
||||
./yazi.nix
|
||||
./yt-dlp.nix
|
||||
./zoxide.nix
|
||||
# ./bluetui.nix
|
||||
# ./goread.nix
|
||||
# ./helix.nix
|
||||
# ./magika.nix
|
||||
# ./mpd.nix
|
||||
# ./mpris-scrobbler.nix
|
||||
# ./ncmpcpp.nix
|
||||
# ./newsboat.nix
|
||||
# ./nh.nix
|
||||
# ./omnix.nix
|
||||
# ./retroarch.nix
|
||||
# ./ryujinx.nix
|
||||
# ./sxiv.nix
|
||||
# ./tea.nix
|
||||
# ./template.nix
|
||||
# ./tuifeed.nix
|
||||
# ./xh.nix
|
||||
# ./zellij.nix
|
||||
./dysk.nix
|
||||
./binwalk.nix
|
||||
./cargo.nix
|
||||
./blobdrop.nix
|
||||
./yq.nix
|
||||
];
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
''}
|
||||
'';
|
||||
};
|
||||
home.shell.enableFishIntegration = true;
|
||||
}
|
||||
// lib.optionalAttrs (!(device.is "tsuba")) {
|
||||
stylix.targets.fish.enable = false;
|
||||
|
||||
1
home/programs/jujutsu.nix
Normal file
1
home/programs/jujutsu.nix
Normal file
@@ -0,0 +1 @@
|
||||
{pkgs, ...}: {home.packages = [pkgs.jujutsu];}
|
||||
@@ -1,4 +1,9 @@
|
||||
{pkgs, ...}: {
|
||||
{pkgs, ...}: let
|
||||
theme = builtins.fetchurl {
|
||||
url = "https://raw.githubusercontent.com/catppuccin/neomutt/refs/heads/main/neomuttrc";
|
||||
sha256 = "sha256:1q086p5maqwxa4gh6z8g7h3nfavdmkbql025ibdhglpz46hsq0hs";
|
||||
};
|
||||
in {
|
||||
programs.neomutt = {
|
||||
enable = true;
|
||||
vimKeys = true;
|
||||
@@ -6,6 +11,9 @@
|
||||
sidebar = {
|
||||
enable = true;
|
||||
};
|
||||
extraConfig = ''
|
||||
source ${theme}
|
||||
'';
|
||||
};
|
||||
programs.notmuch = {
|
||||
enable = true;
|
||||
@@ -17,4 +25,38 @@
|
||||
enable = true;
|
||||
neomutt.enable = true;
|
||||
};
|
||||
services.imapnotify = {
|
||||
enable = true;
|
||||
path = [pkgs.coreutils pkgs.isync pkgs.libnotify];
|
||||
};
|
||||
accounts.email.accounts.fastmail.imapnotify = {
|
||||
enable = true;
|
||||
boxes = ["Inbox"];
|
||||
onNotify = "${pkgs.writeShellScript "mbsync-notify" ''
|
||||
${pkgs.isync}/bin/mbsync $1
|
||||
${pkgs.libnotify}/bin/notify-send "New Mail" "New email in $1"
|
||||
''} %s";
|
||||
};
|
||||
programs.mbsync.enable = true;
|
||||
services.mbsync.enable = pkgs.stdenv.isLinux;
|
||||
|
||||
# launchd.agents.mbsync = {
|
||||
# enable = true;
|
||||
# config = {
|
||||
# # A label for the service
|
||||
# Label = "dev.darksailor.atuin-daemon";
|
||||
# # The command to run
|
||||
# ProgramArguments = [
|
||||
# "${pkgs.atuin}/bin/atuin"
|
||||
# "daemon"
|
||||
# ];
|
||||
# # Run the service when you log in
|
||||
# RunAtLoad = true;
|
||||
# # Keep the process alive, or restart if it dies
|
||||
# KeepAlive = true;
|
||||
# # Log files
|
||||
# StandardOutPath = "${device.home}/Library/Logs/atuin-daemon.log";
|
||||
# StandardErrorPath = "${device.home}/Library/Logs/atuin-daemon.error.log";
|
||||
# };
|
||||
# };
|
||||
}
|
||||
|
||||
@@ -26,4 +26,5 @@
|
||||
}
|
||||
'';
|
||||
};
|
||||
home.shell.enableNushellIntegration = true;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,23 @@
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
lib.optionalAttrs (device.is "ryu") {
|
||||
lib.optionalAttrs (device.is "ryu" || device.is "kuro") {
|
||||
programs.opencode = {
|
||||
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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
}: {
|
||||
programs.ssh = {
|
||||
enable = true;
|
||||
enableDefaultConfig = false;
|
||||
matchBlocks = {
|
||||
tsuba = {
|
||||
user = "servius";
|
||||
@@ -45,13 +46,13 @@
|
||||
hostname = "steamdeck";
|
||||
forwardAgent = true;
|
||||
};
|
||||
# "*" = {
|
||||
# forwardAgent = false;
|
||||
# addKeysToAgent = "no";
|
||||
# # compression = true;
|
||||
# # HashKnownHosts = "no";
|
||||
# serverAliveInterval = 60;
|
||||
# };
|
||||
"*" = {
|
||||
forwardAgent = false;
|
||||
addKeysToAgent = "no";
|
||||
# compression = true;
|
||||
# HashKnownHosts = "no";
|
||||
serverAliveInterval = 60;
|
||||
};
|
||||
};
|
||||
extraConfig =
|
||||
lib.strings.optionalString (pkgs.stdenv.isDarwin && !device.isServer)
|
||||
|
||||
@@ -17,5 +17,6 @@
|
||||
cache_dir = config.home.homeDirectory + "/.cache/yazi/previews";
|
||||
};
|
||||
};
|
||||
shellWrapperName = "yy";
|
||||
};
|
||||
}
|
||||
|
||||
1
home/programs/yq.nix
Normal file
1
home/programs/yq.nix
Normal file
@@ -0,0 +1 @@
|
||||
{pkgs, ...}: {home.packages = [pkgs.yq];}
|
||||
@@ -61,9 +61,9 @@
|
||||
{
|
||||
output = device.monitors.secondary;
|
||||
mode = "2560x1440@170";
|
||||
position = "-1440x-1120";
|
||||
position = "-2560x0";
|
||||
scale = 1;
|
||||
transform = 1;
|
||||
transform = 0;
|
||||
}
|
||||
{
|
||||
output = device.monitors.tertiary;
|
||||
@@ -156,21 +156,20 @@
|
||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
||||
|
||||
windowrulev2 = [
|
||||
# "float, title:^(Steam)$"
|
||||
"float, title:^(Archetype.*)$"
|
||||
"float, class:(.*nextcloud.*)"
|
||||
"float, class:org.kde.kdeconnect.app"
|
||||
windowrule = [
|
||||
# "match:title ^(Steam)$ float"
|
||||
"match:title ^(Archetype.*)$ float"
|
||||
"match:class (.*nextcloud.*) float"
|
||||
"match:class org.kde.kdeconnect.app float"
|
||||
];
|
||||
|
||||
# "misc:vfr" = true;
|
||||
|
||||
env = [
|
||||
"XCURSOR_SIZE,24"
|
||||
"XDG_SESSION_TYPE,wayland"
|
||||
"MOZ_ENABLE_WAYLAND,1"
|
||||
"QT_QPA_PLATFORM,wayland"
|
||||
];
|
||||
|
||||
exec-once = [
|
||||
# "${pkgs.polkit-kde-agent}/libexec/polkit-kde-authentication-agent-1"
|
||||
"${pkgs.mate.mate-polkit}/libexec/polkit-mate-authentication-agent-1"
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
services.hyprpaper = let
|
||||
wallpapers = import ../../utils/wallhaven.nix {inherit pkgs;};
|
||||
nextcloudWallpapers = name: config.home.homeDirectory + "/Nextcloud/Wallpapers/" + name;
|
||||
silksongFleas = nextcloudWallpapers "silksong-fleas.jpg";
|
||||
# silksongFleas = nextcloudWallpapers "silksong-fleas.jpg";
|
||||
bocchiVertical = nextcloudWallpapers "bocchi-vertical.jpg";
|
||||
silksongShadeLord = nextcloudWallpapers "silksong-shadelord.jpg";
|
||||
in {
|
||||
enable = device.is "ryu";
|
||||
settings = {
|
||||
splash = false;
|
||||
wallpaper = [
|
||||
{
|
||||
monitor = device.monitors.primary;
|
||||
@@ -25,7 +27,7 @@
|
||||
}
|
||||
{
|
||||
monitor = device.monitors.tertiary;
|
||||
path = silksongFleas;
|
||||
path = bocchiVertical;
|
||||
fit_mode = "cover";
|
||||
}
|
||||
];
|
||||
|
||||
@@ -13,13 +13,14 @@
|
||||
"${device.monitors.secondary}" = {
|
||||
position = "bottom";
|
||||
start = [
|
||||
{
|
||||
type = "launcher";
|
||||
favourites = ["firefox" "discord"];
|
||||
show_names = false;
|
||||
show_icons = true;
|
||||
}
|
||||
{type = "focused";}
|
||||
{type = "tray";}
|
||||
# {
|
||||
# type = "launcher";
|
||||
# favourites = ["firefox" "discord"];
|
||||
# show_names = false;
|
||||
# show_icons = true;
|
||||
# }
|
||||
# {type = "focused";}
|
||||
];
|
||||
end = [
|
||||
{
|
||||
@@ -35,46 +36,45 @@
|
||||
{type = "clock";}
|
||||
];
|
||||
};
|
||||
"${device.monitors.primary}" = {
|
||||
position = "bottom";
|
||||
icon_theme = "Papirus-Dark";
|
||||
end = [
|
||||
{
|
||||
type = "sys_info";
|
||||
format = [
|
||||
" CPU {cpu_percent}% | {temp_c:coretemp-Package-id-0}°C"
|
||||
" RAM {memory_used}GB/{memory_total}GB"
|
||||
];
|
||||
interval = {
|
||||
cpu = 1;
|
||||
temps = 5;
|
||||
memory = 30;
|
||||
# disks= 300;
|
||||
# networks= 3;
|
||||
};
|
||||
}
|
||||
{type = "tray";}
|
||||
];
|
||||
start = [
|
||||
{
|
||||
type = "workspaces";
|
||||
name_map = {
|
||||
"1" = "icon:foot";
|
||||
"2" = "icon:code";
|
||||
"3" = "icon:firefox";
|
||||
"4" = "icon:slack";
|
||||
"5" = "icon:steam";
|
||||
"6" = "icon:foot";
|
||||
"7" = "icon:foot";
|
||||
"8" = "icon:firefox";
|
||||
"9" = "icon:discord";
|
||||
"10" = "icon:spotify";
|
||||
};
|
||||
favorites = ["1" "2" "3" "4" "5" "6" "7" "8" "9" "10"];
|
||||
all_monitors = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
# "${device.monitors.primary}" = {
|
||||
# position = "bottom";
|
||||
# icon_theme = "Papirus-Dark";
|
||||
# end = [
|
||||
# {
|
||||
# type = "sys_info";
|
||||
# format = [
|
||||
# " CPU {cpu_percent}% | {temp_c:coretemp-Package-id-0}°C"
|
||||
# " RAM {memory_used}GB/{memory_total}GB"
|
||||
# ];
|
||||
# interval = {
|
||||
# cpu = 1;
|
||||
# temps = 5;
|
||||
# memory = 30;
|
||||
# # disks= 300;
|
||||
# # networks= 3;
|
||||
# };
|
||||
# }
|
||||
# ];
|
||||
# start = [
|
||||
# {
|
||||
# type = "workspaces";
|
||||
# name_map = {
|
||||
# "1" = "icon:kitty";
|
||||
# "2" = "icon:code";
|
||||
# "3" = "icon:firefox";
|
||||
# "4" = "icon:slack";
|
||||
# # "5" = "icon:steam";
|
||||
# # "6" = "icon:foot";
|
||||
# # "7" = "icon:foot";
|
||||
# # "8" = "icon:firefox";
|
||||
# # "9" = "icon:discord";
|
||||
# # "10" = "icon:spotify";
|
||||
# };
|
||||
# favorites = ["1" "2" "3" "4"];
|
||||
# all_monitors = false;
|
||||
# }
|
||||
# ];
|
||||
# };
|
||||
"${device.monitors.tertiary}" = {
|
||||
position = "bottom";
|
||||
icon_theme = "Papirus-Dark";
|
||||
|
||||
@@ -1,7 +1,68 @@
|
||||
{device, ...}: {
|
||||
{
|
||||
device,
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
remminaDir = "${config.home.homeDirectory}/.local/share/remmina";
|
||||
applicationsDir = "${config.home.homeDirectory}/.local/share/applications";
|
||||
|
||||
# Script to generate desktop entries for Remmina connections
|
||||
generateRemminaDesktopEntries = pkgs.writeShellScript "generate-remmina-desktop-entries" ''
|
||||
REMMINA_DIR="${remminaDir}"
|
||||
APPS_DIR="${applicationsDir}"
|
||||
|
||||
# Create applications directory if it doesn't exist
|
||||
mkdir -p "$APPS_DIR"
|
||||
|
||||
# Remove old remmina desktop entries
|
||||
rm -f "$APPS_DIR"/remmina-*.desktop
|
||||
|
||||
# Exit if remmina directory doesn't exist
|
||||
[[ ! -d "$REMMINA_DIR" ]] && exit 0
|
||||
|
||||
# Generate desktop entries for each .remmina file
|
||||
find "$REMMINA_DIR" -name "*.remmina" -type f | while read -r file; do
|
||||
# Extract connection details
|
||||
name=$(${pkgs.gnugrep}/bin/grep "^name=" "$file" | ${pkgs.coreutils}/bin/cut -d'=' -f2-)
|
||||
server=$(${pkgs.gnugrep}/bin/grep "^server=" "$file" | ${pkgs.coreutils}/bin/cut -d'=' -f2-)
|
||||
protocol=$(${pkgs.gnugrep}/bin/grep "^protocol=" "$file" | ${pkgs.coreutils}/bin/cut -d'=' -f2-)
|
||||
|
||||
# Use filename as fallback if name is empty
|
||||
[[ -z "$name" ]] && name=$(${pkgs.coreutils}/bin/basename "$file" .remmina)
|
||||
[[ -z "$protocol" ]] && protocol="Unknown"
|
||||
|
||||
# Generate desktop entry filename
|
||||
desktop_name=$(${pkgs.coreutils}/bin/basename "$file" .remmina | ${pkgs.gnused}/bin/sed 's/[^a-zA-Z0-9_-]/-/g')
|
||||
desktop_file="$APPS_DIR/remmina-$desktop_name.desktop"
|
||||
|
||||
# Create desktop entry
|
||||
cat > "$desktop_file" <<EOF
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Remmina - $name
|
||||
GenericName=$protocol Connection to $server
|
||||
Comment=Connect to $server via $protocol
|
||||
Exec=${pkgs.remmina}/bin/remmina -c "$file"
|
||||
Icon=org.remmina.Remmina
|
||||
Terminal=false
|
||||
Categories=Network;RemoteAccess;
|
||||
EOF
|
||||
done
|
||||
'';
|
||||
in {
|
||||
services.remmina = {
|
||||
enable = device.is "ryu";
|
||||
systemdService.enable = true;
|
||||
addRdpMimeTypeAssoc = true;
|
||||
};
|
||||
|
||||
# Activation script to generate desktop entries
|
||||
home.activation.generateRemminaDesktopEntries = mkIf (device.is "ryu") (
|
||||
lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||
run ${generateRemminaDesktopEntries}
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,28 +5,28 @@
|
||||
...
|
||||
}:
|
||||
lib.mkIf (device.is "ryu") {
|
||||
# systemd.user.services.wallpaperengine = {
|
||||
# Unit = {
|
||||
# Description = "Linux Wallpaper Engine";
|
||||
# After = ["hyprland-session.target"];
|
||||
# Wants = ["hyprland-session.target"];
|
||||
# PartOf = ["hyprland-session.target"];
|
||||
# };
|
||||
#
|
||||
# Service = {
|
||||
# Environment = [
|
||||
# "XDG_SESSION_TYPE=wayland"
|
||||
# ];
|
||||
# Type = "simple";
|
||||
# ExecStartPre = "${pkgs.coreutils}/bin/sleep 3";
|
||||
# ExecStart = "${pkgs.linux-wallpaperengine}/bin/linux-wallpaperengine --silent --no-audio-processing -f 15 --scaling fill --screen-root HDMI-A-1 --bg 2780316434";
|
||||
# Restart = "on-failure";
|
||||
# RestartSec = 5;
|
||||
# TimeoutStartSec = 30;
|
||||
# };
|
||||
#
|
||||
# Install = {
|
||||
# WantedBy = ["hyprland-session.target"];
|
||||
# };
|
||||
# };
|
||||
systemd.user.services.wallpaperengine = {
|
||||
Unit = {
|
||||
Description = "Linux Wallpaper Engine";
|
||||
After = ["hyprland-session.target"];
|
||||
Wants = ["hyprland-session.target"];
|
||||
PartOf = ["hyprland-session.target"];
|
||||
};
|
||||
|
||||
Service = {
|
||||
Environment = [
|
||||
"XDG_SESSION_TYPE=wayland"
|
||||
];
|
||||
Type = "simple";
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/sleep 3";
|
||||
ExecStart = "${pkgs.linux-wallpaperengine}/bin/linux-wallpaperengine --silent --no-audio-processing -f 15 --scaling fill --screen-root HDMI-A-1 --bg 2780316434";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 5;
|
||||
TimeoutStartSec = 30;
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = ["hyprland-session.target"];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
2
justfile
2
justfile
@@ -41,3 +41,5 @@ add program:
|
||||
alejandra fmt home/programs/{{program}}.nix home/programs/default.nix
|
||||
git add home/programs/{{program}}.nix
|
||||
|
||||
# add-secret secret:
|
||||
# openssl rand -hex 32 | tr -d '\n' | jq -sR | sops set --value-stdin secrets/secrets.yaml {{secret}}
|
||||
|
||||
162
modules/nixos/affine.nix
Normal file
162
modules/nixos/affine.nix
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
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 = [
|
||||
"--health-cmd=pg_isready -U ${dbUser} -d ${dbName}"
|
||||
"--health-interval=10s"
|
||||
"--health-timeout=5s"
|
||||
"--health-retries=5"
|
||||
];
|
||||
networks = ["affine-net"];
|
||||
};
|
||||
|
||||
affine-redis = {
|
||||
image = "redis:7";
|
||||
volumes = [
|
||||
"${cfg.dataDir}/redis:/data"
|
||||
];
|
||||
networks = ["affine-net"];
|
||||
extraOptions = [
|
||||
"--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;
|
||||
networks = ["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;
|
||||
networks = ["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"];
|
||||
};
|
||||
}
|
||||
@@ -1,480 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.services.caddy;
|
||||
|
||||
certs = config.security.acme.certs;
|
||||
virtualHosts = attrValues cfg.virtualHosts;
|
||||
acmeEnabledVhosts = filter (hostOpts: hostOpts.useACMEHost != null) virtualHosts;
|
||||
vhostCertNames = unique (map (hostOpts: hostOpts.useACMEHost) acmeEnabledVhosts);
|
||||
dependentCertNames = filter (cert: certs.${cert}.dnsProvider == null) vhostCertNames; # those that might depend on the HTTP server
|
||||
independentCertNames = filter (cert: certs.${cert}.dnsProvider != null) vhostCertNames; # those that don't depend on the HTTP server
|
||||
|
||||
mkVHostConf = hostOpts: let
|
||||
sslCertDir = config.security.acme.certs.${hostOpts.useACMEHost}.directory;
|
||||
in ''
|
||||
${hostOpts.hostName} ${concatStringsSep " " hostOpts.serverAliases} {
|
||||
${optionalString (
|
||||
hostOpts.listenAddresses != []
|
||||
) "bind ${concatStringsSep " " hostOpts.listenAddresses}"}
|
||||
${optionalString (
|
||||
hostOpts.useACMEHost != null
|
||||
) "tls ${sslCertDir}/cert.pem ${sslCertDir}/key.pem"}
|
||||
log {
|
||||
${hostOpts.logFormat}
|
||||
}
|
||||
|
||||
${hostOpts.extraConfig}
|
||||
}
|
||||
'';
|
||||
|
||||
settingsFormat = pkgs.formats.json {};
|
||||
|
||||
configFile =
|
||||
if cfg.settings != {}
|
||||
then settingsFormat.generate "caddy.json" cfg.settings
|
||||
else let
|
||||
Caddyfile = pkgs.writeTextDir "Caddyfile" ''
|
||||
{
|
||||
${cfg.globalConfig}
|
||||
}
|
||||
${cfg.extraConfig}
|
||||
${concatMapStringsSep "\n" mkVHostConf virtualHosts}
|
||||
'';
|
||||
|
||||
Caddyfile-formatted = pkgs.runCommand "Caddyfile-formatted" {} ''
|
||||
mkdir -p $out
|
||||
cp --no-preserve=mode ${Caddyfile}/Caddyfile $out/Caddyfile
|
||||
${lib.getExe cfg.package} fmt --overwrite $out/Caddyfile
|
||||
'';
|
||||
in "${
|
||||
if pkgs.stdenv.buildPlatform == pkgs.stdenv.hostPlatform
|
||||
then Caddyfile-formatted
|
||||
else Caddyfile
|
||||
}/Caddyfile";
|
||||
|
||||
etcConfigFile = "caddy/caddy_config";
|
||||
|
||||
configPath = "/etc/${etcConfigFile}";
|
||||
|
||||
mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix lib;
|
||||
in {
|
||||
imports = [
|
||||
(mkRemovedOptionModule [
|
||||
"services"
|
||||
"caddy"
|
||||
"agree"
|
||||
] "this option is no longer necessary for Caddy 2")
|
||||
(mkRenamedOptionModule ["services" "caddy" "ca"] ["services" "caddy" "acmeCA"])
|
||||
(mkRenamedOptionModule ["services" "caddy" "config"] ["services" "caddy" "extraConfig"])
|
||||
];
|
||||
|
||||
# interface
|
||||
options.services.caddy = {
|
||||
enable = mkEnableOption "Caddy web server";
|
||||
|
||||
user = mkOption {
|
||||
default = "caddy";
|
||||
type = types.str;
|
||||
description = ''
|
||||
User account under which caddy runs.
|
||||
|
||||
::: {.note}
|
||||
If left as the default value this user will automatically be created
|
||||
on system activation, otherwise you are responsible for
|
||||
ensuring the user exists before the Caddy service starts.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
default = "caddy";
|
||||
type = types.str;
|
||||
description = ''
|
||||
Group under which caddy runs.
|
||||
|
||||
::: {.note}
|
||||
If left as the default value this group will automatically be created
|
||||
on system activation, otherwise you are responsible for
|
||||
ensuring the group exists before the Caddy service starts.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkPackageOption pkgs "caddy" {};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/caddy";
|
||||
description = ''
|
||||
The data directory for caddy.
|
||||
|
||||
::: {.note}
|
||||
If left as the default value this directory will automatically be created
|
||||
before the Caddy server starts, otherwise you are responsible for ensuring
|
||||
the directory exists with appropriate ownership and permissions.
|
||||
|
||||
Caddy v2 replaced `CADDYPATH` with XDG directories.
|
||||
See <https://caddyserver.com/docs/conventions#file-locations>.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
logDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/log/caddy";
|
||||
description = ''
|
||||
Directory for storing Caddy access logs.
|
||||
|
||||
::: {.note}
|
||||
If left as the default value this directory will automatically be created
|
||||
before the Caddy server starts, otherwise the sysadmin is responsible for
|
||||
ensuring the directory exists with appropriate ownership and permissions.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
logFormat = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
level ERROR
|
||||
'';
|
||||
example = literalExpression ''
|
||||
mkForce "level INFO";
|
||||
'';
|
||||
description = ''
|
||||
Configuration for the default logger. See
|
||||
<https://caddyserver.com/docs/caddyfile/options#log>
|
||||
for details.
|
||||
'';
|
||||
};
|
||||
|
||||
configFile = mkOption {
|
||||
type = types.path;
|
||||
default = configFile;
|
||||
defaultText = "A Caddyfile automatically generated by values from services.caddy.*";
|
||||
example = literalExpression ''
|
||||
pkgs.writeText "Caddyfile" '''
|
||||
example.com
|
||||
|
||||
root * /var/www/wordpress
|
||||
php_fastcgi unix//run/php/php-version-fpm.sock
|
||||
file_server
|
||||
''';
|
||||
'';
|
||||
description = ''
|
||||
Override the configuration file used by Caddy. By default,
|
||||
NixOS generates one automatically.
|
||||
|
||||
The configuration file is exposed at {file}`${configPath}`.
|
||||
'';
|
||||
};
|
||||
|
||||
adapter = mkOption {
|
||||
default =
|
||||
if ((cfg.configFile != configFile) || (builtins.baseNameOf cfg.configFile) == "Caddyfile")
|
||||
then "caddyfile"
|
||||
else null;
|
||||
defaultText = literalExpression ''
|
||||
if ((cfg.configFile != configFile) || (builtins.baseNameOf cfg.configFile) == "Caddyfile") then "caddyfile" else null
|
||||
'';
|
||||
example = literalExpression "nginx";
|
||||
type = with types; nullOr str;
|
||||
description = ''
|
||||
Name of the config adapter to use.
|
||||
See <https://caddyserver.com/docs/config-adapters>
|
||||
for the full list.
|
||||
|
||||
If `null` is specified, the `--adapter` argument is omitted when
|
||||
starting or restarting Caddy. Notably, this allows specification of a
|
||||
configuration file in Caddy's native JSON format, as long as the
|
||||
filename does not start with `Caddyfile` (in which case the `caddyfile`
|
||||
adapter is implicitly enabled). See
|
||||
<https://caddyserver.com/docs/command-line#caddy-run> for details.
|
||||
|
||||
::: {.note}
|
||||
Any value other than `null` or `caddyfile` is only valid when providing
|
||||
your own `configFile`.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
resume = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Use saved config, if any (and prefer over any specified configuration passed with `--config`).
|
||||
'';
|
||||
};
|
||||
|
||||
globalConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
debug
|
||||
servers {
|
||||
protocol {
|
||||
experimental_http3
|
||||
}
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Additional lines of configuration appended to the global config section
|
||||
of the `Caddyfile`.
|
||||
|
||||
Refer to <https://caddyserver.com/docs/caddyfile/options#global-options>
|
||||
for details on supported values.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
example.com {
|
||||
encode gzip
|
||||
log
|
||||
root /srv/http
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Additional lines of configuration appended to the automatically
|
||||
generated `Caddyfile`.
|
||||
'';
|
||||
};
|
||||
|
||||
virtualHosts = mkOption {
|
||||
type = with types; attrsOf (submodule (import ./vhost-options.nix {inherit cfg;}));
|
||||
default = {};
|
||||
example = literalExpression ''
|
||||
{
|
||||
"hydra.example.com" = {
|
||||
serverAliases = [ "www.hydra.example.com" ];
|
||||
extraConfig = '''
|
||||
encode gzip
|
||||
root * /srv/http
|
||||
''';
|
||||
};
|
||||
};
|
||||
'';
|
||||
description = ''
|
||||
Declarative specification of virtual hosts served by Caddy.
|
||||
'';
|
||||
};
|
||||
|
||||
acmeCA = mkOption {
|
||||
default = null;
|
||||
example = "https://acme-v02.api.letsencrypt.org/directory";
|
||||
type = with types; nullOr str;
|
||||
description = ''
|
||||
::: {.note}
|
||||
Sets the [`acme_ca` option](https://caddyserver.com/docs/caddyfile/options#acme-ca)
|
||||
in the global options block of the resulting Caddyfile.
|
||||
:::
|
||||
|
||||
The URL to the ACME CA's directory. It is strongly recommended to set
|
||||
this to `https://acme-staging-v02.api.letsencrypt.org/directory` for
|
||||
Let's Encrypt's [staging endpoint](https://letsencrypt.org/docs/staging-environment/)
|
||||
while testing or in development.
|
||||
|
||||
Value `null` should be prefered for production setups,
|
||||
as it omits the `acme_ca` option to enable
|
||||
[automatic issuer fallback](https://caddyserver.com/docs/automatic-https#issuer-fallback).
|
||||
'';
|
||||
};
|
||||
|
||||
email = mkOption {
|
||||
default = null;
|
||||
type = with types; nullOr str;
|
||||
description = ''
|
||||
Your email address. Mainly used when creating an ACME account with your
|
||||
CA, and is highly recommended in case there are problems with your
|
||||
certificates.
|
||||
'';
|
||||
};
|
||||
|
||||
enableReload = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Reload Caddy instead of restarting it when configuration file changes.
|
||||
|
||||
Note that enabling this option requires the [admin API](https://caddyserver.com/docs/caddyfile/options#admin)
|
||||
to not be turned off.
|
||||
|
||||
If you enable this option, consider setting [`grace_period`](https://caddyserver.com/docs/caddyfile/options#grace-period)
|
||||
to a non-infinite value in {option}`services.caddy.globalConfig`
|
||||
to prevent Caddy waiting for active connections to finish,
|
||||
which could delay the reload essentially indefinitely.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = settingsFormat.type;
|
||||
default = {};
|
||||
description = ''
|
||||
Structured configuration for Caddy to generate a Caddy JSON configuration file.
|
||||
See <https://caddyserver.com/docs/json/> for available options.
|
||||
|
||||
::: {.warning}
|
||||
Using a [Caddyfile](https://caddyserver.com/docs/caddyfile) instead of a JSON config is highly recommended by upstream.
|
||||
There are only very few exception to this.
|
||||
|
||||
Please use a Caddyfile via {option}`services.caddy.configFile`, {option}`services.caddy.virtualHosts` or
|
||||
{option}`services.caddy.extraConfig` with {option}`services.caddy.globalConfig` instead.
|
||||
:::
|
||||
|
||||
::: {.note}
|
||||
Takes presence over most `services.caddy.*` options, such as {option}`services.caddy.configFile` and {option}`services.caddy.virtualHosts`, if specified.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
environmentFile = mkOption {
|
||||
type = with types; nullOr path;
|
||||
default = null;
|
||||
example = "/run/secrets/caddy.env";
|
||||
description = ''
|
||||
Environment file as defined in {manpage}`systemd.exec(5)`.
|
||||
|
||||
You can use environment variables to pass secrets to the service without adding
|
||||
them to the world-redable nix store.
|
||||
|
||||
```
|
||||
# in configuration.nix
|
||||
services.caddy.environmentFile = "/run/secrets/caddy.env";
|
||||
services.caddy.globalConfig = '''
|
||||
{
|
||||
acme_ca https://acme.zerossl.com/v2/DV90
|
||||
acme_eab {
|
||||
key_id {$EAB_KEY_ID}
|
||||
mac_key {$EAB_MAC_KEY}
|
||||
}
|
||||
}
|
||||
''';
|
||||
```
|
||||
|
||||
```
|
||||
# in /run/secrets/caddy.env
|
||||
EAB_KEY_ID=secret
|
||||
EAB_MAC_KEY=secret
|
||||
```
|
||||
|
||||
Find more examples
|
||||
[here](https://caddyserver.com/docs/caddyfile/concepts#environment-variables)
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# implementation
|
||||
config = mkIf cfg.enable {
|
||||
assertions =
|
||||
[
|
||||
{
|
||||
assertion = cfg.configFile == configFile -> cfg.adapter == "caddyfile" || cfg.adapter == null;
|
||||
message = "To specify an adapter other than 'caddyfile' please provide your own configuration via `services.caddy.configFile`";
|
||||
}
|
||||
]
|
||||
++ map (
|
||||
name:
|
||||
mkCertOwnershipAssertion {
|
||||
cert = config.security.acme.certs.${name};
|
||||
groups = config.users.groups;
|
||||
services = [config.systemd.services.caddy];
|
||||
}
|
||||
)
|
||||
vhostCertNames;
|
||||
|
||||
services.caddy.globalConfig = ''
|
||||
${optionalString (cfg.email != null) "email ${cfg.email}"}
|
||||
${optionalString (cfg.acmeCA != null) "acme_ca ${cfg.acmeCA}"}
|
||||
log {
|
||||
${cfg.logFormat}
|
||||
}
|
||||
'';
|
||||
|
||||
# https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes
|
||||
boot.kernel.sysctl."net.core.rmem_max" = mkDefault 2500000;
|
||||
boot.kernel.sysctl."net.core.wmem_max" = mkDefault 2500000;
|
||||
|
||||
systemd.packages = [cfg.package];
|
||||
systemd.services.caddy = {
|
||||
wants = map (certName: "acme-finished-${certName}.target") vhostCertNames;
|
||||
after =
|
||||
map (certName: "acme-selfsigned-${certName}.service") vhostCertNames
|
||||
++ map (certName: "acme-${certName}.service") independentCertNames; # avoid loading self-signed key w/ real cert, or vice-versa
|
||||
before = map (certName: "acme-${certName}.service") dependentCertNames;
|
||||
|
||||
wantedBy = ["multi-user.target"];
|
||||
startLimitIntervalSec = 14400;
|
||||
startLimitBurst = 10;
|
||||
reloadTriggers = optional cfg.enableReload cfg.configFile;
|
||||
restartTriggers = optional (!cfg.enableReload) cfg.configFile;
|
||||
|
||||
serviceConfig = let
|
||||
runOptions = ''--config ${configPath} ${
|
||||
optionalString (cfg.adapter != null) "--adapter ${cfg.adapter}"
|
||||
}'';
|
||||
in {
|
||||
# Override the `ExecStart` line from upstream's systemd unit file by our own:
|
||||
# https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
|
||||
# If the empty string is assigned to this option, the list of commands to start is reset, prior assignments of this option will have no effect.
|
||||
ExecStart = [
|
||||
""
|
||||
''${lib.getExe cfg.package} run ${runOptions} ${optionalString cfg.resume "--resume"}''
|
||||
];
|
||||
# Validating the configuration before applying it ensures we’ll get a proper error that will be reported when switching to the configuration
|
||||
ExecReload =
|
||||
[
|
||||
""
|
||||
]
|
||||
++ lib.optional cfg.enableReload "${lib.getExe cfg.package} reload ${runOptions} --force";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
ReadWritePaths = [cfg.dataDir];
|
||||
StateDirectory = mkIf (cfg.dataDir == "/var/lib/caddy") ["caddy"];
|
||||
LogsDirectory = mkIf (cfg.logDir == "/var/log/caddy") ["caddy"];
|
||||
Restart = "on-failure";
|
||||
RestartPreventExitStatus = 1;
|
||||
RestartSec = "5s";
|
||||
EnvironmentFile = optional (cfg.environmentFile != null) cfg.environmentFile;
|
||||
|
||||
# TODO: attempt to upstream these options
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
ProtectHome = true;
|
||||
};
|
||||
};
|
||||
|
||||
users.users = optionalAttrs (cfg.user == "caddy") {
|
||||
caddy = {
|
||||
group = cfg.group;
|
||||
uid = config.ids.uids.caddy;
|
||||
home = cfg.dataDir;
|
||||
};
|
||||
};
|
||||
|
||||
users.groups = optionalAttrs (cfg.group == "caddy") {
|
||||
caddy.gid = config.ids.gids.caddy;
|
||||
};
|
||||
|
||||
security.acme.certs = let
|
||||
certCfg =
|
||||
map (
|
||||
certName:
|
||||
nameValuePair certName {
|
||||
group = mkDefault cfg.group;
|
||||
reloadServices = ["caddy.service"];
|
||||
}
|
||||
)
|
||||
vhostCertNames;
|
||||
in
|
||||
listToAttrs certCfg;
|
||||
|
||||
environment.etc.${etcConfigFile}.source = cfg.configFile;
|
||||
};
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
{cfg}: {
|
||||
config,
|
||||
lib,
|
||||
name,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) literalExpression mkOption types;
|
||||
in {
|
||||
options = {
|
||||
hostName = mkOption {
|
||||
type = types.str;
|
||||
default = name;
|
||||
description = "Canonical hostname for the server.";
|
||||
};
|
||||
|
||||
serverAliases = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [];
|
||||
example = [
|
||||
"www.example.org"
|
||||
"example.org"
|
||||
];
|
||||
description = ''
|
||||
Additional names of virtual hosts served by this virtual host configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
listenAddresses = mkOption {
|
||||
type = with types; listOf str;
|
||||
description = ''
|
||||
A list of host interfaces to bind to for this virtual host.
|
||||
'';
|
||||
default = [];
|
||||
example = [
|
||||
"127.0.0.1"
|
||||
"::1"
|
||||
];
|
||||
};
|
||||
|
||||
useACMEHost = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
A host of an existing Let's Encrypt certificate to use.
|
||||
This is mostly useful if you use DNS challenges but Caddy does not
|
||||
currently support your provider.
|
||||
|
||||
*Note that this option does not create any certificates, nor
|
||||
does it add subdomains to existing ones – you will need to create them
|
||||
manually using [](#opt-security.acme.certs).*
|
||||
'';
|
||||
};
|
||||
|
||||
logFormat = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
output file ${cfg.logDir}/access-${lib.replaceStrings ["/" " "] ["_" "_"] config.hostName}.log
|
||||
'';
|
||||
defaultText = ''
|
||||
output file ''${config.services.caddy.logDir}/access-''${hostName}.log
|
||||
'';
|
||||
example = literalExpression ''
|
||||
mkForce '''
|
||||
output discard
|
||||
''';
|
||||
'';
|
||||
description = ''
|
||||
Configuration for HTTP request logging (also known as access logs). See
|
||||
<https://caddyserver.com/docs/caddyfile/directives/log#log>
|
||||
for details.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Additional lines of configuration appended to this virtual host in the
|
||||
automatically generated `Caddyfile`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
50
modules/nixos/substituters.nix
Normal file
50
modules/nixos/substituters.nix
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.nix.substituters;
|
||||
in {
|
||||
options.nix.substituters = {
|
||||
enableCuda = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable NixOS CUDA cache";
|
||||
};
|
||||
|
||||
enableLlamaCpp = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable llama-cpp cache";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
nix.settings = {
|
||||
trusted-substituters =
|
||||
[
|
||||
"https://nix-community.cachix.org"
|
||||
"https://nixos-raspberrypi.cachix.org"
|
||||
]
|
||||
++ optionals cfg.enableLlamaCpp [
|
||||
"https://llama-cpp.cachix.org"
|
||||
]
|
||||
++ optionals cfg.enableCuda [
|
||||
"https://cache.nixos-cuda.org"
|
||||
];
|
||||
|
||||
trusted-public-keys =
|
||||
[
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
"nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
|
||||
]
|
||||
++ optionals cfg.enableLlamaCpp [
|
||||
"llama-cpp.cachix.org-1:H75X+w83wUKTIPSO1KWy9ADUrzThyGs8P5tmAbkWhQc="
|
||||
]
|
||||
++ optionals cfg.enableCuda [
|
||||
"cache.nixos-cuda.org:74DUi4Ye579gUqzH4ziL9IyiJBlDpMRn9MBN8oNan9M="
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
};
|
||||
in {
|
||||
opts = {
|
||||
autoread = true;
|
||||
completeopt = "menu,menuone,popup,noselect";
|
||||
expandtab = true;
|
||||
foldenable = true;
|
||||
@@ -106,7 +107,7 @@ in {
|
||||
"<C-q>x" = "[[<cmd>tabclose<cr>]]";
|
||||
"<C-q>n" = "[[<cmd>tabnext<cr>]]";
|
||||
"<C-q>p" = "[[<cmd>tabprevious<cr>]]";
|
||||
"<c-.>" = "require('sidekick.cli').toggle";
|
||||
"<C-.>" = "require('opencode').toggle";
|
||||
};
|
||||
terminal = {
|
||||
"<C-\\>" = "require('FTerm').toggle";
|
||||
@@ -177,16 +178,19 @@ in {
|
||||
trouble.enable = true;
|
||||
ts-context-commentstring.enable = true;
|
||||
which-key.enable = true;
|
||||
|
||||
sidekick = {
|
||||
opencode = {
|
||||
enable = true;
|
||||
settings = {
|
||||
nes = {
|
||||
enabled = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# sidekick = {
|
||||
# enable = true;
|
||||
# settings = {
|
||||
# nes = {
|
||||
# enabled = false;
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
|
||||
conform-nvim = {
|
||||
enable = true;
|
||||
settings = {
|
||||
@@ -616,6 +620,21 @@ in {
|
||||
};
|
||||
sources = {
|
||||
cmdline = [];
|
||||
# default =
|
||||
# rawLua
|
||||
# /*
|
||||
# lua
|
||||
# */
|
||||
# ''
|
||||
# function(ctx)
|
||||
# local success, node = pcall(vim.treesitter.get_node)
|
||||
# if success and node and vim.tbl_contains({ 'comment', 'line_comment', 'block_comment' }, node:type()) then
|
||||
# return { 'buffer' }
|
||||
# else
|
||||
# return { 'git', 'lsp', 'path', 'snippets', 'buffer', 'dictionary', 'ripgrep', 'tmux' }
|
||||
# end
|
||||
# end
|
||||
# '';
|
||||
default = [
|
||||
"git"
|
||||
"lsp"
|
||||
@@ -624,6 +643,7 @@ in {
|
||||
"path"
|
||||
"buffer"
|
||||
"ripgrep"
|
||||
# "tmux"
|
||||
];
|
||||
providers = {
|
||||
buffer = {
|
||||
@@ -635,23 +655,30 @@ in {
|
||||
path = {};
|
||||
dictionary = {
|
||||
module = "blink-cmp-dictionary";
|
||||
name = "Dict";
|
||||
name = "dict";
|
||||
min_keyword_length = 3;
|
||||
opts = {
|
||||
};
|
||||
};
|
||||
git = {
|
||||
module = "blink-cmp-git";
|
||||
name = "Git";
|
||||
name = "git";
|
||||
opts = {
|
||||
# -- options for the blink-cmp-git
|
||||
};
|
||||
};
|
||||
ripgrep = {
|
||||
module = "blink-ripgrep";
|
||||
name = "Ripgrep";
|
||||
name = "ripgrep";
|
||||
opts = {};
|
||||
};
|
||||
# tmux = {
|
||||
# module = "blink-cmp-tmux";
|
||||
# name = "tmux";
|
||||
# opts = {
|
||||
# triggered_only = false;
|
||||
# };
|
||||
# };
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -661,6 +688,7 @@ in {
|
||||
blink-cmp-dictionary.enable = true;
|
||||
blink-cmp-copilot.enable = true;
|
||||
blink-cmp-spell.enable = true;
|
||||
blink-cmp-tmux.enable = true;
|
||||
blink-compat = {
|
||||
enable = true;
|
||||
settings.impersonate_nvim_cmp = true;
|
||||
@@ -857,5 +885,6 @@ in {
|
||||
pkgs.lua
|
||||
pkgs.ripgrep
|
||||
pkgs.nodejs-slim
|
||||
pkgs.lsof
|
||||
];
|
||||
}
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
documentation.dev.enable = true;
|
||||
documentation.doc.enable = true;
|
||||
documentation.nixos.enable = true;
|
||||
documentation.man.generateCaches = true;
|
||||
}
|
||||
|
||||
@@ -7,5 +7,11 @@
|
||||
# ./alvr.nix
|
||||
./easyeffects.nix
|
||||
./vr.nix
|
||||
./helvum.nix
|
||||
# ./wine.nix
|
||||
# ./virt.nix
|
||||
./gparted.nix
|
||||
./nvtop.nix
|
||||
# ./qpwgraph.nix
|
||||
];
|
||||
}
|
||||
|
||||
3
nixos/ryu/apps/gparted.nix
Normal file
3
nixos/ryu/apps/gparted.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [gparted];
|
||||
}
|
||||
3
nixos/ryu/apps/helvum.nix
Normal file
3
nixos/ryu/apps/helvum.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [helvum];
|
||||
}
|
||||
3
nixos/ryu/apps/nvtop.nix
Normal file
3
nixos/ryu/apps/nvtop.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [nvtopPackages.nvidia];
|
||||
}
|
||||
3
nixos/ryu/apps/qpwgraph.nix
Normal file
3
nixos/ryu/apps/qpwgraph.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [qpwgraph];
|
||||
}
|
||||
6
nixos/ryu/apps/virt.nix
Normal file
6
nixos/ryu/apps/virt.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
virt-manager
|
||||
quickemu
|
||||
];
|
||||
}
|
||||
7
nixos/ryu/apps/wine.nix
Normal file
7
nixos/ryu/apps/wine.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
wine-wayland
|
||||
winetricks
|
||||
wineWowPackages.waylandFull
|
||||
];
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
pkgs,
|
||||
lib,
|
||||
device,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
@@ -12,6 +13,7 @@
|
||||
./apps
|
||||
./vms
|
||||
./games
|
||||
../../modules/nixos/substituters.nix
|
||||
];
|
||||
|
||||
security.tpm2 = {
|
||||
@@ -46,18 +48,7 @@
|
||||
auto-optimise-store = true;
|
||||
extra-experimental-features = "nix-command flakes auto-allocate-uids";
|
||||
trusted-users = [device.user];
|
||||
trusted-substituters = [
|
||||
"https://nix-community.cachix.org"
|
||||
"https://nixos-raspberrypi.cachix.org"
|
||||
"https://llama-cpp.cachix.org"
|
||||
"https://cuda-maintainers.cachix.org"
|
||||
];
|
||||
trusted-public-keys = [
|
||||
"cuda-maintainers.cachix.org-1:0dq3bujKpuEPMCX6U4WylrUDZ9JyUG0VpVZa7CNfq5E="
|
||||
"llama-cpp.cachix.org-1:H75X+w83wUKTIPSO1KWy9ADUrzThyGs8P5tmAbkWhQc="
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
"nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
|
||||
];
|
||||
extra-sandbox-paths = [config.programs.ccache.cacheDir];
|
||||
};
|
||||
extraOptions = ''
|
||||
build-users-group = nixbld
|
||||
@@ -76,12 +67,17 @@
|
||||
# ../../builders/tsuba.nix
|
||||
];
|
||||
distributedBuilds = true;
|
||||
# Enable CUDA and llama-cpp caches
|
||||
substituters = {
|
||||
enableCuda = true;
|
||||
enableLlamaCpp = true;
|
||||
};
|
||||
};
|
||||
|
||||
users.users.${device.user} = {
|
||||
uid = device.uid;
|
||||
isNormalUser = true;
|
||||
extraGroups = ["wheel" "audio" "i2c" "media" "video" "tss"];
|
||||
extraGroups = ["wheel" "audio" "i2c" "media" "video" "tss" "plugdev"];
|
||||
openssh.authorizedKeys.keyFiles = [
|
||||
../../secrets/id_ed25519.pub
|
||||
../../secrets/id_ios.pub
|
||||
@@ -111,12 +107,6 @@
|
||||
};
|
||||
displayManager.gdm.enable = true;
|
||||
# desktopManager.gnome.enable = true;
|
||||
pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
pulse.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
boot = {
|
||||
@@ -169,12 +159,31 @@
|
||||
Name = "Ryu";
|
||||
Enable = "Source,Sink,Media,Socket";
|
||||
ControllerMode = "dual";
|
||||
FactConnectable = "true";
|
||||
Experimental = "true";
|
||||
FactConnectable = true;
|
||||
Experimental = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
boot.extraModprobeConfig = ''
|
||||
# Keep Bluetooth coexistence disabled for better BT audio stability
|
||||
options iwlwifi bt_coex_active=0
|
||||
|
||||
# Enable software crypto (helps BT coexistence sometimes)
|
||||
options iwlwifi swcrypto=1
|
||||
|
||||
# Disable power saving on Wi-Fi module to reduce radio state changes that might disrupt BT
|
||||
options iwlwifi power_save=0
|
||||
|
||||
# Disable Unscheduled Automatic Power Save Delivery (U-APSD) to improve BT audio stability
|
||||
options iwlwifi uapsd_disable=1
|
||||
|
||||
# Disable D0i3 power state to avoid problematic power transitions
|
||||
options iwlwifi d0i3_disable=1
|
||||
|
||||
# Set power scheme for performance (iwlmvm)
|
||||
options iwlmvm power_scheme=1
|
||||
'';
|
||||
|
||||
networking = {
|
||||
interfaces.eno1.wakeOnLan = {
|
||||
@@ -284,41 +293,6 @@
|
||||
fonts.fontconfig.enable = true;
|
||||
fonts.fontDir.enable = true;
|
||||
environment = {
|
||||
# List packages installed in system profile. To search, run:
|
||||
# $ nix search wget
|
||||
systemPackages = with pkgs; [
|
||||
v4l-utils
|
||||
polychromatic
|
||||
openrazer-daemon
|
||||
cudatoolkit
|
||||
# Wine
|
||||
wine-wayland
|
||||
winetricks
|
||||
wineWowPackages.waylandFull
|
||||
|
||||
virt-manager
|
||||
gparted
|
||||
nvtopPackages.nvidia
|
||||
quickemu
|
||||
# (nixvim.makeNixvim (import ../../neovim))
|
||||
qpwgraph
|
||||
hyprland
|
||||
xorg.xhost
|
||||
foot
|
||||
git
|
||||
fish
|
||||
nushell
|
||||
# (pkgs.wrapFirefox
|
||||
# (pkgs.firefox-unwrapped.override {pipewireSupport = true;})
|
||||
# {})
|
||||
gnumake
|
||||
python3
|
||||
nerd-fonts.fira-code
|
||||
nerd-fonts.hasklug
|
||||
nerd-fonts.symbols-only
|
||||
monaspace
|
||||
ddcutil
|
||||
];
|
||||
sessionVariables = {
|
||||
WLR_NO_HARDWARE_CURSORS = "1";
|
||||
NIXOS_OZONE_WL = "1";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{...}: {
|
||||
imports = [
|
||||
./hytale.nix
|
||||
# ./hytale.nix
|
||||
];
|
||||
}
|
||||
|
||||
6
nixos/ryu/programs/ccache.nix
Normal file
6
nixos/ryu/programs/ccache.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{...}: {
|
||||
programs.ccache = {
|
||||
enable = true;
|
||||
packageNames = ["ollama" "orca-slicer" "opencv" "onnxruntime" "obs-studio" "llama-cpp"];
|
||||
};
|
||||
}
|
||||
3
nixos/ryu/programs/cuda.nix
Normal file
3
nixos/ryu/programs/cuda.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [cudatoolkit];
|
||||
}
|
||||
3
nixos/ryu/programs/ddcutil.nix
Normal file
3
nixos/ryu/programs/ddcutil.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [ddcutil];
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
./steam.nix
|
||||
./1password.nix
|
||||
./localsend.nix
|
||||
./appimage.nix
|
||||
# ./appimage.nix
|
||||
./obs-studio.nix
|
||||
./gnome-disks.nix
|
||||
./nix-ld.nix
|
||||
@@ -12,5 +12,15 @@
|
||||
./droidcam.nix
|
||||
./wireshark.nix
|
||||
./flatpak.nix
|
||||
./v4l-utils.nix
|
||||
./razer.nix
|
||||
./cuda.nix
|
||||
./fonts.nix
|
||||
./dev.nix
|
||||
./shells.nix
|
||||
./hyprland.nix
|
||||
./foot.nix
|
||||
./ddcutil.nix
|
||||
./libnotify.nix
|
||||
];
|
||||
}
|
||||
|
||||
7
nixos/ryu/programs/dev.nix
Normal file
7
nixos/ryu/programs/dev.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
git
|
||||
gnumake
|
||||
python3
|
||||
];
|
||||
}
|
||||
8
nixos/ryu/programs/fonts.nix
Normal file
8
nixos/ryu/programs/fonts.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
nerd-fonts.fira-code
|
||||
nerd-fonts.hasklug
|
||||
nerd-fonts.symbols-only
|
||||
monaspace
|
||||
];
|
||||
}
|
||||
3
nixos/ryu/programs/foot.nix
Normal file
3
nixos/ryu/programs/foot.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [foot];
|
||||
}
|
||||
6
nixos/ryu/programs/hyprland.nix
Normal file
6
nixos/ryu/programs/hyprland.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
hyprland
|
||||
xorg.xhost
|
||||
];
|
||||
}
|
||||
3
nixos/ryu/programs/libnotify.nix
Normal file
3
nixos/ryu/programs/libnotify.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [libnotify];
|
||||
}
|
||||
6
nixos/ryu/programs/razer.nix
Normal file
6
nixos/ryu/programs/razer.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
polychromatic
|
||||
openrazer-daemon
|
||||
];
|
||||
}
|
||||
6
nixos/ryu/programs/shells.nix
Normal file
6
nixos/ryu/programs/shells.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
fish
|
||||
nushell
|
||||
];
|
||||
}
|
||||
3
nixos/ryu/programs/v4l-utils.nix
Normal file
3
nixos/ryu/programs/v4l-utils.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [v4l-utils];
|
||||
}
|
||||
@@ -14,6 +14,11 @@
|
||||
services = {
|
||||
caddy = {
|
||||
enable = true;
|
||||
globalConfig = ''
|
||||
servers {
|
||||
metrics
|
||||
}
|
||||
'';
|
||||
extraConfig = ''
|
||||
(cloudflare) {
|
||||
tls {
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
# services.command-runner = {
|
||||
# enable = false;
|
||||
# port = 5599;
|
||||
# user = "servius";
|
||||
# commands = let
|
||||
# hyprctl = "${pkgs.hyprland}/bin/hyprctl";
|
||||
# in
|
||||
# {
|
||||
# "display_on" = [hyprctl "-i" "{instance}" "dispatch" "dpms" "on"];
|
||||
# "display_off" = [hyprctl "-i" "{instance}" "dispatch" "dpms" "off"];
|
||||
# "display_toggle" = [hyprctl "-i" "{instance}" "dispatch" "dpms" "toggle"];
|
||||
# "display_status" = [hyprctl "-i" "{instance}" "-j" "monitors"];
|
||||
# "hyprland_instance" = [hyprctl "-j" "instances"];
|
||||
# }
|
||||
# // (builtins.foldl' (acc: elem: acc // elem) {} (lib.map (name: {
|
||||
# "display_on_${name}" = [hyprctl "-i" "{instance}" "dispatch" "dpms" "on" name];
|
||||
# "display_off_${name}" = [hyprctl "-i" "{instance}" "dispatch" "dpms" "off" name];
|
||||
# "display_toggle_${name}" = [hyprctl "-i" "{instance}" "dispatch" "dpms" "toggle" name];
|
||||
# }) ["HDMI-A-1" "DP-3" "DP-1"]));
|
||||
# };
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
# ./zerotier.nix
|
||||
# ./dnscrypt.nix
|
||||
./caddy.nix
|
||||
./command-runner.nix
|
||||
./dualsense.nix
|
||||
./fprintd.nix
|
||||
./fwupd.nix
|
||||
@@ -22,5 +21,6 @@
|
||||
# ./sunshine.nix
|
||||
./tailscale.nix
|
||||
./wivrn.nix
|
||||
./pipewire.nix
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,11 +1,28 @@
|
||||
{...}: {
|
||||
{pkgs, ...}: let
|
||||
# Port configurations
|
||||
ports = {
|
||||
# System exporters
|
||||
node = 9100;
|
||||
systemd = 9558;
|
||||
process = 9256;
|
||||
nvidiagpu = 9835;
|
||||
|
||||
# Infrastructure exporters
|
||||
cadvisor = 8080;
|
||||
caddy = 2019;
|
||||
};
|
||||
in {
|
||||
services = {
|
||||
prometheus = {
|
||||
exporters = {
|
||||
systemd = {
|
||||
enable = true;
|
||||
port = ports.systemd;
|
||||
};
|
||||
nvidia-gpu = {
|
||||
enable = true;
|
||||
port = ports.nvidiagpu;
|
||||
};
|
||||
nvidia-gpu.enable = true;
|
||||
node = {
|
||||
enable = true;
|
||||
enabledCollectors = [
|
||||
@@ -19,7 +36,10 @@
|
||||
"time"
|
||||
"uname"
|
||||
"vmstat"
|
||||
"diskstats"
|
||||
"cpu"
|
||||
];
|
||||
port = ports.node;
|
||||
};
|
||||
process = {
|
||||
enable = true;
|
||||
@@ -33,4 +53,34 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Docker cAdvisor for container metrics
|
||||
# virtualisation.oci-containers.containers.cadvisor = {
|
||||
# image = "gcr.io/cadvisor/cadvisor:v0.49.1";
|
||||
# ports = ["${toString ports.cadvisor}:8080"];
|
||||
# volumes = [
|
||||
# "/:/rootfs:ro"
|
||||
# "/var/run:/var/run:ro"
|
||||
# "/sys:/sys:ro"
|
||||
# "/var/lib/docker/:/var/lib/docker:ro"
|
||||
# "/dev/disk/:/dev/disk:ro"
|
||||
# ];
|
||||
# extraOptions = [
|
||||
# "--privileged"
|
||||
# "--device=/dev/kmsg"
|
||||
# ];
|
||||
# };
|
||||
|
||||
# Open firewall ports for Prometheus exporters
|
||||
networking.firewall = {
|
||||
# Allow from Tailscale network
|
||||
interfaces."tailscale0".allowedTCPPorts = [
|
||||
ports.node
|
||||
ports.systemd
|
||||
ports.process
|
||||
ports.nvidiagpu
|
||||
ports.cadvisor
|
||||
ports.caddy
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
19
nixos/ryu/services/pipewire.nix
Normal file
19
nixos/ryu/services/pipewire.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{...}: {
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
audio.enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
pulse.enable = true;
|
||||
extraConfig = {
|
||||
pipewire = {
|
||||
"10-clock-rate" = {
|
||||
"context.properties" = {
|
||||
"default.clock.quantum" = 32;
|
||||
"default.clock.allowed-rates" = [44100 48000 88200 96000];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -2,10 +2,14 @@
|
||||
# Disable all the dns stuff in favour of tailscale's DNS
|
||||
services.resolved = {
|
||||
enable = true;
|
||||
dnssec = "true";
|
||||
dnsovertls = "true";
|
||||
domains = ["lemur-newton.ts.net"];
|
||||
fallbackDns = [];
|
||||
settings = {
|
||||
Resolve = {
|
||||
DNSSEC = "true";
|
||||
DNSoverTLS = "true";
|
||||
Domains = ["lemur-newton.ts.net"];
|
||||
FallbackDNS = [];
|
||||
};
|
||||
};
|
||||
};
|
||||
networking.nameservers = [];
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
./services
|
||||
./tako.nix
|
||||
# ./docker.nix
|
||||
../../modules/nixos/substituters.nix
|
||||
];
|
||||
|
||||
virtualisation.docker.enable = true;
|
||||
@@ -35,7 +36,6 @@
|
||||
# Use the systemd-boot EFI boot loader.
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
nix = {
|
||||
settings = {
|
||||
max-jobs = 1;
|
||||
@@ -43,16 +43,6 @@
|
||||
auto-optimise-store = true;
|
||||
extra-experimental-features = "nix-command flakes auto-allocate-uids";
|
||||
trusted-users = [device.user "remotebuilder"];
|
||||
trusted-substituters = [
|
||||
"https://nix-community.cachix.org"
|
||||
"https://nixos-raspberrypi.cachix.org"
|
||||
# "https://sh.darksailor.dev"
|
||||
];
|
||||
trusted-public-keys = [
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
"nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
|
||||
# "tako:bcVPoFGBZ0i7JAKMXIqLj2GY3CulLC4kP7rQyqes1RM="
|
||||
];
|
||||
};
|
||||
extraOptions = ''
|
||||
build-users-group = nixbld
|
||||
@@ -67,6 +57,9 @@
|
||||
};
|
||||
package = pkgs.nixVersions.nix_2_32; # deploy-rs doesn't work with nix >= 2.32
|
||||
distributedBuilds = true;
|
||||
substituters = {
|
||||
enableCuda = true;
|
||||
};
|
||||
};
|
||||
|
||||
users.users.${device.user} = {
|
||||
|
||||
89
nixos/tako/services/affine.nix
Normal file
89
nixos/tako/services/affine.nix
Normal 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"];
|
||||
}
|
||||
@@ -1,16 +1,21 @@
|
||||
{...}: {
|
||||
{config, ...}: let
|
||||
address = "127.0.0.1:8052";
|
||||
in {
|
||||
sops = {
|
||||
secrets."attic/jwt_secret" = {};
|
||||
templates."attic.env".content = ''
|
||||
ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64=${config.sops.placeholder."attic/jwt_secret"}
|
||||
'';
|
||||
};
|
||||
services = {
|
||||
atticd = {
|
||||
enable = false;
|
||||
listen = "/run/attic.sock";
|
||||
enable = true;
|
||||
settings.listen = address;
|
||||
environmentFile = config.sops.templates."attic.env".path;
|
||||
};
|
||||
caddy = {
|
||||
virtualHosts."cache.darksailor.dev".extraConfig = ''
|
||||
reverse_proxy /run/attic.sock {
|
||||
transport http {
|
||||
protocol = "fd"
|
||||
}
|
||||
}
|
||||
reverse_proxy ${address}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
services = {
|
||||
caddy = {
|
||||
enable = true;
|
||||
globalConfig = ''
|
||||
servers {
|
||||
metrics
|
||||
}
|
||||
'';
|
||||
extraConfig = ''
|
||||
(auth) {
|
||||
forward_auth localhost:5555 {
|
||||
|
||||
@@ -1,29 +1,33 @@
|
||||
{...}: {
|
||||
imports = [
|
||||
./games
|
||||
# ./headscale.nix
|
||||
./llms.nix
|
||||
# ./monitoring.nix
|
||||
# ./paperless.nix
|
||||
./navidrome.nix
|
||||
./shitpost.nix
|
||||
./atuin.nix
|
||||
./authelia.nix
|
||||
./caddy.nix
|
||||
./excalidraw.nix
|
||||
./fail2ban.nix
|
||||
./flaresolverr.nix
|
||||
./gitea.nix
|
||||
./homepage.nix
|
||||
./immich.nix
|
||||
./lldap.nix
|
||||
./navidrome.nix
|
||||
./nextcloud.nix
|
||||
./openssh.nix
|
||||
./prowlarr.nix
|
||||
./resolved.nix
|
||||
./searxng.nix
|
||||
./tailscale.nix
|
||||
./gitea.nix
|
||||
|
||||
./affine.nix
|
||||
./attic.nix
|
||||
./excalidraw.nix
|
||||
./flaresolverr.nix
|
||||
# ./games
|
||||
# ./headscale.nix
|
||||
./immich.nix
|
||||
./kellnr.nix
|
||||
# ./llms.nix
|
||||
./matrix
|
||||
# ./monitoring.nix
|
||||
# ./paperless.nix
|
||||
./prowlarr.nix
|
||||
# ./searxng.nix
|
||||
# ./shitpost.nix
|
||||
];
|
||||
services = {
|
||||
nix-serve = {
|
||||
|
||||
@@ -1,30 +1,91 @@
|
||||
{...}: {
|
||||
{config, ...}: let
|
||||
dataDir = "/var/lib/excalidraw";
|
||||
base_domain = "darksailor.dev";
|
||||
in {
|
||||
# SOPS secrets and templates
|
||||
sops = {
|
||||
secrets = {
|
||||
"excalidraw/jwt_secret" = {};
|
||||
"authelia/oidc/excalidraw/client_id" = {
|
||||
owner = config.systemd.services.authelia-darksailor.serviceConfig.User;
|
||||
mode = "0440";
|
||||
restartUnits = ["authelia-darksailor.service"];
|
||||
};
|
||||
"authelia/oidc/excalidraw/client_secret" = {
|
||||
owner = config.systemd.services.authelia-darksailor.serviceConfig.User;
|
||||
mode = "0440";
|
||||
restartUnits = ["authelia-darksailor.service"];
|
||||
};
|
||||
};
|
||||
templates."excalidraw.env".content = ''
|
||||
OIDC_ISSUER_URL=https://auth.${base_domain}
|
||||
OIDC_CLIENT_ID=${config.sops.placeholder."authelia/oidc/excalidraw/client_id"}
|
||||
OIDC_CLIENT_SECRET=${config.sops.placeholder."authelia/oidc/excalidraw/client_secret"}
|
||||
OIDC_REDIRECT_URL=https://draw.${base_domain}/auth/callback
|
||||
JWT_SECRET=${config.sops.placeholder."excalidraw/jwt_secret"}
|
||||
STORAGE_TYPE=sqlite
|
||||
DATA_SOURCE_NAME=excalidraw.db
|
||||
LOCAL_STORAGE_PATH=/root/data
|
||||
'';
|
||||
};
|
||||
|
||||
# Create data directory and initialize SQLite DB
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${dataDir} 0755 root root -"
|
||||
"d ${dataDir}/data 0755 root root -"
|
||||
"f ${dataDir}/excalidraw.db 0644 root root -"
|
||||
];
|
||||
|
||||
virtualisation.oci-containers = {
|
||||
backend = "docker";
|
||||
containers = {
|
||||
# Excalidraw Full backend
|
||||
excalidraw = {
|
||||
image = "excalidraw/excalidraw:latest";
|
||||
ports = ["127.0.0.1:5959:80"];
|
||||
volumes = [];
|
||||
image = "ghcr.io/betterandbetterii/excalidraw-full:latest";
|
||||
ports = ["127.0.0.1:3002:3002"];
|
||||
environmentFiles = [
|
||||
config.sops.templates."excalidraw.env".path
|
||||
];
|
||||
volumes = [
|
||||
"${dataDir}/data:/root/data"
|
||||
"${dataDir}/excalidraw.db:/root/excalidraw.db"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
services.caddy.virtualHosts."draw.darksailor.dev".extraConfig = ''
|
||||
import auth
|
||||
reverse_proxy localhost:5959
|
||||
|
||||
# Caddy reverse proxy
|
||||
services.caddy.virtualHosts."draw.${base_domain}".extraConfig = ''
|
||||
reverse_proxy localhost:3002
|
||||
'';
|
||||
services.authelia = {
|
||||
instances.darksailor = {
|
||||
settings = {
|
||||
access_control = {
|
||||
rules = [
|
||||
|
||||
# Configure Authelia OIDC for Excalidraw
|
||||
services.authelia.instances.darksailor.settings = {
|
||||
identity_providers = {
|
||||
oidc = {
|
||||
clients = [
|
||||
{
|
||||
domain = "draw.darksailor.dev";
|
||||
policy = "one_factor";
|
||||
client_name = "Excalidraw: Darksailor";
|
||||
client_id = ''{{ secret "${config.sops.secrets."authelia/oidc/excalidraw/client_id".path}" }}'';
|
||||
client_secret = ''{{ secret "${config.sops.secrets."authelia/oidc/excalidraw/client_secret".path}" }}'';
|
||||
public = false;
|
||||
authorization_policy = "one_factor";
|
||||
require_pkce = false;
|
||||
redirect_uris = [
|
||||
"https://draw.${base_domain}/auth/callback"
|
||||
];
|
||||
scopes = [
|
||||
"openid"
|
||||
"email"
|
||||
"profile"
|
||||
];
|
||||
response_types = ["code"];
|
||||
grant_types = ["authorization_code"];
|
||||
userinfo_signed_response_alg = "none";
|
||||
token_endpoint_auth_method = "client_secret_post";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
ignoreIP = [
|
||||
"106.219.121.52"
|
||||
"106.219.122.125"
|
||||
"106.219.122.221"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
imports = [
|
||||
# ./minecraft.nix
|
||||
# ./satisfactory.nix
|
||||
./terraria.nix
|
||||
# ./terraria.nix
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
|
||||
@@ -63,6 +63,10 @@
|
||||
# LFS_START_SERVER = true;
|
||||
LFS_ALLOW_PURE_SSH = true;
|
||||
};
|
||||
metrics = {
|
||||
ENABLED = true;
|
||||
TOKEN = "";
|
||||
};
|
||||
oauth2_client = {
|
||||
ENABLE_AUTO_REGISTRATION = true;
|
||||
ACCOUNT_LINKING = "auto";
|
||||
@@ -75,22 +79,22 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
# gitea-actions-runner = {
|
||||
# instances = {
|
||||
# tako = {
|
||||
# enable = true;
|
||||
# name = "tako";
|
||||
# url = "https://git.darksailor.dev";
|
||||
# labels = [
|
||||
# "ubuntu-latest:docker://catthehacker/ubuntu:full-latest"
|
||||
# "ubuntu-22.04:docker://catthehacker/ubuntu:full-22.04"
|
||||
# "ubuntu-20.04:docker://catthehacker/ubuntu:full-20.04"
|
||||
# "native:host"
|
||||
# ];
|
||||
# tokenFile = "${config.sops.templates."GITEA_REGISTRATION_TOKEN.env".path}";
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
gitea-actions-runner = {
|
||||
instances = {
|
||||
tako = {
|
||||
enable = true;
|
||||
name = "tako";
|
||||
url = "https://git.darksailor.dev";
|
||||
labels = [
|
||||
"ubuntu-latest:docker://catthehacker/ubuntu:full-latest"
|
||||
"ubuntu-22.04:docker://catthehacker/ubuntu:full-22.04"
|
||||
"ubuntu-20.04:docker://catthehacker/ubuntu:full-20.04"
|
||||
"native:host"
|
||||
];
|
||||
tokenFile = "${config.sops.templates."GITEA_REGISTRATION_TOKEN.env".path}";
|
||||
};
|
||||
};
|
||||
};
|
||||
caddy = {
|
||||
virtualHosts."git.darksailor.dev".extraConfig = ''
|
||||
reverse_proxy localhost:3000
|
||||
|
||||
@@ -34,12 +34,12 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
# headplane = {
|
||||
# enable = true;
|
||||
# settings = {
|
||||
# server.port = 42562;
|
||||
# };
|
||||
# };
|
||||
headplane = {
|
||||
enable = true;
|
||||
settings = {
|
||||
server.port = 42562;
|
||||
};
|
||||
};
|
||||
caddy = {
|
||||
virtualHosts."headscale.darksailor.dev".extraConfig = ''
|
||||
reverse_proxy localhost:${toString config.services.headplane.settings.server.port}
|
||||
|
||||
@@ -87,6 +87,14 @@
|
||||
siteMonitor = "https://git.darksailor.dev";
|
||||
};
|
||||
}
|
||||
{
|
||||
"Grafana" = {
|
||||
icon = "grafana.png";
|
||||
description = "Grafana Monitoring & Metrics";
|
||||
href = "https://grafana.darksailor.dev";
|
||||
siteMonitor = "https://grafana.darksailor.dev";
|
||||
};
|
||||
}
|
||||
{
|
||||
"Nextcloud" = {
|
||||
icon = "nextcloud.png";
|
||||
|
||||
7
nixos/tako/services/matrix/default.nix
Normal file
7
nixos/tako/services/matrix/default.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{...}: {
|
||||
imports = [
|
||||
./tuwunel.nix
|
||||
# ./signal.nix // libolm deprecated
|
||||
# ./discord.nix
|
||||
];
|
||||
}
|
||||
19
nixos/tako/services/matrix/discord.nix
Normal file
19
nixos/tako/services/matrix/discord.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{...}: {
|
||||
services.mautrix-discord = {
|
||||
enable = true;
|
||||
settings = {
|
||||
homeserver = {
|
||||
address = "http://localhost:6167";
|
||||
domain = "darksailor.dev";
|
||||
};
|
||||
appservice.public = {
|
||||
prefix = "/public";
|
||||
external = "https://matrix.darksailor.dev/public";
|
||||
};
|
||||
bridge.permissions = {
|
||||
"darksailor.dev" = "user";
|
||||
"@servius:darksailor.dev" = "admin";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
5
nixos/tako/services/matrix/signal.nix
Normal file
5
nixos/tako/services/matrix/signal.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{...}: {
|
||||
services.mautrix-signal = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
193
nixos/tako/services/matrix/tuwunel.nix
Normal file
193
nixos/tako/services/matrix/tuwunel.nix
Normal file
@@ -0,0 +1,193 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
port = 6167;
|
||||
base_domain = "darksailor.dev";
|
||||
client_id = "tuwunel";
|
||||
rtc_domain = "matrix-rtc.${base_domain}";
|
||||
jwt_port = 8081;
|
||||
elementConfig = builtins.toJSON {
|
||||
default_server_config = {
|
||||
"m.homeserver" = {
|
||||
base_url = "https://matrix.${base_domain}";
|
||||
};
|
||||
};
|
||||
sso_redirect_options = {
|
||||
immediate = false;
|
||||
on_welcome_page = true;
|
||||
on_login_page = true;
|
||||
};
|
||||
};
|
||||
elementConfigFile = pkgs.writeText "element-config.json" elementConfig;
|
||||
in {
|
||||
sops = {
|
||||
secrets."tuwunel/client_id" = {
|
||||
owner = config.services.matrix-tuwunel.user;
|
||||
group = config.systemd.services.authelia-darksailor.serviceConfig.Group;
|
||||
mode = "0440";
|
||||
};
|
||||
secrets."tuwunel/client_secret" = {
|
||||
owner = config.services.matrix-tuwunel.user;
|
||||
group = config.systemd.services.authelia-darksailor.serviceConfig.Group;
|
||||
mode = "0440";
|
||||
};
|
||||
secrets."tuwunel/registration_token".owner = config.services.matrix-tuwunel.user;
|
||||
secrets."livekit/key_name" = {};
|
||||
secrets."livekit/key_secret" = {};
|
||||
templates."livekit-keys".content = ''
|
||||
${config.sops.placeholder."livekit/key_name"}: ${config.sops.placeholder."livekit/key_secret"}
|
||||
'';
|
||||
};
|
||||
services.matrix-tuwunel = {
|
||||
enable = true;
|
||||
settings.global = {
|
||||
server_name = "${base_domain}";
|
||||
address = ["127.0.0.1"];
|
||||
port = [port];
|
||||
allow_registration = true;
|
||||
registration_token_file = config.sops.secrets."tuwunel/registration_token".path;
|
||||
single_sso = true;
|
||||
identity_provider = [
|
||||
{
|
||||
inherit client_id;
|
||||
brand = "Authelia";
|
||||
name = "Authelia";
|
||||
default = true;
|
||||
issuer_url = "https://auth.${base_domain}";
|
||||
client_secret_file = config.sops.secrets."tuwunel/client_secret".path;
|
||||
callback_url = "https://matrix.${base_domain}/_matrix/client/unstable/login/sso/callback/${client_id}";
|
||||
}
|
||||
];
|
||||
well_known = {
|
||||
client = "https://matrix.${base_domain}";
|
||||
server = "matrix.${base_domain}:443";
|
||||
rtc_transports = [
|
||||
{
|
||||
type = "livekit";
|
||||
livekit_service_url = "https://${rtc_domain}";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
package = pkgs.matrix-tuwunel;
|
||||
};
|
||||
services.caddy.virtualHosts = {
|
||||
"matrix.${base_domain}".extraConfig = ''
|
||||
reverse_proxy /_matrix/* localhost:${toString port}
|
||||
handle_path /config.json {
|
||||
file_server
|
||||
root ${elementConfigFile}
|
||||
}
|
||||
root * ${pkgs.element-web}
|
||||
file_server
|
||||
'';
|
||||
"${base_domain}".extraConfig = ''
|
||||
reverse_proxy /.well-known/* localhost:${toString port}
|
||||
'';
|
||||
"${rtc_domain}".extraConfig = ''
|
||||
@jwt_service {
|
||||
path /sfu/get* /healthz*
|
||||
}
|
||||
handle @jwt_service {
|
||||
reverse_proxy localhost:${toString jwt_port}
|
||||
}
|
||||
handle {
|
||||
reverse_proxy localhost:${toString config.services.livekit.settings.port} {
|
||||
header_up Connection "upgrade"
|
||||
header_up Upgrade {http.request.header.Upgrade}
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [8448 7881];
|
||||
allowedUDPPorts = [3478];
|
||||
allowedUDPPortRanges = [
|
||||
{
|
||||
from = 50300;
|
||||
to = 65535;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
users.users.${config.services.caddy.user}.extraGroups = [config.services.matrix-tuwunel.group];
|
||||
|
||||
services.livekit = {
|
||||
enable = true;
|
||||
keyFile = config.sops.templates."livekit-keys".path;
|
||||
openFirewall = true;
|
||||
settings = {
|
||||
rtc = {
|
||||
tcp_port = 7881;
|
||||
port_range_start = 50100;
|
||||
port_range_end = 50200;
|
||||
use_external_ip = true;
|
||||
enable_loopback_candidate = false;
|
||||
};
|
||||
turn = {
|
||||
enabled = true;
|
||||
udp_port = 3478;
|
||||
relay_range_start = 50300;
|
||||
relay_range_end = 65535;
|
||||
domain = rtc_domain;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.lk-jwt-service = {
|
||||
enable = true;
|
||||
port = jwt_port;
|
||||
livekitUrl = "wss://${rtc_domain}";
|
||||
keyFile = config.sops.templates."livekit-keys".path;
|
||||
};
|
||||
|
||||
services = {
|
||||
authelia = {
|
||||
instances.darksailor = {
|
||||
settings = {
|
||||
identity_providers = {
|
||||
oidc = {
|
||||
claims_policies = {
|
||||
tuwunel = {
|
||||
id_token = [
|
||||
"email"
|
||||
"name"
|
||||
"groups"
|
||||
"preferred_username"
|
||||
];
|
||||
};
|
||||
};
|
||||
clients = [
|
||||
{
|
||||
inherit client_id;
|
||||
client_name = "Matrix: Darksailor";
|
||||
client_secret = ''{{ secret "${config.sops.secrets."tuwunel/client_secret".path}" }}'';
|
||||
public = false;
|
||||
authorization_policy = "one_factor";
|
||||
require_pkce = false;
|
||||
# pkce_challenge_method = "S256";
|
||||
redirect_uris = [
|
||||
"https://matrix.${base_domain}/_matrix/client/unstable/login/sso/callback/${client_id}"
|
||||
];
|
||||
scopes = [
|
||||
"openid"
|
||||
"groups"
|
||||
"email"
|
||||
"profile"
|
||||
];
|
||||
response_types = ["code"];
|
||||
response_modes = ["form_post"];
|
||||
grant_types = ["refresh_token" "authorization_code"];
|
||||
userinfo_signed_response_alg = "none";
|
||||
token_endpoint_auth_method = "client_secret_post";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
483
nixos/tako/services/monitoring.nix
Normal file
483
nixos/tako/services/monitoring.nix
Normal file
@@ -0,0 +1,483 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
# Port configurations
|
||||
ports = {
|
||||
grafana = 3001; # Changed from 3000 to avoid clash with Gitea
|
||||
prometheus = 9090;
|
||||
|
||||
# System exporters
|
||||
node = 9100;
|
||||
systemd = 9558;
|
||||
process = 9256;
|
||||
|
||||
# Infrastructure exporters
|
||||
postgres = 9187;
|
||||
redis = 9121;
|
||||
cadvisor = 8080;
|
||||
|
||||
# Application exporters
|
||||
caddy = 2019;
|
||||
};
|
||||
in {
|
||||
# Grafana configuration with Authelia integration
|
||||
services.grafana = {
|
||||
enable = true;
|
||||
settings = {
|
||||
server = {
|
||||
http_addr = "127.0.0.1";
|
||||
http_port = ports.grafana;
|
||||
domain = "grafana.darksailor.dev";
|
||||
root_url = "https://grafana.darksailor.dev";
|
||||
};
|
||||
|
||||
# Disable Grafana's own auth since we use Authelia
|
||||
auth.disable_login_form = true;
|
||||
"auth.basic".enabled = false;
|
||||
"auth.anonymous".enabled = false;
|
||||
"auth.proxy" = {
|
||||
enabled = true;
|
||||
header_name = "REMOTE-USER";
|
||||
header_property = "username";
|
||||
auto_sign_up = true;
|
||||
};
|
||||
|
||||
users = {
|
||||
allow_sign_up = false;
|
||||
auto_assign_org = true;
|
||||
auto_assign_org_role = "Admin";
|
||||
};
|
||||
|
||||
security = {
|
||||
disable_gravatar = true;
|
||||
cookie_secure = true;
|
||||
};
|
||||
|
||||
analytics = {
|
||||
reporting_enabled = false;
|
||||
check_for_updates = false;
|
||||
};
|
||||
};
|
||||
|
||||
provision = {
|
||||
enable = true;
|
||||
datasources.settings.datasources = [
|
||||
{
|
||||
name = "Prometheus";
|
||||
type = "prometheus";
|
||||
access = "proxy";
|
||||
url = "http://localhost:${toString ports.prometheus}";
|
||||
isDefault = true;
|
||||
jsonData = {
|
||||
timeInterval = "30s";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
# Provision popular community dashboards
|
||||
dashboards = {
|
||||
settings = {
|
||||
apiVersion = 1;
|
||||
providers = [
|
||||
{
|
||||
name = "default";
|
||||
orgId = 1;
|
||||
folder = "";
|
||||
type = "file";
|
||||
disableDeletion = false;
|
||||
updateIntervalSeconds = 10;
|
||||
allowUiUpdates = true;
|
||||
options.path = "/var/lib/grafana/dashboards";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Caddy virtual host for Grafana with Authelia
|
||||
services.caddy.virtualHosts."grafana.darksailor.dev".extraConfig = ''
|
||||
import auth
|
||||
reverse_proxy localhost:${toString ports.grafana}
|
||||
'';
|
||||
|
||||
# Central Prometheus server
|
||||
services.prometheus = {
|
||||
enable = true;
|
||||
port = ports.prometheus;
|
||||
|
||||
# Retention settings (90 days)
|
||||
retentionTime = "90d";
|
||||
|
||||
# Global scrape config
|
||||
globalConfig = {
|
||||
scrape_interval = "30s";
|
||||
evaluation_interval = "30s";
|
||||
};
|
||||
|
||||
# System exporters for tako
|
||||
exporters = {
|
||||
node = {
|
||||
enable = true;
|
||||
port = ports.node;
|
||||
enabledCollectors = [
|
||||
"systemd"
|
||||
"textfile"
|
||||
"filesystem"
|
||||
"loadavg"
|
||||
"meminfo"
|
||||
"netdev"
|
||||
"netstat"
|
||||
"stat"
|
||||
"time"
|
||||
"uname"
|
||||
"vmstat"
|
||||
"diskstats"
|
||||
"cpu"
|
||||
];
|
||||
};
|
||||
|
||||
systemd = {
|
||||
enable = true;
|
||||
port = ports.systemd;
|
||||
};
|
||||
|
||||
process = {
|
||||
enable = true;
|
||||
settings.process_names = [
|
||||
{
|
||||
name = "{{.Comm}}";
|
||||
cmdline = [".*"];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
postgres = {
|
||||
enable = true;
|
||||
port = ports.postgres;
|
||||
runAsLocalSuperUser = true;
|
||||
};
|
||||
|
||||
redis = {
|
||||
enable = true;
|
||||
port = ports.redis;
|
||||
};
|
||||
};
|
||||
|
||||
# Scrape configurations for all targets
|
||||
scrapeConfigs = [
|
||||
# System metrics - tako (local)
|
||||
{
|
||||
job_name = "tako-system";
|
||||
static_configs = [
|
||||
{
|
||||
targets = [
|
||||
"localhost:${toString ports.node}"
|
||||
"localhost:${toString ports.systemd}"
|
||||
"localhost:${toString ports.process}"
|
||||
];
|
||||
labels = {
|
||||
instance = "tako";
|
||||
machine = "tako";
|
||||
role = "server";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
# Infrastructure - tako
|
||||
{
|
||||
job_name = "tako-infrastructure";
|
||||
static_configs = [
|
||||
{
|
||||
targets = [
|
||||
"localhost:${toString ports.postgres}"
|
||||
"localhost:${toString ports.redis}"
|
||||
"localhost:${toString ports.cadvisor}"
|
||||
];
|
||||
labels = {
|
||||
instance = "tako";
|
||||
machine = "tako";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
# Caddy metrics - tako
|
||||
{
|
||||
job_name = "tako-caddy";
|
||||
static_configs = [
|
||||
{
|
||||
targets = ["localhost:${toString ports.caddy}"];
|
||||
labels = {
|
||||
instance = "tako";
|
||||
machine = "tako";
|
||||
service = "caddy";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
# Application metrics - tako
|
||||
{
|
||||
job_name = "tako-applications";
|
||||
static_configs = [
|
||||
{
|
||||
targets = [
|
||||
"localhost:3000" # gitea
|
||||
"localhost:5555" # authelia (if metrics enabled)
|
||||
];
|
||||
labels = {
|
||||
instance = "tako";
|
||||
machine = "tako";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
# System metrics - tsuba (remote via Tailscale)
|
||||
{
|
||||
job_name = "tsuba-system";
|
||||
static_configs = [
|
||||
{
|
||||
targets = [
|
||||
"tsuba:9100" # node
|
||||
"tsuba:9558" # systemd
|
||||
"tsuba:9256" # process
|
||||
];
|
||||
labels = {
|
||||
instance = "tsuba";
|
||||
machine = "tsuba";
|
||||
role = "server";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
# Infrastructure - tsuba
|
||||
{
|
||||
job_name = "tsuba-infrastructure";
|
||||
static_configs = [
|
||||
{
|
||||
targets = [
|
||||
"tsuba:8080" # cadvisor
|
||||
"tsuba:2019" # caddy
|
||||
];
|
||||
labels = {
|
||||
instance = "tsuba";
|
||||
machine = "tsuba";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
# Media services - tsuba
|
||||
{
|
||||
job_name = "tsuba-media";
|
||||
static_configs = [
|
||||
{
|
||||
targets = [
|
||||
"tsuba:8096" # jellyfin (built-in /metrics endpoint)
|
||||
"tsuba:8123" # homeassistant (configure prometheus integration)
|
||||
"tsuba:9617" # pihole-exporter
|
||||
];
|
||||
labels = {
|
||||
instance = "tsuba";
|
||||
machine = "tsuba";
|
||||
};
|
||||
}
|
||||
];
|
||||
metrics_path = "/metrics";
|
||||
relabel_configs = [
|
||||
{
|
||||
source_labels = ["__address__"];
|
||||
regex = "tsuba:8096";
|
||||
target_label = "__metrics_path__";
|
||||
replacement = "/metrics";
|
||||
}
|
||||
{
|
||||
source_labels = ["__address__"];
|
||||
regex = "tsuba:8123";
|
||||
target_label = "__metrics_path__";
|
||||
replacement = "/api/prometheus";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
# Servarr stack - tsuba (exportarr)
|
||||
{
|
||||
job_name = "tsuba-servarr";
|
||||
static_configs = [
|
||||
{
|
||||
targets = [
|
||||
"tsuba:9707" # sonarr
|
||||
"tsuba:9708" # radarr
|
||||
"tsuba:9709" # lidarr
|
||||
"tsuba:9710" # bazarr
|
||||
];
|
||||
labels = {
|
||||
instance = "tsuba";
|
||||
machine = "tsuba";
|
||||
stack = "servarr";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
# Deluge - tsuba
|
||||
{
|
||||
job_name = "tsuba-deluge";
|
||||
static_configs = [
|
||||
{
|
||||
targets = ["tsuba:9354"];
|
||||
labels = {
|
||||
instance = "tsuba";
|
||||
machine = "tsuba";
|
||||
service = "deluge";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
# System metrics - ryu (remote via Tailscale)
|
||||
{
|
||||
job_name = "ryu-system";
|
||||
static_configs = [
|
||||
{
|
||||
targets = [
|
||||
"ryu:9100"
|
||||
"ryu:9558"
|
||||
"ryu:9256"
|
||||
"ryu:9835" # nvidia-gpu
|
||||
];
|
||||
labels = {
|
||||
instance = "ryu";
|
||||
machine = "ryu";
|
||||
role = "desktop";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
# Infrastructure - ryu
|
||||
{
|
||||
job_name = "ryu-infrastructure";
|
||||
static_configs = [
|
||||
{
|
||||
targets = [
|
||||
"ryu:8080" # cadvisor
|
||||
"ryu:2019" # caddy
|
||||
];
|
||||
labels = {
|
||||
instance = "ryu";
|
||||
machine = "ryu";
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# Docker cAdvisor for container metrics
|
||||
# virtualisation.oci-containers.containers.cadvisor = {
|
||||
# image = "gcr.io/cadvisor/cadvisor:v0.49.1";
|
||||
# ports = ["127.0.0.1:${toString ports.cadvisor}:8080"];
|
||||
# volumes = [
|
||||
# "/:/rootfs:ro"
|
||||
# "/var/run:/var/run:ro"
|
||||
# "/sys:/sys:ro"
|
||||
# "/var/lib/docker/:/var/lib/docker:ro"
|
||||
# "/dev/disk/:/dev/disk:ro"
|
||||
# ];
|
||||
# extraOptions = [
|
||||
# "--privileged"
|
||||
# "--device=/dev/kmsg"
|
||||
# ];
|
||||
# };
|
||||
|
||||
# Link dashboard files from Nix store to Grafana's expected location
|
||||
systemd.tmpfiles.rules = let
|
||||
# Define dashboard files with proper hashes
|
||||
nodeExporterFull = pkgs.fetchurl {
|
||||
url = "https://grafana.com/api/dashboards/1860/revisions/37/download";
|
||||
sha256 = "0qza4j8lywrj08bqbww52dgh2p2b9rkhq5p313g72i57lrlkacfl";
|
||||
};
|
||||
nvidiaDashboardRaw = pkgs.fetchurl {
|
||||
url = "https://grafana.com/api/dashboards/14574/revisions/9/download";
|
||||
sha256 = "170ijap5i99sapkxlf3k0lnvwmb6g9jkk7q66nwjwswkj2a7rqbr";
|
||||
};
|
||||
# Fix NVIDIA dashboard to use our Prometheus datasource
|
||||
nvidiaDashboard = pkgs.runCommand "nvidia-gpu-fixed.json" {} ''
|
||||
${pkgs.gnused}/bin/sed 's/\''${DS_PROMETHEUS}/Prometheus/g' ${nvidiaDashboardRaw} > $out
|
||||
'';
|
||||
postgresqlDashboardRaw = pkgs.fetchurl {
|
||||
url = "https://grafana.com/api/dashboards/9628/revisions/7/download";
|
||||
sha256 = "0xmk68kqb9b8aspjj2f8wxv2mxiqk9k3xs0yal4szmzbv65c6k66";
|
||||
};
|
||||
# Fix PostgreSQL dashboard to use our Prometheus datasource
|
||||
postgresqlDashboard = pkgs.runCommand "postgresql-fixed.json" {} ''
|
||||
${pkgs.gnused}/bin/sed 's/\''${DS_PROMETHEUS}/Prometheus/g' ${postgresqlDashboardRaw} > $out
|
||||
'';
|
||||
redisDashboard = pkgs.fetchurl {
|
||||
url = "https://grafana.com/api/dashboards/11835/revisions/1/download";
|
||||
sha256 = "15lbn4i8j5hiypl4dsg0d72jgrgjwpagkf5kcwx66gyps17jcrxx";
|
||||
};
|
||||
dockerDashboardRaw = pkgs.fetchurl {
|
||||
url = "https://grafana.com/api/dashboards/193/revisions/1/download";
|
||||
sha256 = "1lxbbl91fh0yfh8x53205b7nw5ivghlpfb0m308z2p6fzvz2iq2m";
|
||||
};
|
||||
# Fix Docker dashboard to use our Prometheus datasource
|
||||
dockerDashboard = pkgs.runCommand "docker-cadvisor-fixed.json" {} ''
|
||||
${pkgs.gnused}/bin/sed 's/\''${DS_PROMETHEUS}/Prometheus/g' ${dockerDashboardRaw} > $out
|
||||
'';
|
||||
caddyDashboardRaw = pkgs.fetchurl {
|
||||
url = "https://grafana.com/api/dashboards/14280/revisions/1/download";
|
||||
sha256 = "0j3q68cq1nj8gcxkqz5h1kn1ds5kgq4jlkw73xp6yc88mbm5nyh4";
|
||||
};
|
||||
# Fix Caddy dashboard to use our Prometheus datasource
|
||||
caddyDashboard = pkgs.runCommand "caddy-fixed.json" {} ''
|
||||
${pkgs.gnused}/bin/sed 's/\''${DS_PROMETHEUS}/Prometheus/g' ${caddyDashboardRaw} > $out
|
||||
'';
|
||||
piholeDashboardRaw = pkgs.fetchurl {
|
||||
url = "https://grafana.com/api/dashboards/10176/revisions/3/download";
|
||||
sha256 = "18f8w3l5k178agipfbimg29lkf2i32xynin1g1v5abiac3ahj7ih";
|
||||
};
|
||||
# Fix Pi-hole dashboard to use our Prometheus datasource
|
||||
piholeDashboard = pkgs.runCommand "pihole-fixed.json" {} ''
|
||||
${pkgs.gnused}/bin/sed 's/\''${DS_PROMETHEUS}/Prometheus/g' ${piholeDashboardRaw} > $out
|
||||
'';
|
||||
in [
|
||||
"d /var/lib/grafana/dashboards 0755 grafana grafana -"
|
||||
"L+ /var/lib/grafana/dashboards/node-exporter-full.json - - - - ${nodeExporterFull}"
|
||||
"L+ /var/lib/grafana/dashboards/nvidia-gpu.json - - - - ${nvidiaDashboard}"
|
||||
"L+ /var/lib/grafana/dashboards/postgresql.json - - - - ${postgresqlDashboard}"
|
||||
"L+ /var/lib/grafana/dashboards/redis.json - - - - ${redisDashboard}"
|
||||
"L+ /var/lib/grafana/dashboards/docker-cadvisor.json - - - - ${dockerDashboard}"
|
||||
"L+ /var/lib/grafana/dashboards/caddy.json - - - - ${caddyDashboard}"
|
||||
"L+ /var/lib/grafana/dashboards/pihole.json - - - - ${piholeDashboard}"
|
||||
];
|
||||
|
||||
# Open firewall ports for Prometheus to scrape exporters
|
||||
networking.firewall = {
|
||||
# allowedTCPPorts = [
|
||||
# ports.node
|
||||
# ports.systemd
|
||||
# ports.process
|
||||
# ];
|
||||
|
||||
# Allow Prometheus and Grafana access from Tailscale network
|
||||
interfaces."tailscale0".allowedTCPPorts = [
|
||||
ports.prometheus
|
||||
ports.grafana
|
||||
ports.node
|
||||
ports.systemd
|
||||
ports.process
|
||||
ports.postgres
|
||||
ports.redis
|
||||
ports.cadvisor
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -18,8 +18,8 @@ in {
|
||||
enable = true;
|
||||
settings = {
|
||||
MusicFolder = "/media/music";
|
||||
ReverseProxyUserHeader = "Remote-User";
|
||||
ReverseProxyWhitelist = "@";
|
||||
"ExtAuth.TrustedSources" = "@";
|
||||
"ExtAuth.UserHeader" = "Remote-User";
|
||||
Address = "unix:${socket}";
|
||||
BaseUrl = "https://music.darksailor.dev";
|
||||
};
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings.PasswordAuthentication = false;
|
||||
settings.PermitRootLogin = "prohibit-password";
|
||||
settings.PermitRootLogin = "no";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
{...}: {
|
||||
services.resolved = {
|
||||
enable = true;
|
||||
dnssec = "true";
|
||||
dnsovertls = "true";
|
||||
domains = ["lemur-newton.ts.net"];
|
||||
fallbackDns = ["1.1.1.1"];
|
||||
settings = {
|
||||
Resolve = {
|
||||
DNSSEC = "true";
|
||||
DNSoverTLS = "true";
|
||||
Domains = ["lemur-newton.ts.net"];
|
||||
FallbackDNS = [];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
device,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
../../modules/nixos/substituters.nix
|
||||
];
|
||||
|
||||
users.extraUsers.servius.extraGroups = ["docker"];
|
||||
networking.firewall.enable = false;
|
||||
services.openssh.enable = true;
|
||||
@@ -16,14 +20,6 @@
|
||||
auto-optimise-store = true;
|
||||
extra-experimental-features = "nix-command flakes auto-allocate-uids";
|
||||
trusted-users = ["root" "remotebuilder" device.user];
|
||||
trusted-substituters = [
|
||||
"https://nix-community.cachix.org"
|
||||
"https://nixos-raspberrypi.cachix.org"
|
||||
];
|
||||
trusted-public-keys = [
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
"nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
|
||||
];
|
||||
};
|
||||
extraOptions = ''
|
||||
build-users-group = nixbld
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
services = {
|
||||
caddy = {
|
||||
enable = true;
|
||||
globalConfig = ''
|
||||
servers {
|
||||
metrics
|
||||
}
|
||||
'';
|
||||
extraConfig = ''
|
||||
(cloudflare) {
|
||||
tls {
|
||||
|
||||
@@ -27,20 +27,12 @@
|
||||
users.groups.jellyfin = {};
|
||||
|
||||
services = {
|
||||
# jellyseerr = {
|
||||
# enable = true;
|
||||
# package = unstablePkgs.jellyseerr;
|
||||
# };
|
||||
caddy = {
|
||||
# virtualHosts."jellyseerr.tsuba.darksailor.dev".extraConfig = ''
|
||||
# import cloudflare
|
||||
# reverse_proxy localhost:${builtins.toString config.services.jellyseerr.port}
|
||||
# '';
|
||||
virtualHosts."jellyfin.tsuba.darksailor.dev".extraConfig = ''
|
||||
import cloudflare
|
||||
reverse_proxy localhost:8096
|
||||
'';
|
||||
virtualHosts."media.darksailor.dev".extraConfig = ''
|
||||
virtualHosts."jellyfin.darksailor.dev".extraConfig = ''
|
||||
import cloudflare
|
||||
reverse_proxy localhost:8096
|
||||
'';
|
||||
|
||||
@@ -1,10 +1,40 @@
|
||||
{...}: {
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
# Port configurations
|
||||
ports = {
|
||||
# System exporters
|
||||
node = 9100;
|
||||
systemd = 9558;
|
||||
process = 9256;
|
||||
|
||||
# Infrastructure exporters
|
||||
cadvisor = 8080;
|
||||
caddy = 2019;
|
||||
|
||||
# Media exporters
|
||||
jellyfin = 9220;
|
||||
pihole = 9617;
|
||||
|
||||
# Servarr exporters (via exportarr)
|
||||
sonarr = 9707;
|
||||
radarr = 9708;
|
||||
lidarr = 9709;
|
||||
bazarr = 9710;
|
||||
|
||||
# Torrent
|
||||
deluge = 9354;
|
||||
};
|
||||
in {
|
||||
sops.secrets."pihole/password" = {};
|
||||
services = {
|
||||
prometheus = {
|
||||
exporters = {
|
||||
systemd = {
|
||||
enable = true;
|
||||
port = 9558;
|
||||
port = ports.systemd;
|
||||
};
|
||||
node = {
|
||||
enable = true;
|
||||
@@ -19,8 +49,10 @@
|
||||
"time"
|
||||
"uname"
|
||||
"vmstat"
|
||||
"diskstats"
|
||||
"cpu"
|
||||
];
|
||||
port = 9100;
|
||||
port = ports.node;
|
||||
};
|
||||
process = {
|
||||
enable = true;
|
||||
@@ -35,14 +67,142 @@
|
||||
};
|
||||
};
|
||||
|
||||
# Docker cAdvisor for container metrics
|
||||
virtualisation.oci-containers.containers.cadvisor = {
|
||||
image = "gcr.io/cadvisor/cadvisor:v0.49.1";
|
||||
ports = ["${toString ports.cadvisor}:8080"];
|
||||
volumes = [
|
||||
"/:/rootfs:ro"
|
||||
"/var/run:/var/run:ro"
|
||||
"/sys:/sys:ro"
|
||||
"/var/lib/docker/:/var/lib/docker:ro"
|
||||
"/dev/disk/:/dev/disk:ro"
|
||||
];
|
||||
extraOptions = [
|
||||
"--privileged"
|
||||
"--device=/dev/kmsg"
|
||||
];
|
||||
};
|
||||
|
||||
# Jellyfin - use built-in metrics endpoint at http://localhost:8096/metrics
|
||||
# No separate exporter needed - Prometheus will scrape directly
|
||||
|
||||
# Home Assistant - has built-in Prometheus integration
|
||||
# Configure in Home Assistant configuration.yaml:
|
||||
# prometheus:
|
||||
# namespace: homeassistant
|
||||
|
||||
# Pi-hole exporter
|
||||
# Uses sops-managed API token for authentication with Pi-hole v6
|
||||
# To set the token: edit secrets/secrets.yaml and replace the placeholder at pihole.api_token
|
||||
systemd.services.pihole-exporter = {
|
||||
description = "Pi-hole Prometheus Exporter";
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["network.target" "sops-nix.service"];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
DynamicUser = true;
|
||||
# Load API token from sops secret file
|
||||
LoadCredential = "ppassword:${config.sops.secrets."pihole/password".path}";
|
||||
ExecStart = ''
|
||||
${pkgs.bash}/bin/bash -c '${pkgs.prometheus-pihole-exporter}/bin/pihole-exporter \
|
||||
-pihole_hostname localhost \
|
||||
-pihole_port 8053 \
|
||||
-port ${toString ports.pihole} \
|
||||
-pihole_password $(cat ''${CREDENTIALS_DIRECTORY}/ppassword)'
|
||||
'';
|
||||
Restart = "on-failure";
|
||||
};
|
||||
};
|
||||
|
||||
# Exportarr for Sonarr
|
||||
# Disabled: needs API key configuration
|
||||
# systemd.services.exportarr-sonarr = {
|
||||
# description = "Exportarr Prometheus Exporter for Sonarr";
|
||||
# wantedBy = ["multi-user.target"];
|
||||
# after = ["network.target"];
|
||||
# serviceConfig = {
|
||||
# Type = "simple";
|
||||
# DynamicUser = true;
|
||||
# ExecStart = "${pkgs.exportarr}/bin/exportarr sonarr --port ${toString ports.sonarr} --url http://localhost:8989";
|
||||
# Restart = "on-failure";
|
||||
# };
|
||||
# };
|
||||
|
||||
# Exportarr for Radarr
|
||||
# Disabled: needs API key configuration
|
||||
# systemd.services.exportarr-radarr = {
|
||||
# description = "Exportarr Prometheus Exporter for Radarr";
|
||||
# wantedBy = ["multi-user.target"];
|
||||
# after = ["network.target"];
|
||||
# serviceConfig = {
|
||||
# Type = "simple";
|
||||
# DynamicUser = true;
|
||||
# ExecStart = "${pkgs.exportarr}/bin/exportarr radarr --port ${toString ports.radarr} --url http://localhost:7878";
|
||||
# Restart = "on-failure";
|
||||
# };
|
||||
# };
|
||||
|
||||
# Exportarr for Lidarr
|
||||
# Disabled: needs API key configuration
|
||||
# systemd.services.exportarr-lidarr = {
|
||||
# description = "Exportarr Prometheus Exporter for Lidarr";
|
||||
# wantedBy = ["multi-user.target"];
|
||||
# after = ["network.target"];
|
||||
# serviceConfig = {
|
||||
# Type = "simple";
|
||||
# DynamicUser = true;
|
||||
# ExecStart = "${pkgs.exportarr}/bin/exportarr lidarr --port ${toString ports.lidarr} --url http://localhost:8686";
|
||||
# Restart = "on-failure";
|
||||
# };
|
||||
# };
|
||||
|
||||
# Exportarr for Bazarr
|
||||
# Disabled: needs API key configuration
|
||||
# systemd.services.exportarr-bazarr = {
|
||||
# description = "Exportarr Prometheus Exporter for Bazarr";
|
||||
# wantedBy = ["multi-user.target"];
|
||||
# after = ["network.target"];
|
||||
# serviceConfig = {
|
||||
# Type = "simple";
|
||||
# DynamicUser = true;
|
||||
# ExecStart = "${pkgs.exportarr}/bin/exportarr bazarr --port ${toString ports.bazarr} --url http://localhost:6767";
|
||||
# Restart = "on-failure";
|
||||
# };
|
||||
# };
|
||||
|
||||
# Deluge exporter
|
||||
systemd.services.deluge-exporter = {
|
||||
description = "Deluge Prometheus Exporter";
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["network.target"];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
DynamicUser = true;
|
||||
ExecStart = "${pkgs.prometheus-deluge-exporter}/bin/deluge-exporter localhost:58846 --addr :${toString ports.deluge}";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
};
|
||||
|
||||
# Samba exporter - using a simple script to expose smbstatus metrics
|
||||
# For now, we'll skip this and can add later if needed
|
||||
|
||||
# Open firewall ports for Prometheus exporters
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [
|
||||
9100 # node exporter
|
||||
9256 # process exporter
|
||||
9558 # systemd exporter
|
||||
9134 # zfs exporter
|
||||
9633 # smartctl exporter
|
||||
# Allow from Tailscale network
|
||||
interfaces."tailscale0".allowedTCPPorts = [
|
||||
ports.node
|
||||
ports.systemd
|
||||
ports.process
|
||||
ports.cadvisor
|
||||
ports.caddy
|
||||
ports.jellyfin
|
||||
ports.pihole
|
||||
# ports.sonarr # Disabled - needs API key
|
||||
# ports.radarr # Disabled - needs API key
|
||||
# ports.lidarr # Disabled - needs API key
|
||||
# ports.bazarr # Disabled - needs API key
|
||||
ports.deluge
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
{lib, ...}: {
|
||||
{...}: {
|
||||
services.resolved = {
|
||||
enable = false;
|
||||
# dnssec = "true";
|
||||
# domains = ["~." "lemur-newton.ts.net"];
|
||||
# fallbackDns = ["1.1.1.1#one.one.one.one" "1.0.0.1#one.one.one.one"];
|
||||
fallbackDns = [];
|
||||
# dnsovertls = "true";
|
||||
};
|
||||
networking.nameservers = [];
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
systemd.network.wait-online.enable = false;
|
||||
|
||||
fileSystems."/home".neededForBoot = true;
|
||||
boot.loader.raspberryPi.bootloader = "kernel";
|
||||
boot.loader.raspberry-pi.bootloader = "kernel";
|
||||
|
||||
system.nixos.tags = let
|
||||
cfg = config.boot.loader.raspberryPi;
|
||||
cfg = config.boot.loader.raspberry-pi;
|
||||
in [
|
||||
"raspberry-pi-${cfg.variant}"
|
||||
cfg.bootloader
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
From 3f49f2d9783151520ac0b9a588581454b60fd2ad Mon Sep 17 00:00:00 2001
|
||||
From: Lin Xianyi <iynaix@gmail.com>
|
||||
Date: Sat, 2 Aug 2025 01:15:23 +0800
|
||||
Subject: [PATCH] orca-slicer: remove dependency on libsoup2
|
||||
|
||||
---
|
||||
pkgs/by-name/or/orca-slicer/package.nix | 13 +++++++++++--
|
||||
...stream-CMakeLists-Link-against-webkit2gtk-.patch | 7 +++----
|
||||
2 files changed, 14 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/pkgs/by-name/or/orca-slicer/package.nix b/pkgs/by-name/or/orca-slicer/package.nix
|
||||
index 7e817859988acd..e1376110dcd38e 100644
|
||||
--- a/pkgs/by-name/or/orca-slicer/package.nix
|
||||
+++ b/pkgs/by-name/or/orca-slicer/package.nix
|
||||
@@ -35,7 +35,7 @@
|
||||
pcre,
|
||||
systemd,
|
||||
tbb_2021,
|
||||
- webkitgtk_4_0,
|
||||
+ webkitgtk_4_1,
|
||||
wxGTK31,
|
||||
xorg,
|
||||
libnoise,
|
||||
@@ -47,8 +47,17 @@ let
|
||||
withCurl = true;
|
||||
withPrivateFonts = true;
|
||||
withWebKit = true;
|
||||
+ webkitgtk_4_0 = webkitgtk_4_1;
|
||||
}).overrideAttrs
|
||||
(old: {
|
||||
+ src = fetchFromGitHub {
|
||||
+ owner = "SoftFever";
|
||||
+ repo = "Orca-deps-wxWidgets";
|
||||
+ rev = "acdc6db5064274405c323c3823eedf559bbe0474";
|
||||
+ hash = "sha256-Rt03VK0AzZyROkya0zRKpckS/OSa74pLTNbZoJiitfo=";
|
||||
+ fetchSubmodules = true;
|
||||
+ };
|
||||
+
|
||||
configureFlags = old.configureFlags ++ [
|
||||
# Disable noisy debug dialogs
|
||||
"--enable-debug=no"
|
||||
@@ -112,7 +121,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
openvdb
|
||||
pcre
|
||||
tbb_2021
|
||||
- webkitgtk_4_0
|
||||
+ webkitgtk_4_1
|
||||
wxGTK'
|
||||
xorg.libX11
|
||||
opencv.cxxdev
|
||||
diff --git a/pkgs/by-name/or/orca-slicer/patches/0001-not-for-upstream-CMakeLists-Link-against-webkit2gtk-.patch b/pkgs/by-name/or/orca-slicer/patches/0001-not-for-upstream-CMakeLists-Link-against-webkit2gtk-.patch
|
||||
index 15f1bf8f0b59e1..8cf3345131449f 100644
|
||||
--- a/pkgs/by-name/or/orca-slicer/patches/0001-not-for-upstream-CMakeLists-Link-against-webkit2gtk-.patch
|
||||
+++ b/pkgs/by-name/or/orca-slicer/patches/0001-not-for-upstream-CMakeLists-Link-against-webkit2gtk-.patch
|
||||
@@ -20,15 +20,14 @@ index 9c5cb96..e92a0e3 100644
|
||||
@@ -175,6 +175,11 @@ if (WIN32)
|
||||
target_link_libraries(BambuStudio_app_gui PRIVATE boost_headeronly)
|
||||
endif ()
|
||||
-
|
||||
+
|
||||
+# We link against webkit2gtk symbols in src/slic3r/GUI/Widgets/WebView.cpp
|
||||
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
-+ target_link_libraries(libslic3r_gui "-lwebkit2gtk-4.0")
|
||||
++ target_link_libraries(libslic3r_gui "-lwebkit2gtk-4.1")
|
||||
+endif ()
|
||||
+
|
||||
# Link the resources dir to where Slic3r GUI expects it
|
||||
set(output_dlls_Release "")
|
||||
set(output_dlls_Debug "")
|
||||
---
|
||||
+--
|
||||
2.38.1
|
||||
-
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user