forked from aylac.top/nixcfg
this repo has no description

i love copying stuff. also damn i gotta fix this hooks thing it doesnt work fully properly in here

+3
.envrc
···
+
# shellcheck disable=SC2148
+
export DIRENV_WARN_TIMEOUT=0
+
use flake
+51
.github/workflows/build-nix.yml
···
+
concurrency:
+
cancel-in-progress: true
+
group: ${{ github.workflow }}-${{ github.ref }}
+
jobs:
+
build-devShell-default:
+
runs-on: ubuntu-latest
+
steps:
+
- uses: actions/checkout@main
+
with:
+
fetch-depth: 1
+
- uses: DeterminateSystems/nix-installer-action@main
+
- uses: cachix/cachix-action@master
+
with:
+
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
+
name: ayla6
+
- name: Build devShell default
+
run: nix build --accept-flake-config --print-out-paths .#devShells.x86_64-linux.default
+
build-package-gen-files:
+
runs-on: ubuntu-latest
+
steps:
+
- uses: actions/checkout@main
+
with:
+
fetch-depth: 1
+
- uses: DeterminateSystems/nix-installer-action@main
+
- uses: cachix/cachix-action@master
+
with:
+
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
+
name: ayla6
+
- name: Build package gen-files
+
run: nix build --accept-flake-config --print-out-paths .#packages.x86_64-linux.gen-files
+
build-package-render-workflows:
+
runs-on: ubuntu-latest
+
steps:
+
- uses: actions/checkout@main
+
with:
+
fetch-depth: 1
+
- uses: DeterminateSystems/nix-installer-action@main
+
- uses: cachix/cachix-action@master
+
with:
+
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
+
name: ayla6
+
- name: Build package render-workflows
+
run: nix build --accept-flake-config --print-out-paths .#packages.x86_64-linux.render-workflows
+
name: build-nix
+
'on':
+
push:
+
paths:
+
- flake.lock
+
- flake.nix
+
- flake/
+
workflow_dispatch: {}
+48
.github/workflows/build-nixos.yml
···
+
concurrency:
+
cancel-in-progress: true
+
group: ${{ github.workflow }}-${{ github.ref }}
+
jobs:
+
build-morgana:
+
runs-on: ubuntu-latest
+
steps:
+
- name: Free Disk Space (Ubuntu)
+
uses: jlumbroso/free-disk-space@main
+
- name: Checkout
+
uses: actions/checkout@main
+
with:
+
fetch-depth: 1
+
- name: Install Nix
+
uses: DeterminateSystems/nix-installer-action@main
+
- name: Cachix
+
uses: cachix/cachix-action@master
+
with:
+
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
+
name: ayla6
+
- name: Build morgana
+
run: nix build --accept-flake-config --print-out-paths .#nixosConfigurations.morgana.config.system.build.toplevel
+
build-nanpi:
+
runs-on: ubuntu-latest
+
steps:
+
- name: Free Disk Space (Ubuntu)
+
uses: jlumbroso/free-disk-space@main
+
- name: Checkout
+
uses: actions/checkout@main
+
with:
+
fetch-depth: 1
+
- name: Install Nix
+
uses: DeterminateSystems/nix-installer-action@main
+
- name: Cachix
+
uses: cachix/cachix-action@master
+
with:
+
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
+
name: ayla6
+
- name: Build nanpi
+
run: nix build --accept-flake-config --print-out-paths .#nixosConfigurations.nanpi.config.system.build.toplevel
+
name: build-nixos
+
'on':
+
push:
+
paths-ignore:
+
- '**/*.md'
+
- .github/**
+
- _img/**
+
workflow_dispatch: {}
+21
.github/workflows/check-nix.yml
···
+
concurrency:
+
cancel-in-progress: true
+
group: ${{ github.workflow }}-${{ github.ref }}
+
jobs:
+
check-flake:
+
runs-on: ubuntu-latest
+
steps:
+
- uses: actions/checkout@main
+
with:
+
fetch-depth: 1
+
- uses: DeterminateSystems/nix-installer-action@main
+
- name: Check flake evaluation
+
run: nix -Lv flake check --all-systems
+
name: check-nix
+
'on':
+
push:
+
paths-ignore:
+
- '**/*.md'
+
- .github/**
+
- _img/**
+
workflow_dispatch: {}
+56
.github/workflows/deploy-tailscale-acls.yml
···
+
jobs:
+
acls:
+
runs-on: ubuntu-latest
+
steps:
+
- uses: actions/checkout@main
+
with:
+
fetch-depth: 1
+
- uses: DeterminateSystems/nix-installer-action@main
+
- name: Convert .#tailscaleACLs to tailscale.json
+
run: nix eval --json .#tailscaleACLs > tailscale.json
+
- if: |-
+
github.event_name == 'push' ||
+
(github.event_name == 'workflow_dispatch' &&
+
github.event.inputs.action == 'deploy')
+
name: Deploy ACL
+
uses: tailscale/gitops-acl-action@v1
+
with:
+
action: apply
+
api-key: ${{ secrets.TS_API_KEY }}
+
policy-file: tailscale.json
+
tailnet: ayla6.github
+
- if: |-
+
github.event_name == 'pull_request' ||
+
(github.event_name == 'workflow_dispatch' &&
+
github.event.inputs.action == 'test')
+
name: Test ACL
+
uses: tailscale/gitops-acl-action@v1
+
with:
+
action: test
+
api-key: ${{ secrets.TS_API_KEY }}
+
policy-file: tailscale.json
+
tailnet: ayla6.github
+
name: deploy-tailscale-acls
+
'on':
+
pull_request:
+
branches:
+
- master
+
paths:
+
- .github/workflows/deploy-tailscale-acls.yml
+
- flake/tailscale.nix
+
push:
+
branches:
+
- master
+
paths:
+
- .github/workflows/deploy-tailscale-acls.yml
+
- flake/tailscale.nix
+
workflow_dispatch:
+
inputs:
+
action:
+
default: deploy
+
description: Which action to run
+
options:
+
- deploy
+
- test
+
required: true
+
type: choice
+26
.github/workflows/update-inputs.yml
···
+
jobs:
+
update-flake-lock:
+
runs-on: ubuntu-latest
+
steps:
+
- uses: actions/checkout@main
+
with:
+
fetch-depth: 1
+
ref: ${{ github.head_ref }}
+
- name: Setup Git
+
run: |-
+
git config --local user.name "github-actions[bot]"
+
git config --local user.email "github-actions[bot]@users.noreply.github.com"
+
- uses: DeterminateSystems/nix-installer-action@main
+
- uses: DeterminateSystems/update-flake-lock@main
+
with:
+
pr-assignees: ayla6
+
pr-labels: |-
+
dependencies
+
automated
+
pr-title: 'flake: update inputs'
+
token: ${{ secrets.FLAKE_UPDATE_PAT }}
+
name: update-inputs
+
'on':
+
schedule:
+
- cron: 0 6 * * 2,5
+
workflow_dispatch: {}
-1
.gitignore
···
result
-
secrets/fonts/emoji
+1
.pre-commit-config.yaml
···
+
/nix/store/2425841fzkif6s3a5s1kpmzswzgp03cv-pre-commit-config.json
+83
.zed/settings.json
···
+
{
+
"auto_install_extensions": {
+
"basher": true,
+
"nix": true
+
},
+
"languages": {
+
"JSON": {
+
"format_on_save": "on",
+
"formatter": {
+
"external": {
+
"arguments": [
+
"--stdin-filepath",
+
"{buffer_path}"
+
],
+
"command": "/nix/store/qa30pcbdqczmqnybhshlkjh1qxaac9sb-prettier-3.6.2/bin/prettier"
+
}
+
}
+
},
+
"Markdown": {
+
"format_on_save": "on",
+
"formatter": {
+
"external": {
+
"arguments": [
+
"--stdin-filepath",
+
"{buffer_path}"
+
],
+
"command": "/nix/store/qa30pcbdqczmqnybhshlkjh1qxaac9sb-prettier-3.6.2/bin/prettier"
+
}
+
}
+
},
+
"Nix": {
+
"format_on_save": "on",
+
"formatter": "language_server",
+
"language_servers": [
+
"nixd"
+
]
+
},
+
"Shell Script": {
+
"format_on_save": "on",
+
"formatter": {
+
"external": {
+
"arguments": [
+
"--filename",
+
"{buffer_path}",
+
"-i",
+
"2"
+
],
+
"command": "/nix/store/d6s6915z6g0lsffym2ibcb8yjxrvsav6-shfmt-3.12.0/bin/shfmt"
+
}
+
},
+
"hard_tabs": false,
+
"tab_size": 2
+
},
+
"YAML": {
+
"format_on_save": "on",
+
"formatter": {
+
"external": {
+
"arguments": [
+
"--stdin-filepath",
+
"{buffer_path}"
+
],
+
"command": "/nix/store/qa30pcbdqczmqnybhshlkjh1qxaac9sb-prettier-3.6.2/bin/prettier"
+
}
+
}
+
}
+
},
+
"lsp": {
+
"nixd": {
+
"binary": {
+
"path": "/nix/store/58ghdm4idf5yql6k4d68cb4gj1qy85pd-nixd-2.6.4/bin/nixd"
+
},
+
"settings": {
+
"formatting": {
+
"command": [
+
"/nix/store/rk7b4ldkp4ssblpsa1x56kl8xf94kd1a-alejandra-4.0.0/bin/alejandra",
+
"--quiet",
+
"--"
+
]
+
}
+
}
+
}
+
}
+
}
+1 -1
README.md
···
My NixOS config!
-
Heavily inspired/stolen from https://github.com/alyraffauf/nixcfg, aly you're really cool!!!
+
a loooooot of stuff here is copied from https://github.com/alyraffauf/nixcfg, aly you're really cool!!!
+190 -17
flake.lock
···
{
"nodes": {
+
"actions-nix": {
+
"inputs": {
+
"flake-parts": "flake-parts",
+
"git-hooks": [
+
"git-hooks-nix"
+
],
+
"nixpkgs": [
+
"nixpkgs"
+
]
+
},
+
"locked": {
+
"lastModified": 1754669222,
+
"narHash": "sha256-4PbaZ5m2boVVzgSEGp+/HdcyHhW7UZkw/Wji5k4ICGw=",
+
"owner": "alyraffauf",
+
"repo": "actions.nix",
+
"rev": "f2c78ac1a9cfab8f8bce5aa1fd72e221395f0798",
+
"type": "github"
+
},
+
"original": {
+
"owner": "alyraffauf",
+
"repo": "actions.nix",
+
"type": "github"
+
}
+
},
"agenix": {
"inputs": {
"darwin": "darwin",
···
"type": "github"
}
},
+
"disko": {
+
"inputs": {
+
"nixpkgs": [
+
"nixpkgs"
+
]
+
},
+
"locked": {
+
"lastModified": 1754971456,
+
"narHash": "sha256-p04ZnIBGzerSyiY2dNGmookCldhldWAu03y0s3P8CB0=",
+
"owner": "nix-community",
+
"repo": "disko",
+
"rev": "8246829f2e675a46919718f9a64b71afe3bfb22d",
+
"type": "github"
+
},
+
"original": {
+
"owner": "nix-community",
+
"repo": "disko",
+
"type": "github"
+
}
+
},
+
"files": {
+
"locked": {
+
"lastModified": 1753414454,
+
"narHash": "sha256-IMdHZjva8z354/TAjkKqgHJ0k7qGZeaf460EPq/awDA=",
+
"owner": "alyraffauf",
+
"repo": "files",
+
"rev": "fdfd673e34933a6836e6dccda820e448300e4c05",
+
"type": "github"
+
},
+
"original": {
+
"owner": "alyraffauf",
+
"repo": "files",
+
"type": "github"
+
}
+
},
+
"firefox-onebar": {
+
"flake": false,
+
"locked": {
+
"narHash": "sha256-kkg+wplvJvOmO2FseZuF/P2HBh+r/uSEEb9TD6RSA54=",
+
"type": "file",
+
"url": "https://git.gay/freeplay/Firefox-Onebar/raw/branch/waf/onebar.css"
+
},
+
"original": {
+
"type": "file",
+
"url": "https://git.gay/freeplay/Firefox-Onebar/raw/branch/waf/onebar.css"
+
}
+
},
"flake-compat": {
"flake": false,
"locked": {
+
"lastModified": 1747046372,
+
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
+
"owner": "edolstra",
+
"repo": "flake-compat",
+
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
+
"type": "github"
+
},
+
"original": {
+
"owner": "edolstra",
+
"repo": "flake-compat",
+
"type": "github"
+
}
+
},
+
"flake-compat_2": {
+
"flake": false,
+
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
···
},
"flake-parts": {
"inputs": {
+
"nixpkgs-lib": [
+
"actions-nix",
+
"nixpkgs"
+
]
+
},
+
"locked": {
+
"lastModified": 1738453229,
+
"narHash": "sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm+zmZ7vxbJdo=",
+
"owner": "hercules-ci",
+
"repo": "flake-parts",
+
"rev": "32ea77a06711b758da0ad9bd6a844c5740a87abd",
+
"type": "github"
+
},
+
"original": {
+
"owner": "hercules-ci",
+
"repo": "flake-parts",
+
"type": "github"
+
}
+
},
+
"flake-parts_2": {
+
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
···
"type": "github"
}
},
-
"flake-parts_2": {
+
"flake-parts_3": {
"inputs": {
"nixpkgs-lib": [
"lanzaboote",
···
"type": "github"
}
},
-
"flake-parts_3": {
+
"flake-parts_4": {
"inputs": {
"nixpkgs-lib": [
"nur",
···
"type": "github"
}
},
+
"git-hooks-nix": {
+
"inputs": {
+
"flake-compat": "flake-compat",
+
"gitignore": "gitignore",
+
"nixpkgs": [
+
"nixpkgs"
+
]
+
},
+
"locked": {
+
"lastModified": 1754416808,
+
"narHash": "sha256-c6yg0EQ9xVESx6HGDOCMcyRSjaTpNJP10ef+6fRcofA=",
+
"owner": "cachix",
+
"repo": "git-hooks.nix",
+
"rev": "9c52372878df6911f9afc1e2a1391f55e4dfc864",
+
"type": "github"
+
},
+
"original": {
+
"owner": "cachix",
+
"repo": "git-hooks.nix",
+
"type": "github"
+
}
+
},
"gitignore": {
+
"inputs": {
+
"nixpkgs": [
+
"git-hooks-nix",
+
"nixpkgs"
+
]
+
},
+
"locked": {
+
"lastModified": 1709087332,
+
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+
"owner": "hercules-ci",
+
"repo": "gitignore.nix",
+
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+
"type": "github"
+
},
+
"original": {
+
"owner": "hercules-ci",
+
"repo": "gitignore.nix",
+
"type": "github"
+
}
+
},
+
"gitignore_2": {
"inputs": {
"nixpkgs": [
"lanzaboote",
···
]
},
"locked": {
-
"lastModified": 1754842705,
-
"narHash": "sha256-2vvncPLsBWV6dRM5LfGHMGYZ+vzqRDqSPBzxPAS0R/A=",
+
"lastModified": 1754974548,
+
"narHash": "sha256-XMjUjKD/QRPcqUnmSDczSYdw46SilnG0+wkho654DFM=",
"owner": "nix-community",
"repo": "home-manager",
-
"rev": "91586008a23c01cc32894ee187dca8c0a7bd20a4",
+
"rev": "27a26be51ff0162a8f67660239f9407dba68d7c5",
"type": "github"
},
"original": {
···
"lanzaboote": {
"inputs": {
"crane": "crane",
-
"flake-compat": "flake-compat",
-
"flake-parts": "flake-parts_2",
+
"flake-compat": "flake-compat_2",
+
"flake-parts": "flake-parts_3",
"nixpkgs": [
"nixpkgs"
],
···
},
"nixpkgs-unstable": {
"locked": {
-
"lastModified": 1754800730,
-
"narHash": "sha256-HfVZCXic9XLBgybP0318ym3cDnGwBs/+H5MgxFVYF4I=",
+
"lastModified": 1754956457,
+
"narHash": "sha256-T2+GFBeim9Nd1D1sTytRpgo8E2RwlTwHmQUmewBceo4=",
"owner": "NixOS",
"repo": "nixpkgs",
-
"rev": "641d909c4a7538f1539da9240dedb1755c907e40",
+
"rev": "5a983011e0f4b3b286aaa73e011ce32b1449a528",
"type": "github"
},
"original": {
···
},
"nur": {
"inputs": {
-
"flake-parts": "flake-parts_3",
+
"flake-parts": "flake-parts_4",
"nixpkgs": "nixpkgs_2"
},
"locked": {
-
"lastModified": 1754883319,
-
"narHash": "sha256-DUddNJ5q6sxzQ8SZaWt2KgNIATwSviQnpoeoUWCGopY=",
+
"lastModified": 1754996709,
+
"narHash": "sha256-IOFqbuRuumZFG9s/c8pablo4AL4jzXdjr86OvMxINkE=",
"owner": "nix-community",
"repo": "NUR",
-
"rev": "f657c3820a06481f3a037ffba0e69d01f2cedfb2",
+
"rev": "ccb6cee3ff1f3b002d95144230d3908bcdf1b4d8",
"type": "github"
},
"original": {
···
"lanzaboote",
"flake-compat"
],
-
"gitignore": "gitignore",
+
"gitignore": "gitignore_2",
"nixpkgs": [
"lanzaboote",
"nixpkgs"
···
},
"root": {
"inputs": {
+
"actions-nix": "actions-nix",
"agenix": "agenix",
-
"flake-parts": "flake-parts",
+
"disko": "disko",
+
"files": "files",
+
"firefox-onebar": "firefox-onebar",
+
"flake-parts": "flake-parts_2",
+
"git-hooks-nix": "git-hooks-nix",
"home-manager": "home-manager_2",
"lanzaboote": "lanzaboote",
"nixpkgs": "nixpkgs",
"nixpkgs-unstable": "nixpkgs-unstable",
-
"nur": "nur"
+
"nur": "nur",
+
"secrets": "secrets"
}
},
"rust-overlay": {
···
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
+
"type": "github"
+
}
+
},
+
"secrets": {
+
"flake": false,
+
"locked": {
+
"lastModified": 1754995747,
+
"narHash": "sha256-dG8juVoHNl3MVLZ7CODm6BNFVTrBGSTEu5fmf0b2O3o=",
+
"owner": "ayla6",
+
"repo": "secrets",
+
"rev": "4fb41ba578c06d5b93ca4f742fb8141a98ee5b51",
+
"type": "github"
+
},
+
"original": {
+
"owner": "ayla6",
+
"repo": "secrets",
"type": "github"
}
},
+33
flake.nix
···
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+
actions-nix = {
+
url = "github:alyraffauf/actions.nix";
+
+
inputs = {
+
git-hooks.follows = "git-hooks-nix";
+
nixpkgs.follows = "nixpkgs";
+
};
+
};
+
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs";
};
+
disko = {
+
url = "github:nix-community/disko";
+
inputs.nixpkgs.follows = "nixpkgs";
+
};
+
+
files.url = "github:alyraffauf/files";
flake-parts.url = "github:hercules-ci/flake-parts";
+
git-hooks-nix = {
+
url = "github:cachix/git-hooks.nix";
+
inputs.nixpkgs.follows = "nixpkgs";
+
};
+
home-manager = {
url = "github:nix-community/home-manager/master";
inputs.nixpkgs.follows = "nixpkgs";
···
};
nur.url = "github:nix-community/NUR";
+
+
secrets = {
+
url = "github:ayla6/secrets";
+
flake = false;
+
};
+
+
firefox-onebar = {
+
url = "https://git.gay/freeplay/Firefox-Onebar/raw/branch/waf/onebar.css";
+
flake = false;
+
};
};
nixConfig = {
···
imports = [
./modules/flake
+
inputs.actions-nix.flakeModules.default
+
inputs.files.flakeModules.default
+
#inputs.git-hooks-nix.flakeModule
inputs.home-manager.flakeModules.home-manager
];
};
+1 -1
homes/ayla/default.nix
···
mpv.enable = true;
obs-studio.enable = true;
zed-editor.enable = true;
+
ssh.enable = true;
};
profiles = {
···
services = {
aria2.enable = true;
-
syncthing.enable = true;
};
style = {
+26 -2
hosts/morgana/default.nix
···
-
{self, ...}: {
+
{
+
self,
+
config,
+
...
+
}: {
imports = [
./home.nix
+
./secrets.nix
self.nixosModules.locale-en-gb
];
···
profiles = {
base.enable = true;
workstation.enable = true;
+
btrfs.enable = true;
+
autoUpgrade = {
+
enable = true;
+
operation = "switch";
+
};
};
desktop.gnome.enable = true;
services = {
-
tailscale.enable = true;
+
# i can't make caddy work :(
+
#caddy.enable = true;
+
tailscale = {
+
enable = true;
+
# i can't make caddy work :(
+
enableCaddy = false;
+
operator = "ayla";
+
};
aria2.enable = true;
+
syncthing = {
+
enable = true;
+
certFile = config.age.secrets.syncthingCert.path;
+
keyFile = config.age.secrets.syncthingKey.path;
+
user = "ayla";
+
};
};
style.fonts.enable = true;
};
myUsers = {
ayla = {
+
enable = true;
password = "REDACTED";
};
};
+7
hosts/morgana/secrets.nix
···
+
{self, ...}: {
+
age.secrets = {
+
tailscaleAuthKey.file = "${self.inputs.secrets}/tailscale/auth.age";
+
syncthingCert.file = "${self.inputs.secrets}/ayla/syncthing/morgana/cert.age";
+
syncthingKey.file = "${self.inputs.secrets}/ayla/syncthing/morgana/key.age";
+
};
+
}
+1
hosts/nanpi/README.md
···
+
my server that is actually an old weak laptop
+69
hosts/nanpi/default.nix
···
+
{
+
self,
+
config,
+
...
+
}: {
+
imports = [
+
./home.nix
+
./secrets.nix
+
./services.nix
+
self.nixosModules.locale-en-gb
+
self.diskoConfigurations.lvm-ext4
+
];
+
+
networking.hostName = "nanpi";
+
system.stateVersion = "25.05";
+
time.timeZone = "America/Sao_Paulo";
+
myHardware.hp.theRedOne.enable = true;
+
+
myNixOS = {
+
programs = {
+
systemd-boot.enable = true;
+
nix.enable = true;
+
};
+
profiles = {
+
base.enable = true;
+
server.enable = true;
+
autoUpgrade = {
+
enable = true;
+
operation = "boot";
+
};
+
backups.enable = true;
+
};
+
services = {
+
caddy.enable = true;
+
tailscale = {
+
enable = true;
+
enableCaddy = false;
+
operator = "ayla";
+
};
+
syncthing = {
+
enable = true;
+
certFile = config.age.secrets.syncthingCert.path;
+
keyFile = config.age.secrets.syncthingKey.path;
+
user = "ayla";
+
};
+
qbittorrent = {
+
inherit (config.mySnippets.tailnet.networkMap.qbittorrent) port;
+
enable = true;
+
};
+
};
+
};
+
+
myUsers = {
+
ayla = {
+
enable = true;
+
password = "REDACTED";
+
};
+
};
+
+
boot.initrd = {
+
availableKernelModules = [
+
"xhci_pci"
+
"ahci"
+
"usb_storage"
+
"sd_mod"
+
"rtsx_pci_sdmmc"
+
];
+
};
+
}
+45
hosts/nanpi/home.nix
···
+
{self, ...}: {
+
home-manager.users.ayla = {pkgs, ...}: {
+
imports = [
+
self.homeModules.default
+
self.inputs.agenix.homeManagerModules.default
+
];
+
+
age.secrets.rclone.file = "${self.inputs.secrets}/rclone.age";
+
+
home = {
+
homeDirectory = "/home/ayla";
+
+
packages = with pkgs; [
+
curl
+
rclone
+
restic
+
];
+
+
stateVersion = "25.05";
+
username = "ayla";
+
};
+
programs = {
+
helix = {
+
enable = true;
+
defaultEditor = true;
+
};
+
+
micro = {
+
enable = true;
+
};
+
+
home-manager.enable = true;
+
};
+
+
myHome = {
+
programs = {
+
git.enable = true;
+
ssh.enable = true;
+
fastfetch.enable = true;
+
};
+
+
profiles.shell.enable = true;
+
};
+
};
+
}
+12
hosts/nanpi/secrets.nix
···
+
{self, ...}: {
+
age.secrets = {
+
cloudflareCertificate.file = "${self.inputs.secrets}/cloudflare/certificate.age";
+
cloudflareCredentials.file = "${self.inputs.secrets}/cloudflare/credentials.age";
+
pds.file = "${self.inputs.secrets}/pds.age";
+
rclone.file = "${self.inputs.secrets}/rclone.age";
+
tailscaleAuthKey.file = "${self.inputs.secrets}/tailscale/auth.age";
+
syncthingCert.file = "${self.inputs.secrets}/ayla/syncthing/nanpi/cert.age";
+
syncthingKey.file = "${self.inputs.secrets}/ayla/syncthing/nanpi/key.age";
+
resticPassword.file = "${self.inputs.secrets}/restic-passwd.age";
+
};
+
}
+55
hosts/nanpi/services.nix
···
+
{config, ...}: let
+
dataDirectory = "/home/Data";
+
in {
+
services = {
+
pds = {
+
enable = true;
+
environmentFiles = [config.age.secrets.pds.path];
+
pdsadmin.enable = true;
+
settings = {
+
PDS_HOSTNAME = "pds.aylac.top";
+
};
+
};
+
+
cloudflared = {
+
enable = true;
+
certificateFile = config.age.secrets.cloudflareCertificate.path;
+
tunnels = {
+
"3c012d05-cc92-4598-a726-909088e6588c" = {
+
certificateFile = config.age.secrets.cloudflareCertificate.path;
+
credentialsFile = config.age.secrets.cloudflareCredentials.path;
+
default = "http_status:404";
+
ingress = {
+
"pds.aylac.top" = "http://localhost:3000";
+
};
+
};
+
};
+
};
+
+
caddy.virtualHosts = {
+
"${config.mySnippets.tailnet.networkMap.jellyfin.vHost}" = {
+
extraConfig = ''
+
bind tailscale/jellyfin
+
encode zstd gzip
+
reverse_proxy ${config.mySnippets.tailnet.networkMap.jellyfin.hostName}:${toString config.mySnippets.tailnet.networkMap.jellyfin.port} {
+
flush_interval -1
+
}
+
'';
+
};
+
+
"${config.mySnippets.tailnet.networkMap.qbittorrent.vHost}" = {
+
extraConfig = ''
+
bind tailscale/qbittorrent
+
encode zstd gzip
+
reverse_proxy ${config.mySnippets.tailnet.networkMap.qbittorrent.hostName}:${toString config.mySnippets.tailnet.networkMap.qbittorrent.port}
+
'';
+
};
+
};
+
+
jellyfin = {
+
enable = true;
+
openFirewall = true;
+
dataDir = "${dataDirectory}/jellyfin";
+
};
+
};
+
}
+82
modules/disko/btrfs-subvolumes/default.nix
···
+
{
+
config,
+
lib,
+
...
+
}: {
+
options.myDisko.installDrive = lib.mkOption {
+
description = "Disk to install NixOS to.";
+
default = "/dev/nvme0n1";
+
type = lib.types.str;
+
};
+
+
config = {
+
assertions = [
+
{
+
assertion = config.myDisko.installDrive != "";
+
message = "config.myDisko.installDrive cannot be empty.";
+
}
+
];
+
+
disko.devices = {
+
disk = {
+
main = {
+
type = "disk";
+
device = config.myDisko.installDrive;
+
+
content = {
+
type = "gpt";
+
+
partitions = {
+
ESP = {
+
content = {
+
format = "vfat";
+
mountOptions = ["umask=0077"];
+
mountpoint = "/boot";
+
type = "filesystem";
+
};
+
+
end = "1024M";
+
name = "ESP";
+
priority = 1;
+
start = "1M";
+
type = "EF00";
+
};
+
+
root = {
+
size = "100%";
+
content = {
+
type = "btrfs";
+
extraArgs = ["-f"]; # Override existing partition
+
+
subvolumes = {
+
"/rootfs" = {
+
mountOptions = ["compress=zstd" "noatime"];
+
mountpoint = "/";
+
};
+
+
"/home" = {
+
mountOptions = ["compress=zstd" "noatime"];
+
mountpoint = "/home";
+
};
+
+
"/home/.snapshots" = {
+
mountOptions = ["compress=zstd" "noatime"];
+
mountpoint = "/home/.snapshots";
+
};
+
+
"/nix" = {
+
mountOptions = ["compress=zstd" "noatime"];
+
mountpoint = "/nix";
+
};
+
};
+
+
mountpoint = "/partition-root";
+
};
+
};
+
};
+
};
+
};
+
};
+
};
+
};
+
}
+92
modules/disko/luks-btrfs-subvolumes/default.nix
···
+
{
+
config,
+
lib,
+
...
+
}: {
+
options.myDisko.installDrive = lib.mkOption {
+
description = "Disk to install NixOS to.";
+
default = "/dev/nvme0n1";
+
type = lib.types.str;
+
};
+
+
config = {
+
assertions = [
+
{
+
assertion = config.myDisko.installDrive != "";
+
message = "config.myDisko.installDrive cannot be empty.";
+
}
+
];
+
+
disko.devices = {
+
disk = {
+
vdb = {
+
type = "disk";
+
device = config.myDisko.installDrive;
+
+
content = {
+
type = "gpt";
+
+
partitions = {
+
ESP = {
+
content = {
+
format = "vfat";
+
+
mountOptions = [
+
"defaults"
+
"umask=0077"
+
];
+
+
mountpoint = "/boot";
+
type = "filesystem";
+
};
+
+
size = "1024M";
+
type = "EF00";
+
};
+
+
luks = {
+
size = "100%";
+
content = {
+
type = "luks";
+
name = "crypted";
+
+
content = {
+
type = "btrfs";
+
extraArgs = ["-f"];
+
+
subvolumes = {
+
"/home" = {
+
mountpoint = "/home";
+
mountOptions = ["compress=zstd" "noatime"];
+
};
+
+
"/home/.snapshots" = {
+
mountOptions = ["compress=zstd" "noatime"];
+
mountpoint = "/home/.snapshots";
+
};
+
+
"/nix" = {
+
mountpoint = "/nix";
+
mountOptions = ["compress=zstd" "noatime"];
+
};
+
+
"persist" = {
+
mountpoint = "/persist";
+
mountOptions = ["compress=zstd" "noatime"];
+
};
+
+
"/root" = {
+
mountpoint = "/";
+
mountOptions = ["compress=zstd" "noatime"];
+
};
+
};
+
};
+
};
+
};
+
};
+
};
+
};
+
};
+
};
+
};
+
}
+74
modules/disko/lvm-ext4/default.nix
···
+
{
+
config,
+
lib,
+
...
+
}: {
+
options.myDisko.installDrive = lib.mkOption {
+
description = "Disk to install NixOS to.";
+
default = "/dev/sda";
+
type = lib.types.str;
+
};
+
+
config = {
+
assertions = [
+
{
+
assertion = config.myDisko.installDrive != "";
+
message = "config.myDisko.installDrive cannot be empty.";
+
}
+
];
+
+
disko.devices = {
+
disk.disk1 = {
+
device = config.myDisko.installDrive;
+
type = "disk";
+
content = {
+
type = "gpt";
+
partitions = {
+
boot = {
+
name = "boot";
+
size = "1M";
+
type = "EF02";
+
};
+
esp = {
+
name = "ESP";
+
size = "500M";
+
type = "EF00";
+
content = {
+
type = "filesystem";
+
format = "vfat";
+
mountpoint = "/boot";
+
};
+
};
+
root = {
+
name = "root";
+
size = "100%";
+
content = {
+
type = "lvm_pv";
+
vg = "pool";
+
};
+
};
+
};
+
};
+
};
+
+
lvm_vg = {
+
pool = {
+
type = "lvm_vg";
+
lvs = {
+
root = {
+
size = "100%FREE";
+
content = {
+
type = "filesystem";
+
format = "ext4";
+
mountpoint = "/";
+
mountOptions = [
+
"defaults"
+
];
+
};
+
};
+
};
+
};
+
};
+
};
+
};
+
}
+300
modules/flake/actions.nix
···
+
{
+
lib,
+
self,
+
...
+
}: {
+
flake.actions-nix = {
+
pre-commit.enable = false; # Set to true if you want pre-commit workflow generation
+
+
workflows = {
+
# build-nix.yml
+
".github/workflows/build-nix.yml" = {
+
name = "build-nix";
+
concurrency = {
+
group = "\${{ github.workflow }}-\${{ github.ref }}";
+
cancel-in-progress = true;
+
};
+
on = {
+
push = {
+
paths = [
+
"flake.lock"
+
"flake.nix"
+
"flake/"
+
];
+
};
+
workflow_dispatch = {};
+
};
+
jobs = let
+
devShells = lib.attrNames (self.devShells.x86_64-linux or {});
+
packages = lib.attrNames (self.packages.x86_64-linux or {});
+
devShellJobs = lib.listToAttrs (map
+
(name: {
+
name = "build-devShell-${name}";
+
value = {
+
runs-on = "ubuntu-latest";
+
steps = [
+
{
+
uses = "actions/checkout@main";
+
"with" = {fetch-depth = 1;};
+
}
+
{uses = "DeterminateSystems/nix-installer-action@main";}
+
{
+
uses = "cachix/cachix-action@master";
+
"with" = {
+
name = "ayla6";
+
authToken = "\${{ secrets.CACHIX_AUTH_TOKEN }}";
+
};
+
}
+
{
+
name = "Build devShell ${name}";
+
run = "nix build --accept-flake-config --print-out-paths .#devShells.x86_64-linux.${name}";
+
}
+
];
+
};
+
})
+
devShells);
+
packageJobs = lib.listToAttrs (map
+
(name: {
+
name = "build-package-${name}";
+
value = {
+
runs-on = "ubuntu-latest";
+
steps = [
+
{
+
uses = "actions/checkout@main";
+
"with" = {fetch-depth = 1;};
+
}
+
{uses = "DeterminateSystems/nix-installer-action@main";}
+
{
+
uses = "cachix/cachix-action@master";
+
"with" = {
+
name = "ayla6";
+
authToken = "\${{ secrets.CACHIX_AUTH_TOKEN }}";
+
};
+
}
+
{
+
name = "Build package ${name}";
+
run = "nix build --accept-flake-config --print-out-paths .#packages.x86_64-linux.${name}";
+
}
+
];
+
};
+
})
+
packages);
+
in
+
devShellJobs // packageJobs;
+
};
+
+
# build-nixos.yml
+
".github/workflows/build-nixos.yml" = {
+
name = "build-nixos";
+
concurrency = {
+
cancel-in-progress = true;
+
group = "\${{ github.workflow }}-\${{ github.ref }}";
+
};
+
on = {
+
push = {
+
paths-ignore = [
+
"**/*.md"
+
".github/**"
+
"_img/**"
+
];
+
};
+
workflow_dispatch = {};
+
};
+
jobs =
+
lib.mapAttrs'
+
(hostname: _: {
+
name = "build-${hostname}";
+
value = {
+
runs-on = "ubuntu-latest";
+
steps = [
+
{
+
name = "Free Disk Space (Ubuntu)";
+
uses = "jlumbroso/free-disk-space@main";
+
}
+
{
+
name = "Checkout";
+
uses = "actions/checkout@main";
+
"with" = {fetch-depth = 1;};
+
}
+
{
+
name = "Install Nix";
+
uses = "DeterminateSystems/nix-installer-action@main";
+
}
+
{
+
name = "Cachix";
+
uses = "cachix/cachix-action@master";
+
"with" = {
+
name = "ayla6";
+
authToken = "\${{ secrets.CACHIX_AUTH_TOKEN }}";
+
};
+
}
+
{
+
name = "Build ${hostname}";
+
run = "nix build --accept-flake-config --print-out-paths .#nixosConfigurations.${hostname}.config.system.build.toplevel";
+
}
+
];
+
};
+
})
+
self.nixosConfigurations;
+
};
+
+
# check-nix.yml
+
".github/workflows/check-nix.yml" = {
+
name = "check-nix";
+
concurrency = {
+
cancel-in-progress = true;
+
group = "\${{ github.workflow }}-\${{ github.ref }}";
+
};
+
on = {
+
push = {
+
paths-ignore = [
+
"**/*.md"
+
".github/**"
+
"_img/**"
+
];
+
};
+
workflow_dispatch = {};
+
};
+
jobs = {
+
check-flake = {
+
runs-on = "ubuntu-latest";
+
steps = [
+
{
+
uses = "actions/checkout@main";
+
"with" = {fetch-depth = 1;};
+
}
+
{uses = "DeterminateSystems/nix-installer-action@main";}
+
{
+
name = "Check flake evaluation";
+
run = "nix -Lv flake check --all-systems";
+
}
+
];
+
};
+
};
+
};
+
+
# deploy-tailscale-acls.yml
+
".github/workflows/deploy-tailscale-acls.yml" = {
+
name = "deploy-tailscale-acls";
+
on = {
+
push = {
+
branches = ["master"];
+
paths = [
+
".github/workflows/deploy-tailscale-acls.yml"
+
"flake/tailscale.nix"
+
];
+
};
+
pull_request = {
+
branches = ["master"];
+
paths = [
+
".github/workflows/deploy-tailscale-acls.yml"
+
"flake/tailscale.nix"
+
];
+
};
+
workflow_dispatch = {
+
inputs = {
+
action = {
+
description = "Which action to run";
+
required = true;
+
type = "choice";
+
default = "deploy";
+
options = ["deploy" "test"];
+
};
+
};
+
};
+
};
+
jobs = {
+
acls = {
+
runs-on = "ubuntu-latest";
+
steps = [
+
{
+
uses = "actions/checkout@main";
+
"with" = {fetch-depth = 1;};
+
}
+
{uses = "DeterminateSystems/nix-installer-action@main";}
+
{
+
name = "Convert .#tailscaleACLs to tailscale.json";
+
run = "nix eval --json .#tailscaleACLs > tailscale.json";
+
}
+
{
+
name = "Deploy ACL";
+
"if" = ''
+
github.event_name == 'push' ||
+
(github.event_name == 'workflow_dispatch' &&
+
github.event.inputs.action == 'deploy')
+
'';
+
uses = "tailscale/gitops-acl-action@v1";
+
"with" = {
+
api-key = "\${{ secrets.TS_API_KEY }}";
+
tailnet = "ayla6.github";
+
policy-file = "tailscale.json";
+
action = "apply";
+
};
+
}
+
{
+
name = "Test ACL";
+
"if" = ''
+
github.event_name == 'pull_request' ||
+
(github.event_name == 'workflow_dispatch' &&
+
github.event.inputs.action == 'test')
+
'';
+
uses = "tailscale/gitops-acl-action@v1";
+
"with" = {
+
api-key = "\${{ secrets.TS_API_KEY }}";
+
tailnet = "ayla6.github";
+
policy-file = "tailscale.json";
+
action = "test";
+
};
+
}
+
];
+
};
+
};
+
};
+
+
# update-inputs.yml
+
".github/workflows/update-inputs.yml" = {
+
name = "update-inputs";
+
on = {
+
schedule = [
+
{cron = "0 6 * * 2,5";}
+
];
+
workflow_dispatch = {};
+
};
+
jobs = {
+
update-flake-lock = {
+
runs-on = "ubuntu-latest";
+
steps = [
+
{
+
uses = "actions/checkout@main";
+
"with" = {
+
ref = "\${{ github.head_ref }}";
+
fetch-depth = 1;
+
};
+
}
+
{
+
name = "Setup Git";
+
run = ''
+
git config --local user.name "github-actions[bot]"
+
git config --local user.email "github-actions[bot]@users.noreply.github.com"
+
'';
+
}
+
{uses = "DeterminateSystems/nix-installer-action@main";}
+
{
+
uses = "DeterminateSystems/update-flake-lock@main";
+
"with" = {
+
token = "\${{ secrets.FLAKE_UPDATE_PAT }}";
+
pr-title = "flake: update inputs";
+
pr-assignees = "ayla6";
+
pr-labels = ''
+
dependencies
+
automated
+
'';
+
};
+
}
+
];
+
};
+
};
+
};
+
};
+
};
+
}
+6
modules/flake/default.nix
···
{
imports = [
+
./actions.nix
+
./files
+
./devShells.nix
+
./git-hooks-nix.nix
./home-manager.nix
./nixos.nix
+
./packages.nix
+
./tailscale.nix
];
}
+34
modules/flake/devShells.nix
···
+
_: {
+
perSystem = {
+
config,
+
lib,
+
pkgs,
+
inputs',
+
self',
+
...
+
}: {
+
devShells.default = pkgs.mkShell {
+
packages =
+
(with pkgs; [
+
(lib.hiPrio uutils-coreutils-noprefix)
+
git
+
nh
+
])
+
# ++ lib.attrValues config.treefmt.build.programs
+
++ [
+
inputs'.agenix.packages.default
+
inputs'.disko.packages.disko-install
+
self'.packages.gen-files
+
];
+
+
shellHook = ''
+
echo "Installing pre-commit hooks..."
+
${config.pre-commit.installationScript}
+
echo "Generating files..."
+
${lib.getExe self'.packages.gen-files}
+
export FLAKE="." NH_FLAKE="."
+
echo "👋 Welcome to the nixcfg devShell!"
+
'';
+
};
+
};
+
}
+8
modules/flake/files/default.nix
···
+
{
+
imports = [
+
# ./ci
+
# ./helix.nix
+
# ./vscode.nix
+
./zed.nix
+
];
+
}
+76
modules/flake/files/zed.nix
···
+
_: {
+
perSystem = {
+
lib,
+
pkgs,
+
...
+
}: {
+
files.files = [
+
{
+
checkFile = false;
+
path_ = ".zed/settings.json";
+
+
drv = (pkgs.formats.json {}).generate "zed-setting.json" {
+
auto_install_extensions = {
+
basher = true;
+
nix = true;
+
};
+
+
languages = {
+
JSON = {
+
format_on_save = "on";
+
+
formatter = {
+
external = {
+
command = lib.getExe pkgs.prettier;
+
arguments = ["--stdin-filepath" "{buffer_path}"];
+
};
+
};
+
};
+
+
Markdown = {
+
format_on_save = "on";
+
+
formatter.external = {
+
command = lib.getExe pkgs.prettier;
+
arguments = ["--stdin-filepath" "{buffer_path}"];
+
};
+
};
+
+
Nix = {
+
format_on_save = "on";
+
formatter = "language_server";
+
language_servers = ["nixd"];
+
};
+
+
"Shell Script" = {
+
format_on_save = "on";
+
+
formatter = {
+
external = {
+
command = lib.getExe pkgs.shfmt;
+
arguments = ["--filename" "{buffer_path}" "-i" "2"];
+
};
+
};
+
+
tab_size = 2;
+
hard_tabs = false;
+
};
+
+
YAML = {
+
format_on_save = "on";
+
formatter.external = {
+
command = lib.getExe pkgs.prettier;
+
arguments = ["--stdin-filepath" "{buffer_path}"];
+
};
+
};
+
};
+
+
lsp.nixd = {
+
binary.path = lib.getExe pkgs.nixd;
+
settings.formatting.command = [(lib.getExe pkgs.alejandra) "--quiet" "--"];
+
};
+
};
+
}
+
];
+
};
+
}
+17
modules/flake/git-hooks-nix.nix
···
+
_: {
+
perSystem = _: {
+
pre-commit.settings.hooks = {
+
alejandra.enable = true;
+
deadnix.enable = true;
+
prettier.enable = false;
+
shellcheck.enable = true;
+
+
shfmt = {
+
enable = true;
+
args = ["-i" "2"];
+
};
+
+
statix.enable = true;
+
};
+
};
+
}
+1
modules/flake/home-manager.nix
···
homeModules = {
default = ../home;
+
snippets = ../snippets;
};
};
}
+14 -1
modules/flake/nixos.nix
···
...
}: {
flake = {
+
diskoConfigurations = {
+
btrfs-subvolumes = ../disko/btrfs-subvolumes;
+
luks-btrfs-subvolumes = ../disko/luks-btrfs-subvolumes;
+
lvm-ext4 = ../disko/lvm-ext4;
+
};
+
nixosModules = {
hardware = ../hardware;
locale-en-gb = ../locale/en-gb;
nixos = ../nixos;
+
snippets = ../snippets;
users = ../users;
};
nixosConfigurations = let
modules = self.nixosModules;
in
-
inputs.nixpkgs.lib.genAttrs ["morgana"] (
+
inputs.nixpkgs.lib.genAttrs [
+
"morgana"
+
"nanpi"
+
] (
host:
inputs.nixpkgs.lib.nixosSystem {
modules = [
../../hosts/${host}
+
inputs.agenix.nixosModules.default
+
inputs.disko.nixosModules.disko
inputs.home-manager.nixosModules.home-manager
inputs.lanzaboote.nixosModules.lanzaboote
modules.hardware
modules.nixos
+
modules.snippets
modules.users
{
+18
modules/flake/packages.nix
···
+
_: {
+
perSystem = {
+
config,
+
lib,
+
pkgs,
+
...
+
}: {
+
packages = {
+
gen-files = pkgs.writeShellApplication {
+
name = "gen-files";
+
+
text = ''
+
${lib.getExe config.files.writer.drv}
+
'';
+
};
+
};
+
};
+
}
+20
modules/flake/tailscale.nix
···
+
_: {
+
flake.tailscaleACLs = {
+
acls = [
+
{
+
action = "accept";
+
dst = ["*:*"];
+
src = ["*"];
+
}
+
];
+
+
ssh = [
+
{
+
action = "accept";
+
dst = ["autogroup:self"];
+
src = ["autogroup:member"];
+
users = ["autogroup:nonroot" "root"];
+
}
+
];
+
};
+
}
+1
modules/hardware/default.nix
···
./nvidia
./intel
./acer
+
./hp
./profiles
];
}
+5
modules/hardware/hp/default.nix
···
+
{...}: {
+
imports = [
+
./theRedOne
+
];
+
}
+22
modules/hardware/hp/theRedOne/default.nix
···
+
{
+
config,
+
lib,
+
...
+
}: {
+
options.myHardware.hp.theRedOne.enable =
+
lib.mkEnableOption "The Red HP laptop hardware configuration.";
+
+
config = lib.mkIf config.myHardware.hp.theRedOne.enable {
+
myHardware = {
+
intel = {
+
cpu.enable = true;
+
gpu.enable = true;
+
};
+
+
profiles = {
+
base.enable = true;
+
laptop.enable = true;
+
};
+
};
+
};
+
}
+4 -5
modules/home/default.nix
···
inputs.agenix.homeManagerModules.default
];
-
home.username = "ayla";
-
home.homeDirectory = "/home/ayla";
-
-
home.stateVersion = "25.05";
-
home.shell.enableFishIntegration = true;
+
home = {
+
stateVersion = "25.05";
+
shell.enableFishIntegration = true;
+
};
programs.home-manager.enable = true;
}
+1 -1
modules/home/hidden.nix
···
-
{...}: {
+
_: {
home.file.".hidden" = {
text = "result";
};
+1 -1
modules/home/packages.nix
···
nodejs
pnpm
typescript
-
ffmpeg
+
ffmpeg-full
luajit
love
+27 -1
modules/home/profiles/shell/default.nix
···
programs = {
bat.enable = true;
+
btop.enable = true;
+
+
direnv = {
+
enable = true;
+
nix-direnv.enable = true;
+
silent = true;
+
+
stdlib = ''
+
: ''${XDG_CACHE_HOME:=$HOME/.cache}
+
declare -A direnv_layout_dirs
+
+
direnv_layout_dir() {
+
echo "''${direnv_layout_dirs[$PWD]:=$(
+
echo -n "$XDG_CACHE_HOME"/direnv/layouts/
+
echo -n "$PWD" | sha1sum | cut -d ' ' -f 1
+
)}"
+
}
+
'';
+
};
eza = {
enable = true;
···
};
fzf.enable = true;
-
btop.enable = true;
+
+
ripgrep = {
+
enable = true;
+
arguments = ["--pretty"];
+
};
+
+
ripgrep-all.enable = true;
+
joshuto.enable = true;
zellij = {
enable = true;
+1
modules/home/programs/default.nix
···
./mpv
./aria2
./micro
+
./ssh
];
}
+2 -4
modules/home/programs/firefox/default.nix
···
lib,
config,
pkgs,
+
self,
...
}: let
engines = import ./engines.nix;
···
"onebar.hide-all-URLbar-icons" = true;
};
-
userChrome = pkgs.fetchurl {
-
url = "https://git.gay/freeplay/Firefox-Onebar/raw/commit/78789cadd56cdf0d273ace47e3ac8b6f7db94eef/onebar.css";
-
sha256 = "sha256-bPBApA5IznRodld+gh6FpzglgVzl0uOQOUUQYNB+nEQ=";
-
};
+
userChrome = builtins.readFile self.inputs.firefox-onebar;
userContent = ''
@font-face {
+27
modules/home/programs/ssh/default.nix
···
+
{
+
config,
+
lib,
+
pkgs,
+
...
+
}: {
+
options.myHome.programs.ssh.enable = lib.mkEnableOption "openssh client";
+
+
config = lib.mkIf config.myHome.programs.ssh.enable {
+
programs.ssh = {
+
enable = true;
+
compression = true;
+
+
# matchBlocks = let
+
# rootMe = name: {
+
# ${name} = {
+
# hostname = name;
+
# user = "root";
+
# };
+
# };
+
# in
+
# rootMe "dewford";
+
+
package = pkgs.openssh;
+
};
+
};
+
}
+1 -1
modules/home/programs/zed-editor/default.nix
···
buffer_font_size = 14;
buffer_font_family = "JetBrains Mono NL";
use_on_type_format = true;
-
wrap_guides = [80];
+
wrap_guides = [100];
minimap.show = "auto";
preferred_line_length = 80;
soft_wrap = "preferred_line_length";
-1
modules/home/services/default.nix
···
{...}: {
imports = [
-
./syncthing
];
}
-13
modules/home/services/syncthing/default.nix
···
-
{
-
lib,
-
config,
-
...
-
}: {
-
options.myHome.services.syncthing.enable = lib.mkEnableOption "syncthing";
-
-
config = lib.mkIf config.myHome.services.syncthing.enable {
-
services.syncthing = {
-
enable = true;
-
};
-
};
-
}
+11 -8
modules/nixos/desktop/gnome/default.nix
···
}
];
-
services.displayManager.gdm.enable = true;
-
services.desktopManager.gnome.enable = true;
+
services = {
+
displayManager.gdm.enable = true;
+
desktopManager.gnome.enable = true;
+
};
environment.gnome.excludePackages = with pkgs; [
-
epiphany # web browser
geary # email reader
gedit # text editor
gnome-characters
···
package = pkgs.gnomeExtensions.gsconnect;
};
-
environment.variables.QT_QPA_PLATFORMTHEME = "qt6ct";
-
environment.systemPackages = with pkgs; [
-
libsForQt5.qt5ct
-
qt6ct
-
];
+
environment = {
+
variables.QT_QPA_PLATFORMTHEME = "qt6ct";
+
systemPackages = with pkgs; [
+
libsForQt5.qt5ct
+
qt6ct
+
];
+
};
myNixOS.desktop.enable = true;
+27
modules/nixos/profiles/autoUpgrade/README.md
···
+
# Auto Upgrade Profile
+
+
Automatic system updates from the flake repository.
+
+
## Usage
+
+
```nix
+
{
+
myNixOS.profiles.autoUpgrade = {
+
enable = true;
+
operation = "boot"; # or "switch" or "test"
+
};
+
}
+
```
+
+
## What It Does
+
+
- **Scheduled updates**: Daily updates at 2:00 AM with up to 120 minutes random delay.
+
- **Flake integration**: Updates from `github:alyraffauf/nixcfg` (or configured `FLAKE` variable).
+
- **Reboot window**: Automatic reboots only between 2:00-6:00 AM.
+
- **Network check**: Tests connectivity before attempting updates.
+
- **Retry logic**: Retries failed updates (useful for laptops that wake without network).
+
- **Persistent timers**: Updates survive system reboots and sleep cycles and begin when possible.
+
+
## Important Notes
+
+
Enables automatic reboots by default during the 2:00-6:00 AM window.
+50
modules/nixos/profiles/autoUpgrade/default.nix
···
+
{
+
config,
+
lib,
+
pkgs,
+
...
+
}: {
+
options.myNixOS.profiles.autoUpgrade = {
+
enable = lib.mkEnableOption "auto-upgrade system";
+
+
operation = lib.mkOption {
+
type = lib.types.str;
+
default = "boot";
+
description = "Operation to perform on auto-upgrade. Can be 'boot', 'switch', or 'test'.";
+
};
+
};
+
+
config = lib.mkIf config.myNixOS.profiles.autoUpgrade.enable {
+
system.autoUpgrade = {
+
inherit (config.myNixOS.profiles.autoUpgrade) operation;
+
+
enable = true;
+
allowReboot = lib.mkDefault true;
+
dates = "02:00";
+
flags = ["--accept-flake-config"];
+
flake = config.environment.variables.FLAKE or "github:ayla6/nixcfg";
+
persistent = true;
+
randomizedDelaySec = "120min";
+
+
rebootWindow = {
+
lower = "02:00";
+
upper = "06:00";
+
};
+
};
+
+
# Allow nixos-upgrade to restart on failure (e.g. when laptop wakes up before network connection is set)
+
systemd.services.nixos-upgrade = {
+
preStart = "${pkgs.host}/bin/host cloudflare.com"; # Check network connectivity
+
+
serviceConfig = {
+
Restart = "on-failure";
+
RestartSec = "120";
+
};
+
+
unitConfig = {
+
StartLimitIntervalSec = 600;
+
StartLimitBurst = 2;
+
};
+
};
+
};
+
}
+213
modules/nixos/profiles/backups/default.nix
···
+
{
+
config,
+
lib,
+
pkgs,
+
...
+
}: let
+
backupDestination = "rclone:gdrive-backups/${config.networking.hostName}";
+
mkRepo = service: "${backupDestination}/${service}";
+
stop = service: "${pkgs.systemd}/bin/systemctl stop ${service}";
+
start = service: "${pkgs.systemd}/bin/systemctl start ${service}";
+
in {
+
options.myNixOS.profiles.backups = {
+
enable = lib.mkEnableOption "automatically back up enabled services to gdrive";
+
};
+
+
config = lib.mkIf config.myNixOS.profiles.backups.enable {
+
services.restic.backups = {
+
audiobookshelf = lib.mkIf config.services.audiobookshelf.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "audiobookshelf";
+
backupPrepareCommand = stop "audiobookshelf";
+
paths = [config.services.audiobookshelf.dataDir];
+
repository = mkRepo "audiobookshelf";
+
}
+
);
+
+
bazarr = lib.mkIf config.services.bazarr.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "bazarr";
+
backupPrepareCommand = stop "bazarr";
+
paths = [config.services.bazarr.dataDir];
+
repository = mkRepo "bazarr";
+
}
+
);
+
+
couchdb = lib.mkIf config.services.couchdb.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "couchdb";
+
backupPrepareCommand = stop "couchdb";
+
paths = [config.services.couchdb.databaseDir];
+
repository = mkRepo "couchdb";
+
}
+
);
+
+
forgejo = lib.mkIf (config.services.forgejo.enable && config.services.forgejo.settings.storage.STORAGE_TYPE != "minio") (
+
config.mySnippets.restic
+
// {
+
paths = [config.services.forgejo.stateDir];
+
repository = mkRepo "forgejo";
+
}
+
);
+
+
immich = lib.mkIf config.services.immich.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "immich-server";
+
backupPrepareCommand = stop "immich-server";
+
+
paths = [
+
"${config.services.immich.mediaLocation}/library"
+
"${config.services.immich.mediaLocation}/profile"
+
"${config.services.immich.mediaLocation}/upload"
+
"${config.services.immich.mediaLocation}/backups"
+
];
+
+
repository = mkRepo "immich";
+
}
+
);
+
+
jellyfin = lib.mkIf config.services.jellyfin.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "jellyfin";
+
backupPrepareCommand = stop "jellyfin";
+
paths = [config.services.jellyfin.dataDir];
+
repository = mkRepo "jellyfin";
+
}
+
);
+
+
lidarr = lib.mkIf config.services.lidarr.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "lidarr";
+
backupPrepareCommand = stop "lidarr";
+
paths = [config.services.lidarr.dataDir];
+
repository = mkRepo "lidarr";
+
}
+
);
+
+
ombi = lib.mkIf config.services.ombi.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "ombi";
+
backupPrepareCommand = stop "ombi";
+
paths = [config.services.ombi.dataDir];
+
repository = mkRepo "ombi";
+
}
+
);
+
+
pds = lib.mkIf config.services.pds.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "pds";
+
backupPrepareCommand = stop "pds";
+
paths = [config.services.pds.settings.PDS_DATA_DIRECTORY];
+
repository = mkRepo "pds";
+
}
+
);
+
+
plex = lib.mkIf config.services.plex.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "plex";
+
backupPrepareCommand = stop "plex";
+
exclude = ["${config.services.plex.dataDir}/Plex Media Server/Plug-in Support/Databases"];
+
paths = [config.services.plex.dataDir];
+
repository = mkRepo "plex";
+
}
+
);
+
+
postgresql = lib.mkIf config.services.postgresql.enable (
+
config.mySnippets.restic
+
// {
+
paths = [config.services.postgresql.dataDir];
+
repository = mkRepo "postgresql";
+
}
+
);
+
+
prowlarr = lib.mkIf config.services.prowlarr.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "prowlarr";
+
backupPrepareCommand = stop "prowlarr";
+
paths = [config.services.prowlarr.dataDir];
+
repository = mkRepo "prowlarr";
+
}
+
);
+
+
qbittorrent = lib.mkIf config.myNixOS.services.qbittorrent.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "qbittorrent";
+
backupPrepareCommand = stop "qbittorrent";
+
paths = [config.myNixOS.services.qbittorrent.dataDir];
+
repository = mkRepo "qbittorrent";
+
}
+
);
+
+
radarr = lib.mkIf config.services.radarr.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "radarr";
+
backupPrepareCommand = stop "radarr";
+
paths = [config.services.radarr.dataDir];
+
repository = mkRepo "radarr";
+
}
+
);
+
+
readarr = lib.mkIf config.services.readarr.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "readarr";
+
backupPrepareCommand = stop "readarr";
+
paths = [config.services.readarr.dataDir];
+
repository = mkRepo "readarr";
+
}
+
);
+
+
sonarr = lib.mkIf config.services.sonarr.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "sonarr";
+
backupPrepareCommand = stop "sonarr";
+
paths = [config.services.sonarr.dataDir];
+
repository = mkRepo "sonarr";
+
}
+
);
+
+
tautulli = lib.mkIf config.services.tautulli.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "tautulli";
+
backupPrepareCommand = stop "tautulli";
+
paths = [config.services.tautulli.dataDir];
+
repository = mkRepo "tautulli";
+
}
+
);
+
+
uptime-kuma = lib.mkIf config.services.uptime-kuma.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "uptime-kuma";
+
backupPrepareCommand = stop "uptime-kuma";
+
paths = ["/var/lib/uptime-kuma"];
+
repository = mkRepo "uptime-kuma";
+
}
+
);
+
+
vaultwarden = lib.mkIf config.services.vaultwarden.enable (
+
config.mySnippets.restic
+
// {
+
backupCleanupCommand = start "vaultwarden";
+
backupPrepareCommand = stop "vaultwarden";
+
paths = ["/var/lib/vaultwarden"];
+
repository = mkRepo "vaultwarden";
+
}
+
);
+
};
+
};
+
}
+12
modules/nixos/profiles/base/default.nix
···
programs = {
dconf.enable = true; # Needed for home-manager
+
direnv = {
+
enable = true;
+
nix-direnv.enable = true;
+
silent = true;
+
};
+
+
gnupg.agent = {
+
enable = true;
+
enableSSHSupport = true;
+
};
+
nh.enable = true;
+
ssh.knownHosts = config.mySnippets.ssh.knownHosts;
};
networking.networkmanager.enable = true;
+42
modules/nixos/profiles/btrfs/README.md
···
+
# Btrfs Profile
+
+
Btrfs filesystem management with snapshots, scrubbing, and optional deduplication.
+
+
## Usage
+
+
```nix
+
{
+
myNixOS.profiles.btrfs = {
+
enable = true;
+
snapshots = false;
+
deduplicate = false; # optional, enables beesd
+
};
+
}
+
```
+
+
## What It Does
+
+
- **Filesystem support**: Enables btrfs kernel support.
+
- **Auto-scrubbing**: Periodic data integrity checks on all btrfs filesystems.
+
- **Snapshots**: Automatic timeline snapshots of `/home` with snapper (if btrfs subvolume).
+
- **Smart filtering**: Excludes cache, config, and temporary files from snapshots.
+
- **Deduplication**: Optional beesd for block-level deduplication (when enabled).
+
- **GUI tools**: Includes snapper-gui on desktop systems.
+
+
## Snapshot Configuration
+
+
- **Timeline snapshots**: Automatic creation and cleanup enabled.
+
- **User access**: Users group can manage their own snapshots.
+
- **Filtered paths**: Excludes `.cache`, `.config`, `.local`, browser profiles, etc.
+
+
## Deduplication (Optional)
+
+
When `deduplicate = true`:
+
+
- **beesd**: Runs with 2GB hash tables and conservative load targets.
+
- **Performance tuning**: Limited to 50% thread factor and 1.0 load average.
+
- **Auto-discovery**: Automatically configures all detected btrfs devices.
+
+
## Important Notes
+
+
Only activates features for detected btrfs filesystems. Snapper only configured if `/home` is a btrfs subvolume.
+95
modules/nixos/profiles/btrfs/default.nix
···
+
{
+
config,
+
lib,
+
pkgs,
+
...
+
}: let
+
# Compute a list of Btrfs file systems (with mountPoint and device)
+
btrfsFSDevices = let
+
# Helper: does a device already appear in the accumulator?
+
isDeviceInList = list: device:
+
builtins.any (e: e.device == device) list;
+
+
# Helper: keep only the first occurrence of each device
+
uniqueDeviceList = lib.foldl' (
+
acc: e:
+
if isDeviceInList acc e.device
+
then acc
+
else acc ++ [e]
+
) [];
+
in
+
uniqueDeviceList (
+
lib.mapAttrsToList (_: fs: {
+
inherit (fs) mountPoint device;
+
})
+
(lib.filterAttrs (_: fs: fs.fsType == "btrfs") config.fileSystems)
+
);
+
+
# Create beesd.filesystems attrset keyed by device basename, with spec = device path
+
beesdConfig = lib.listToAttrs (map (fs: {
+
name = lib.strings.sanitizeDerivationName (baseNameOf fs.device);
+
+
value = {
+
hashTableSizeMB = 2048;
+
spec = fs.device;
+
verbosity = "info";
+
+
extraOptions = [
+
"--loadavg-target"
+
"1.0"
+
"--thread-factor"
+
"0.50"
+
];
+
};
+
})
+
btrfsFSDevices);
+
+
# Check if a btrfs /home entry exists
+
hasHomeSubvolume =
+
lib.hasAttr "/home" config.fileSystems
+
&& config.fileSystems."/home".fsType == "btrfs";
+
in {
+
options.myNixOS.profiles.btrfs = {
+
enable = lib.mkEnableOption "btrfs filesystem configuration";
+
deduplicate = lib.mkEnableOption "deduplicate btrfs filesystems";
+
snapshots = lib.mkEnableOption "enable snapper snapshots";
+
};
+
+
config = lib.mkIf config.myNixOS.profiles.btrfs.enable {
+
boot.supportedFilesystems = ["btrfs"];
+
environment.systemPackages = lib.optionals (config.services.xserver.enable && config.myNixOS.profiles.btrfs.snapshots) [pkgs.snapper-gui];
+
+
services = lib.mkIf (btrfsFSDevices != []) {
+
beesd.filesystems = lib.mkIf config.myNixOS.profiles.btrfs.deduplicate beesdConfig;
+
btrfs.autoScrub.enable = true;
+
+
snapper = lib.mkIf config.myNixOS.profiles.btrfs.snapshots {
+
configs.home = lib.mkIf hasHomeSubvolume {
+
ALLOW_GROUPS = ["users"];
+
FSTYPE = "btrfs";
+
SUBVOLUME = "/home";
+
TIMELINE_CLEANUP = true;
+
TIMELINE_CREATE = true;
+
};
+
+
filters = ''
+
-.bash_profile
+
-.bashrc
+
-.cache
+
-.config
+
-.librewolf
+
-.local
+
-.mozilla
+
-.nix-profile
+
-.pki
+
-.share
+
-.snapshots
+
-.thunderbird
+
-.zshrc
+
'';
+
+
persistentTimer = true;
+
};
+
};
+
};
+
}
+4
modules/nixos/profiles/default.nix
···
{...}: {
imports = [
./base
+
./btrfs
+
./backups
./workstation
+
./server
+
./autoUpgrade
];
}
+25
modules/nixos/profiles/server/README.md
···
+
# Server Profile
+
+
NixOS profile optimized for headless server environments.
+
+
## Usage
+
+
```nix
+
{
+
myNixOS.profiles.server.enable = true;
+
}
+
```
+
+
## What It Does
+
+
- **Minimal footprint**: Disables documentation and reduces system overhead.
+
- **Log management**: Volatile journald storage with 32MB limits to preserve disk space.
+
- **File monitoring**: Optimized inotify limits for server workloads.
+
- **Memory management**: ZRAM swap with zstd compression for efficiency.
+
- **Security**: Automatic fail2ban protection against brute force attacks.
+
- **Performance tuning**: BPF-based automatic kernel tuning.
+
- **Reliability**: systemd-oomd for out-of-memory protection.
+
+
## Important Notes
+
+
Disables coredumps and emergency mode for unattended operation.
+53
modules/nixos/profiles/server/default.nix
···
+
{
+
config,
+
lib,
+
...
+
}: {
+
options.myNixOS.profiles.server.enable = lib.mkEnableOption "server optimizations";
+
config = lib.mkIf config.myNixOS.profiles.server.enable {
+
boot.kernel.sysctl = {
+
# Improved file monitoring
+
"fs.file-max" = lib.mkDefault 2097152;
+
"fs.inotify.max_user_instances" = lib.mkOverride 100 8192;
+
"fs.inotify.max_user_watches" = lib.mkOverride 100 524288;
+
};
+
+
documentation = {
+
enable = false;
+
nixos.enable = false;
+
};
+
+
services = {
+
bpftune.enable = true;
+
+
journald = {
+
storage = "volatile";
+
extraConfig = "SystemMaxUse=32M\nRuntimeMaxUse=32M";
+
};
+
+
timesyncd.enable = true;
+
};
+
+
system.nixos.tags = ["server"];
+
+
systemd = {
+
coredump.enable = false;
+
enableEmergencyMode = false;
+
+
oomd = {
+
enable = true;
+
enableRootSlice = true;
+
enableSystemSlice = true;
+
enableUserSlices = true;
+
};
+
};
+
+
zramSwap = {
+
enable = lib.mkDefault true;
+
algorithm = lib.mkDefault "zstd";
+
priority = lib.mkDefault 100;
+
};
+
+
myNixOS.services.fail2ban.enable = true;
+
};
+
}
+1 -4
modules/nixos/programs/nix/default.nix
···
randomizedDelaySec = "60min";
};
-
settings.experimental-features = [
-
"nix-command"
-
"flakes"
-
];
+
inherit (config.mySnippets.nix) settings;
};
};
}
+35
modules/nixos/services/caddy/default.nix
···
+
{
+
config,
+
lib,
+
pkgs,
+
self,
+
...
+
}: {
+
options.myNixOS.services.caddy.enable = lib.mkEnableOption "Caddy web server.";
+
+
config = lib.mkIf config.myNixOS.services.caddy.enable {
+
age.secrets.tailscaleCaddyAuth.file = "${self.inputs.secrets}/tailscale/caddyAuth.age";
+
networking.firewall.allowedTCPPorts = [80 443];
+
+
services = {
+
caddy = {
+
enable = true;
+
enableReload = false;
+
environmentFile = config.age.secrets.tailscaleCaddyAuth.path;
+
+
globalConfig = ''
+
tailscale {
+
ephemeral true
+
}
+
'';
+
+
package = pkgs.caddy.withPlugins {
+
plugins = ["github.com/tailscale/caddy-tailscale@v0.0.0-20250508175905-642f61fea3cc"];
+
hash = "sha256-0GsjeeJnfLsJywWzWwJcCDk5wjTSBwzqMBY7iHjPQa8=";
+
};
+
};
+
+
tailscale.permitCertUid = "caddy";
+
};
+
};
+
}
+4
modules/nixos/services/default.nix
···
imports = [
./tailscale
./aria2
+
./fail2ban
+
./syncthing
+
./caddy
+
./qbittorrent
];
}
+19
modules/nixos/services/fail2ban/default.nix
···
+
{
+
config,
+
lib,
+
...
+
}: {
+
options.myNixOS.services.fail2ban.enable = lib.mkEnableOption "fail2ban";
+
+
config = lib.mkIf config.myNixOS.services.fail2ban.enable {
+
environment.etc = {
+
};
+
+
services.fail2ban = {
+
enable = true;
+
ignoreIP = ["100.64.0.0/10"];
+
bantime = "24h";
+
bantime-increment.enable = true;
+
};
+
};
+
}
+107
modules/nixos/services/qbittorrent/default.nix
···
+
# Borrowed graciously from https://github.com/WiredMic/nix-config/commit/d9268ce5190a2041ef66b492900eed278d1508e2#diff-9db90aeeaf81739c27dcdab8065abc8709d0bd5428bc658cff2db46acc91536a
+
{
+
config,
+
lib,
+
pkgs,
+
...
+
}: let
+
cfg = config.myNixOS.services.qbittorrent;
+
UID = 888;
+
GID = 888;
+
in {
+
options.myNixOS.services.qbittorrent = {
+
enable = lib.mkEnableOption "qBittorrent headless";
+
+
dataDir = lib.mkOption {
+
type = lib.types.path;
+
default = "/var/lib/qbittorrent";
+
description = "The directory where qBittorrent stores its data files.";
+
};
+
+
user = lib.mkOption {
+
type = lib.types.str;
+
default = "qbittorrent";
+
description = "User account under which qBittorrent runs.";
+
};
+
+
group = lib.mkOption {
+
type = lib.types.str;
+
default = "qbittorrent";
+
description = "Group under which qBittorrent runs.";
+
};
+
+
port = lib.mkOption {
+
type = lib.types.port;
+
default = 8080;
+
description = "qBittorrent web UI port.";
+
};
+
+
openFirewall = lib.mkOption {
+
type = lib.types.bool;
+
default = false;
+
description = "Open services.qBittorrent.port to the outside network.";
+
};
+
+
package = lib.mkOption {
+
type = lib.types.package;
+
default = pkgs.qbittorrent-nox;
+
defaultText = lib.literalExpression "pkgs.qbittorrent-nox";
+
description = "The qbittorrent package to use.";
+
};
+
};
+
+
config = lib.mkIf cfg.enable {
+
networking.firewall =
+
lib.mkIf cfg.openFirewall {allowedTCPPorts = [cfg.port];};
+
+
systemd.services.qbittorrent = {
+
after = ["local-fs.target" "network-online.target"];
+
description = "qBittorrent-nox service";
+
documentation = ["man:qbittorrent-nox(1)"];
+
requires = ["local-fs.target" "network-online.target"];
+
wantedBy = ["multi-user.target"];
+
+
serviceConfig = {
+
Type = "simple";
+
User = cfg.user;
+
Group = cfg.group;
+
+
# Run the pre-start script with full permissions (the "!" prefix) so it
+
# can create the data directory if necessary.
+
ExecStartPre = let
+
preStartScript = pkgs.writeScript "qbittorrent-run-prestart" ''
+
#!${pkgs.bash}/bin/bash
+
+
# Create data directory if it doesn't exist
+
if ! test -d "$QBT_PROFILE"; then
+
echo "Creating initial qBittorrent data directory in: $QBT_PROFILE"
+
install -d -m 0755 -o "${cfg.user}" -g "${cfg.group}" "$QBT_PROFILE"
+
fi
+
'';
+
in "!${preStartScript}";
+
+
ExecStart = "${cfg.package}/bin/qbittorrent-nox";
+
# To prevent "Quit & shutdown daemon" from working; we want systemd to
+
# manage it!
+
#Restart = "on-success";
+
#UMask = "0002";
+
#LimitNOFILE = cfg.openFilesLimit;
+
};
+
+
environment = {
+
QBT_PROFILE = cfg.dataDir;
+
QBT_WEBUI_PORT = toString cfg.port;
+
};
+
};
+
+
users.users = lib.mkIf (cfg.user == "qbittorrent") {
+
qbittorrent = {
+
inherit (cfg) group;
+
uid = UID;
+
};
+
};
+
+
users.groups =
+
lib.mkIf (cfg.group == "qbittorrent") {qbittorrent = {gid = GID;};};
+
};
+
}
+71
modules/nixos/services/syncthing/default.nix
···
+
{
+
config,
+
lib,
+
...
+
}: {
+
options.myNixOS.services.syncthing = {
+
enable = lib.mkEnableOption "Syncthing file syncing service.";
+
+
certFile = lib.mkOption {
+
description = "Path to the certificate file.";
+
type = lib.types.path;
+
};
+
+
keyFile = lib.mkOption {
+
description = "Path to the key file.";
+
type = lib.types.path;
+
};
+
+
user = lib.mkOption {
+
description = "User to run Syncthing as.";
+
type = lib.types.str;
+
};
+
};
+
+
config = lib.mkIf config.myNixOS.services.syncthing.enable {
+
systemd.services.syncthing.environment.STNODEFAULTFOLDER = "true";
+
+
services = {
+
caddy.virtualHosts =
+
lib.mkIf
+
(
+
config.myNixOS.services.caddy.enable
+
&& config.myNixOS.services.tailscale.enable
+
) {
+
"syncthing-${config.networking.hostName}.${config.mySnippets.tailnet.name}" = {
+
extraConfig = ''
+
bind tailscale/syncthing-${config.networking.hostName}
+
reverse_proxy localhost:8384 {
+
header_up Host localhost
+
}
+
'';
+
};
+
};
+
+
syncthing = let
+
cfg = config.myNixOS.services.syncthing;
+
inherit (config.mySnippets.syncthing) devices;
+
+
inherit (config.mySnippets.syncthing) folders;
+
in {
+
enable = true;
+
cert = cfg.certFile;
+
configDir = "${config.services.syncthing.dataDir}/.syncthing";
+
dataDir = "/home/${cfg.user}";
+
key = cfg.keyFile;
+
openDefaultPorts = true;
+
inherit (cfg) user;
+
+
settings = {
+
options = {
+
localAnnounceEnabled = true;
+
relaysEnabled = true;
+
urAccepted = -1;
+
};
+
+
inherit devices folders;
+
};
+
};
+
};
+
};
+
}
+78 -17
modules/nixos/services/tailscale/default.nix
···
config,
lib,
pkgs,
+
self,
...
}: {
options.myNixOS.services.tailscale = {
enable = lib.mkEnableOption "Tailscale VPN service";
+
+
authKeyFile = lib.mkOption {
+
description = "Key file to use for authentication";
+
default = config.age.secrets.tailscaleAuthKey.path or null;
+
type = lib.types.nullOr lib.types.path;
+
};
+
+
enableCaddy = lib.mkOption {
+
description = "Whether to serve supported local services on Tailnet with Caddy.";
+
default = true;
+
type = lib.types.bool;
+
};
+
+
operator = lib.mkOption {
+
description = "Tailscale operator name";
+
default = null;
+
type = lib.types.nullOr lib.types.str;
+
};
};
-
config = lib.mkIf config.myNixOS.services.tailscale.enable (
-
lib.mkMerge [
-
(lib.mkIf config.myNixOS.desktop.gnome.enable {
-
environment.systemPackages = with pkgs; [
-
gnomeExtensions.tailscale-qs
+
config = lib.mkIf config.myNixOS.services.tailscale.enable {
+
assertions = [
+
{
+
assertion = config.myNixOS.services.tailscale.authKeyFile != null;
+
message = "config.tailscale.authKeyFile cannot be null.";
+
}
+
];
+
+
age.secrets.tailscaleCaddyAuth.file = "${self.inputs.secrets}/tailscale/caddyAuth.age";
+
+
home-manager.sharedModules = [
+
{
+
programs.gnome-shell.extensions = [
+
{package = pkgs.gnomeExtensions.tailscale-qs;}
];
-
})
+
}
+
];
+
+
networking.firewall = {
+
allowedUDPPorts = [config.services.tailscale.port];
+
trustedInterfaces = [config.services.tailscale.interfaceName];
+
};
+
+
services = {
+
caddy = lib.mkIf config.myNixOS.services.tailscale.enableCaddy {
+
enable = true;
-
{
-
services.tailscale = {
-
enable = true;
-
extraUpFlags = ["--ssh"];
-
extraSetFlags = ["--advertise-exit-node"];
-
extraDaemonFlags = ["--no-logs-no-support"];
-
openFirewall = true;
-
useRoutingFeatures = "both";
+
virtualHosts = {
+
"${config.networking.hostName}.${config.mySnippets.tailnet.name}".extraConfig = let
+
syncthing = ''
+
redir /syncthing /syncthing/
+
handle_path /syncthing/* {
+
reverse_proxy localhost:8384 {
+
header_up Host localhost
+
}
+
}
+
'';
+
in
+
lib.concatLines (
+
lib.optional config.services.syncthing.enable syncthing
+
);
};
-
}
-
]
-
);
+
};
+
+
tailscale = {
+
enable = true;
+
inherit (config.myNixOS.services.tailscale) authKeyFile;
+
+
extraUpFlags =
+
["--ssh"]
+
++ lib.optional (config.myNixOS.services.tailscale.operator != null)
+
"--operator ${config.myNixOS.services.tailscale.operator}";
+
+
extraSetFlags = ["--advertise-exit-node"];
+
extraDaemonFlags = ["--no-logs-no-support"];
+
+
openFirewall = true;
+
permitCertUid = lib.mkIf config.services.caddy.enable "caddy";
+
useRoutingFeatures = "both";
+
};
+
};
+
};
}
+9
modules/snippets/default.nix
···
+
{...}: {
+
imports = [
+
./nix
+
./ssh
+
./tailnet
+
./syncthing
+
./restic
+
];
+
}
+5
modules/snippets/nix/default.nix
···
+
{...}: {
+
imports = [
+
./settings.nix
+
];
+
}
+29
modules/snippets/nix/settings.nix
···
+
{lib, ...}: {
+
options = {
+
mySnippets.nix.settings = lib.mkOption {
+
type = lib.types.attrs;
+
description = "Default nix settings shared across machines.";
+
+
default = {
+
builders-use-substitutes = true;
+
+
experimental-features = [
+
"ca-derivations"
+
"fetch-closure"
+
"flakes"
+
"nix-command"
+
"recursive-nix"
+
];
+
+
substituters = [
+
"https://cache.nixos.org/"
+
];
+
+
trusted-public-keys = [
+
];
+
+
trusted-users = ["@admin" "@wheel" "nixbuild"];
+
};
+
};
+
};
+
}
+38
modules/snippets/restic/default.nix
···
+
{
+
config,
+
lib,
+
...
+
}: {
+
options = {
+
mySnippets.restic = lib.mkOption {
+
type = lib.types.attrs;
+
description = "Default restic backup settings shared across backup jobs.";
+
+
default = {
+
extraBackupArgs = [
+
"--cleanup-cache"
+
"--compression max"
+
"--no-scan"
+
];
+
+
inhibitsSleep = true;
+
initialize = true;
+
passwordFile = config.age.secrets.resticPassword.path;
+
+
pruneOpts = [
+
"--keep-daily 7"
+
"--keep-weekly 4"
+
"--keep-monthly 3"
+
];
+
+
rcloneConfigFile = config.age.secrets.rclone.path;
+
+
timerConfig = {
+
OnCalendar = "daily";
+
Persistent = true;
+
RandomizedDelaySec = "3h";
+
};
+
};
+
};
+
};
+
}
+5
modules/snippets/ssh/default.nix
···
+
{...}: {
+
imports = [
+
./knownHosts.nix
+
];
+
}
+28
modules/snippets/ssh/knownHosts.nix
···
+
{
+
config,
+
lib,
+
self,
+
...
+
}: {
+
options.mySnippets.ssh.knownHosts = lib.mkOption {
+
type = lib.types.attrs;
+
description = "Default ssh known hosts.";
+
+
default = {
+
morgana = {
+
hostNames = ["morgana" "morgana.local" "morgana.${config.mySnippets.tailnet.name}"];
+
publicKeyFile = "${self.inputs.secrets}/publicKeys/root_morgana.pub";
+
};
+
+
#nan = {
+
# hostNames = ["nanpi" "nanpi.local" "nanpi.${config.mySnippets.tailnet.name}"];
+
# publicKeyFile = "${self.inputs.secrets}/publicKeys/root_nanpi.pub";
+
#};
+
+
m23 = {
+
hostNames = ["m23" "m23.local" "m23.${config.mySnippets.tailnet.name}"];
+
publicKeyFile = "${self.inputs.secrets}/publicKeys/ayla_m23.pub";
+
};
+
};
+
};
+
}
+61
modules/snippets/syncthing/README.md
···
+
# 🔄 Syncthing Configuration
+
+
This snippet provides centralized Syncthing device and folder configurations for all hosts in the flake.
+
+
---
+
+
## 📂 Structure
+
+
- `default.nix` - Main module that imports device and folder configurations
+
- `devices.nix` - Defines all Syncthing devices with their IDs
+
- `folders.nix` - Defines shared folders and which devices sync them
+
+
---
+
+
## 🛠️ Adding New Devices
+
+
When provisioning a new host that should participate in Syncthing synchronization:
+
+
1. **Generate Syncthing certificates and device ID**:
+
+
```bash
+
syncthing -generate="$HOSTNAME"
+
```
+
+
2. **Extract device ID**:
+
- Locate the device ID in the generated `config.xml`
+
- The device ID is a long alphanumeric string in the format: `XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX-XXXXXXX`
+
+
3. **Add device to configuration**:
+
- Add the new device to the `devices.nix` file with its hostname and device ID
+
- Follow the existing format: `"hostname" = {id = "DEVICE-ID-HERE";};`
+
+
4. **Configure folder access**:
+
- Update `folders.nix` to include the new device in the appropriate folder device lists
+
- Add the hostname to the `devices` array for each folder the device should sync
+
+
5. **Encrypt certificates**:
+
- Encrypt the generated `cert.pem` and `key.pem` using `agenix`
+
- Store them in the secrets repository at `github.com/alyraffauf/secrets`
+
- Configure the host to use these encrypted certificates in its Syncthing service configuration
+
+
---
+
+
## 📋 Usage by Hosts
+
+
Hosts can reference the centralized device and folder configurations via either **NixOS** or **home-manager**.
+
+
```nix
+
{
+
services.syncthing = {
+
enable = true;
+
+
settings = {
+
devices = config.mySnippets.syncthing.devices;
+
folders = config.mySnippets.syncthing.folders;
+
};
+
};
+
}
+
```
+
+
This ensures all devices have a consistent view of the Syncthing network topology regardless of the configuration method used.
+6
modules/snippets/syncthing/default.nix
···
+
{...}: {
+
imports = [
+
./devices.nix
+
./folders.nix
+
];
+
}
+14
modules/snippets/syncthing/devices.nix
···
+
{lib, ...}: {
+
options = {
+
mySnippets.syncthing.devices = lib.mkOption {
+
description = "List of Syncthing devices.";
+
type = lib.types.attrs;
+
+
default = {
+
"m23" = {id = "EXW2FQP-LLGZTF3-UJ7IQ6D-CZB4UWB-ZQHM4GG-T6D4E2Q-ZOWSTG4-HJOKPQK";}; # Samsung Galaxy M23
+
"morgana" = {id = "IR327YY-QZD7HZX-F24BWPO-UXQAVGU-4M2WN3P-XCYPCGX-ZQKDLIV-BL6RNAR";}; # Acer Aspire A515-52G
+
"nanpi" = {id = "UBHN6T7-SLXLI4P-WVXQ35Q-OH4RPOI-RCVODK7-ASBJU6A-7BIEMYU-5ICYJAN";}; # The Red HP Laptop
+
};
+
};
+
};
+
}
+80
modules/snippets/syncthing/folders.nix
···
+
{lib, ...}: {
+
options = {
+
mySnippets.syncthing.folders = lib.mkOption {
+
description = "List of Syncthing folders.";
+
type = lib.types.attrs;
+
+
default = {
+
"Backups" = {
+
devices = [
+
"morgana"
+
"m23"
+
];
+
+
id = "cerbn-dj3xo";
+
path = "~/Backups";
+
};
+
+
"Books" = {
+
devices = [
+
"morgana"
+
"m23"
+
];
+
+
id = "1pnmb-naasx";
+
path = "/home/Data/Books";
+
};
+
+
"DCIM" = {
+
devices = [
+
"morgana"
+
"m23"
+
];
+
+
id = "dcfsw-meuwf";
+
path = "~/DCIM";
+
};
+
+
"Music" = {
+
devices = [
+
"morgana"
+
"m23"
+
];
+
+
id = "pacgr-fvsd7";
+
path = "~/Music";
+
};
+
+
"Passwords" = {
+
devices = [
+
"morgana"
+
"m23"
+
];
+
+
id = "mkiff-evvnj";
+
path = "~/Documents/Passwords";
+
};
+
+
"Pictures" = {
+
devices = [
+
"morgana"
+
"m23"
+
];
+
+
id = "u5d66-bcnho";
+
path = "~/Pictures";
+
};
+
+
"Koreader Settings" = {
+
devices = [
+
"morgana"
+
"m23"
+
];
+
+
id = "hkw65-lktvx";
+
path = "/home/Data/koreader";
+
};
+
};
+
};
+
};
+
}
+32
modules/snippets/tailnet/default.nix
···
+
{
+
config,
+
lib,
+
...
+
}: {
+
options.mySnippets.tailnet = {
+
name = lib.mkOption {
+
default = "cinnamon-is.ts.net";
+
description = "Tailnet name.";
+
type = lib.types.str;
+
};
+
+
networkMap = lib.mkOption {
+
type = lib.types.attrs;
+
description = "Hostnames, ports, and vHosts for ${config.mySnippets.tailnet.name} services.";
+
+
default = {
+
qbittorrent = {
+
hostName = "nanpi";
+
port = 8080;
+
vHost = "qbittorrent.${config.mySnippets.tailnet.name}";
+
};
+
+
jellyfin = {
+
hostName = "nanpi";
+
port = 8096;
+
vHost = "jellyfin.${config.mySnippets.tailnet.name}";
+
};
+
};
+
};
+
};
+
}
+17 -7
modules/users/ayla/default.nix
···
{
pkgs,
+
lib,
config,
+
self,
...
}: {
-
users.users.ayla = {
-
description = "Ayla";
-
isNormalUser = true;
-
extraGroups = config.myUsers.defaultGroups;
-
hashedPassword = config.myUsers.ayla.password;
-
uid = 1000;
-
shell = pkgs.fish;
+
config = lib.mkIf config.myUsers.ayla.enable {
+
users.users.ayla = {
+
description = "Ayla";
+
isNormalUser = true;
+
extraGroups = config.myUsers.defaultGroups;
+
hashedPassword = config.myUsers.ayla.password;
+
+
openssh.authorizedKeys.keyFiles =
+
lib.map (file: "${self.inputs.secrets}/publicKeys/${file}")
+
(lib.filter (file: lib.hasPrefix "ayla_" file)
+
(builtins.attrNames (builtins.readDir "${self.inputs.secrets}/publicKeys")));
+
+
uid = 1000;
+
shell = pkgs.fish;
+
};
};
}