Compare commits

...

95 Commits

Author SHA1 Message Date
Giulio De Pasquale
f6907766f0 Merge branch 'master' of ssh://git.giugl.io/peperunas/nixos 2025-06-05 16:59:06 +01:00
Giulio De Pasquale
31dc159727 fix(secrets): update publicKeys entry from "ovh.age" to "cloudflare.age" 2025-06-05 16:56:24 +01:00
Giulio De Pasquale
504f3590d3 chore(firewall): remove unused device entries from Tailscale configuration
- Removed outdated device entries (`dodino`, `chuck`) from Tailscale firewall configuration
2025-06-05 16:56:02 +01:00
Giulio De Pasquale
e6ddfcd153 chore(nextcloud): remove unused system packages nodejs-18_x and libtensorflow
- Removed deprecated or unused packages (`nodejs-18_x`, `libtensorflow`) from system dependencies
2025-06-05 16:55:52 +01:00
Giulio De Pasquale
09b6afc1ac chore(postgres): upgrade to postgresql_16
- Updated PostgreSQL package version from default to `postgresql_16` for compatibility and feature improvements
2025-06-05 16:55:44 +01:00
Giulio De Pasquale
39fbc03827 refactor(tailscale): restructure pepe.core configuration and add openUDP port 41641
- Restructured `pepe.core` configuration to include `firewall.openUDP` for port 41641
- Updated Tailscale network interface configuration with new device entries (`work_laptop`, `work_desktop`)
- Removed outdated device entries (`dodino`, `chuck`) from Tailscale configuration
2025-06-05 16:55:35 +01:00
Giulio De Pasquale
5c1abae02c refactor(hosts/architect): remove commented-out configurations and update headscale settings
- Removed commented-out `uiPackage`, `tikaPackage`, `frontendDomain`, and `environmentVariables` in llm configuration
- Removed commented-out `package` line for headscale
- Added `server_url` configuration for headscale
- Updated DNS settings with `magic_dns = false` and `override_local_dns = true`
2025-06-05 16:55:07 +01:00
Giulio De Pasquale
aabbff3ad4 chore(backup): add exclusion for /var/lib/ollama in backup configuration 2025-06-05 16:54:35 +01:00
Giulio De Pasquale
241973d56a chore(flake): update nixpkgs, nixos-unstable, home-manager versions and add cudaSupport
- Updated nixpkgs to commit 10d7f8d34e5eb9c0f9a0485186c1ca691d2c5922
- Updated nixos-unstable to commit c2a03962b8e24e669fb37b7df10e7c79531ff1a4
- Upgraded home-manager to release-25.05
- Added cudaSupport = true to Linux x64 CUDA package configuration
2025-06-05 16:54:12 +01:00
Giulio De Pasquale
0da5018e8c chore(host.nix): update system.stateVersion to "25.05"
- Bumped NixOS system state version from 24.11 to 25.05
2025-06-05 16:53:51 +01:00
Giulio De Pasquale
184f039e40 refactor(dns/network): replace dnsResolvableName with hostname and restructure DNS record generation
- Replaced `dnsResolvableName` with `hostname` in device configuration options
- Updated DNS record generation logic to use `hostname` instead of domain-based naming
- Removed deprecated `dnsResolvableName` option from network module
- Restructured DNS record templates to use consistent formatting
- Simplified code structure by removing redundant whitespace and reorganizing attribute definitions
- Updated `generateDeviceHostRecords` to use new naming convention and improved template syntax
2025-06-05 16:53:35 +01:00
Giulio De Pasquale
0e513e1c69 chore(home): update stateVersion to "25.05"
- Bumped Home Manager state version from 24.11 to 25.05
2025-06-05 16:52:48 +01:00
Giulio De Pasquale
6fafab2e5c chore(update_cached_hashes): update RELEASE version to 25.05
- Changed RELEASE variable from 24.11 to 25.05 in the script
- This affects cached hash updates for the new release version
- No functional changes, only build configuration update
2025-06-05 16:52:28 +01:00
Giulio De Pasquale (aider)
2af3952cf5 fix: Join extra hosts list into single string 2025-06-05 12:58:08 +01:00
Giulio De Pasquale (aider)
c2d96e936e fix: Correctly generate extraHosts for vhosts 2025-06-05 12:56:55 +01:00
Giulio De Pasquale (aider)
7217af2233 feat: Add local vhost resolution via extraHosts 2025-06-05 12:50:30 +01:00
Giulio De Pasquale (aider)
44af2887a5 feat: Allow network devices to define DNS resolvable names 2025-06-05 12:42:14 +01:00
Giulio De Pasquale (aider)
9e8e7169d3 refactor: Use mkMerge to combine LLM module configs 2025-06-04 15:44:29 +01:00
Giulio De Pasquale
317803eb5a refactor: Restructure LLM module options and vhost creation 2025-06-04 15:44:27 +01:00
Giulio De Pasquale
46cb8d1c7e remove old llm file 2025-06-04 15:41:49 +01:00
Giulio De Pasquale
60c447024d fix(gitea): disabel registartion 2025-06-04 13:19:59 +01:00
Giulio De Pasquale (aider)
2afe7dc76c refactor: Use freeform type for headscale settings option 2025-06-04 12:58:30 +01:00
Giulio De Pasquale
c3a2c54b13 fix(acme): switch to cloudflare 2025-06-04 12:44:39 +01:00
Giulio De Pasquale
388a11a76e fix: update hosts 2025-05-16 12:10:08 +01:00
Giulio De Pasquale
d2b361e82b bump: bump 2025-05-06 13:00:56 +01:00
Giulio De Pasquale
7053b64156 refactor(network-config): update configuration references to use pepe.core.network.interfaces
- Refactored config references from `config.architect.networks` to `config.pepe.core.network.interfaces` across multiple files
- Updated `fail2ban.nix`, `firewall.nix`, `tailscale.nix`, and `utilities.nix` to align with new configuration structure
- Centralized network interface configuration under `pepe.core` for better maintainability
- Maintained existing functionality while modernizing configuration hierarchy
2025-05-06 12:57:02 +01:00
Giulio De Pasquale
9277af4088 refactor(nix): move headscale configuration into main file and remove import
- Removed `./headscale.nix` from `imports` section
- Added `headscale` configuration under `pepe.core` with:
  - Domain: `vipienne.giugl.io`
  - Network settings with IPv4 prefixes and DNS configuration
  - Debug logging enabled
- Removed `docker` configuration block from `pepe.core` (separate refactor)
2025-05-06 12:56:25 +01:00
Giulio De Pasquale
e8afefea50 refactor(headscale): restructure headscale module and improve configuration
- Migrated headscale configuration to dedicated module file
- Added host configuration option for Headscale service
- Restructured settings configuration with nested options
- Improved type definitions for configuration parameters
- Added security headers in virtual host configuration
- Fixed formatting in vhost configuration
- Corrected typo in useACMEHost configuration
2025-05-06 12:55:27 +01:00
Giulio De Pasquale (aider)
4fa79d642f <think>
Okay, let's see. The user wants to port the architect/headscale.nix to a module. The existing code is in the architect directory, and they want to move it to a module structure.

First, I need to understand what the original file does. It seems to be configuring Headscale with specific settings, ports, and vhost configurations. The new module should encapsulate these settings into a reusable module.

Looking at the diffs, the new module is created under modules/services/headscale.nix. The module defines options for enabling the service, package, domain, port, and settings. The config section sets up the service, vhost, and firewall rules.

The commit message needs to be concise. The type is 'refactor' because it's restructuring the code into a module. The description should mention moving the configuration to a module and making it reusable. Keeping it under 72 characters.

So, "refactor: move headscale configuration to a reusable module" seems appropriate. It starts with 'refactor', uses imperative mood, and is within the character limit.
</think>

refactor: move headscale configuration to a reusable module
2025-05-06 11:53:27 +01:00
Giulio De Pasquale (aider)
db884c9e86 feat: port Docker configuration to new modular structure 2025-04-28 15:31:05 +01:00
Giulio De Pasquale (aider)
cbd6725b2a feat: enable redlib and llm services in architect configuration 2025-04-28 09:59:04 +01:00
Giulio De Pasquale (aider)
51517d8914 feat: port redlib and llm services to new modules structure 2025-04-28 09:58:03 +01:00
Giulio De Pasquale
3ba686f159 feat: port home assistant (part 1) 2025-04-26 23:39:39 +01:00
Giulio De Pasquale (aider)
0d8776d8e7 feat: migrate Home Assistant configuration to new module structure in architect host 2025-04-26 23:11:09 +01:00
Giulio De Pasquale
f6b1d1d71c fix: remove duplicate homeassistant.nix import in architect host config 2025-04-26 23:11:07 +01:00
Giulio De Pasquale (aider)
431e7fac05 feat: port homeassistant.nix to modules/services/ structure 2025-04-26 23:10:36 +01:00
Giulio De Pasquale
a0331deac3 delete 2025-04-26 19:43:46 +01:00
Giulio De Pasquale
52a5a7e7d2 fix: other services 2025-04-26 19:43:22 +01:00
Giulio De Pasquale
353f5822bf delete 2025-04-26 19:31:26 +01:00
Giulio De Pasquale
4369735976 stuff 2025-04-26 19:31:05 +01:00
Giulio De Pasquale (aider)
9c71d75363 feat: add DNS endpoint configuration to network and DNS modules 2025-04-26 19:14:49 +01:00
Giulio De Pasquale
3508ebc879 refactor: simplify DNS configuration generation and remove processDomainsFirst option 2025-04-26 19:14:48 +01:00
Giulio De Pasquale (aider)
c1baa0eb65 feat: Add processDomainsFirst option to DNS module for flexible CoreDNS configuration 2025-04-26 19:06:59 +01:00
Giulio De Pasquale
a022b2d0ce MASSIVE 2025-04-26 17:43:50 +01:00
Giulio De Pasquale (aider)
1a54c00cc2 refactor: simplify DNS configuration for vhosts with dynamic interface detection 2025-04-26 17:31:07 +01:00
Giulio De Pasquale
301629243e fix: update AdGuard DNS interface configuration in dns.nix 2025-04-26 17:31:05 +01:00
Giulio De Pasquale (aider)
48b86055a0 refactor: port hosts/architect/dns.nix to new modules/core/dns.nix structure 2025-04-26 17:24:01 +01:00
Giulio De Pasquale (aider)
70c39b782b refactor: migrate architect to use core MinIO service module 2025-04-26 17:18:45 +01:00
Giulio De Pasquale (aider)
9b945b0a84 feat: port MinIO service to new modular services structure 2025-04-26 17:18:09 +01:00
Giulio De Pasquale (aider)
c7e579ec95 fix: update vhost.nix to handle interface names correctly 2025-04-26 17:14:55 +01:00
Giulio De Pasquale (aider)
738b0e9577 fix: modify network interface type handling to resolve Nix type error 2025-04-26 17:14:17 +01:00
Giulio De Pasquale (aider)
a5232f522b refactor: replace network groups with direct interface type access 2025-04-26 17:12:46 +01:00
Giulio De Pasquale (aider)
2c350070a3 feat: add network groups and interface types to network module 2025-04-26 17:11:52 +01:00
Giulio De Pasquale (aider)
b1065f61d9 refactor: use interface CIDR ranges instead of network groups in vhost.nix 2025-04-26 17:11:22 +01:00
Giulio De Pasquale (aider)
89aa2e7f20 refactor: use network groups for allowLAN/VPN in vhost configuration 2025-04-26 17:10:46 +01:00
Giulio De Pasquale
985d325885 refactor: remove unused allowLan option from vhost module 2025-04-26 17:10:45 +01:00
Giulio De Pasquale (aider)
894bc74667 feat: add interfacesByType option to network module for type-based interface access 2025-04-26 17:09:33 +01:00
Giulio De Pasquale
2d4bdd0cfd refactor: update network interface types and configuration 2025-04-26 17:09:32 +01:00
Giulio De Pasquale (aider)
309872f4f2 refactor: migrate architect network config to pepe.core.network module structure 2025-04-26 17:06:29 +01:00
Giulio De Pasquale (aider)
9f0a119c8e refactor: remove interfaceTypes and simplify network interface type filtering 2025-04-26 17:05:48 +01:00
Giulio De Pasquale (aider)
d3e8f402a9 feat: add interface type and categorize interfaces by type in network module 2025-04-26 17:04:50 +01:00
Giulio De Pasquale (aider)
87511fc1b8 refactor: abstract vhost allow rules with new allowVPN, allowLAN, allowWAN options 2025-04-26 16:58:23 +01:00
Giulio De Pasquale (aider)
88990545ed refactor: Introduce interface types for network configuration 2025-04-26 16:57:07 +01:00
Giulio De Pasquale (aider)
08ae792712 refactor: Migrate network, vhost, and firewall configurations to new pepe.core namespace 2025-04-26 16:55:36 +01:00
Giulio De Pasquale (aider)
8c72ff433c feat: add jellyseer, lidarr, navidrome, and nzbget service modules 2025-04-26 16:53:16 +01:00
Giulio De Pasquale (aider)
3c44bbc034 feat: add Jellyfin service module with configuration options 2025-04-26 16:51:50 +01:00
Giulio De Pasquale (aider)
a44533a0e0 feat: add Bazarr service module with configuration options 2025-04-26 16:51:24 +01:00
Giulio De Pasquale (aider)
35035111e7 feat: add Prowlarr service module with configuration options 2025-04-26 16:50:42 +01:00
Giulio De Pasquale (aider)
296609fdfb feat: migrate sonarr to new modular service structure 2025-04-26 16:50:09 +01:00
Giulio De Pasquale
5601a2cab0 fix: do not force graphics on architect 2025-04-26 16:47:26 +01:00
Giulio De Pasquale
6bf0fc0967 feat: move more stuff into graphics 2025-04-26 16:46:22 +01:00
Giulio De Pasquale
9a0b8d3917 feat: start moving graphics/ 2025-04-26 16:38:04 +01:00
Giulio De Pasquale
8808298c29 feat: move radarr to modules/ 2025-04-26 16:31:53 +01:00
Giulio De Pasquale
c2b89b7fc5 fix: use media in hardware 2025-04-26 16:27:23 +01:00
Giulio De Pasquale
eec1a9c66a feat: added media module 2025-04-26 16:27:13 +01:00
Giulio De Pasquale
d40f064925 feat: switch immich to modules/ 2025-04-26 14:51:16 +01:00
Giulio De Pasquale
ddc4d884b7 feat: first switch to modules with gitea 2025-04-26 14:44:46 +01:00
Giulio De Pasquale
955b9f4cfb feat: immich 2025-04-26 13:46:45 +01:00
Giulio De Pasquale
bd95960c84 bump(nextcloud): 31 2025-04-24 13:03:07 +01:00
Giulio De Pasquale
ab817ede3e bump: flake: 2025-04-24 12:52:57 +01:00
Giulio De Pasquale
95c5be3098 fix: use stable aichat 2025-04-24 11:37:39 +01:00
Giulio De Pasquale
b2091de9c9 fix(home/common): use aichat instead of aichat-full 2025-04-24 11:37:14 +01:00
Giulio De Pasquale
970b75b064 fix(tailscale): fixed names 2025-04-24 11:36:50 +01:00
Giulio De Pasquale
2f3470cf50 fix(dns): fallback to lan 2025-04-24 11:36:27 +01:00
Giulio De Pasquale
df91ea0fb9 fix: update hosts 2025-04-22 16:52:04 +01:00
Giulio De Pasquale
e6c5b780df feat(dns): per-host dns 2025-04-22 16:47:15 +01:00
Giulio De Pasquale (aider)
f3dfa9543e feat: add unique CoreDNS views for each VPN-defined host with forwarding 2025-04-22 16:30:32 +01:00
Giulio De Pasquale
6a21b5b40a feat(ignore): aider ignore 2025-04-22 15:24:33 +01:00
Giulio De Pasquale
aba86e6d02 feat: TLS dns 2025-04-22 15:19:04 +01:00
Giulio De Pasquale
abbb655383 blah 2025-04-22 12:26:18 +01:00
Giulio De Pasquale
a7b03d9b9a fix: nixpkgs-unstable -> nixos-unstable 2025-04-22 12:16:01 +01:00
Giulio De Pasquale
a467cbe6dc bump: lock 2025-04-22 12:03:40 +01:00
Giulio De Pasquale
63a6642f8c refactor(update_cached_hashes.sh): modularize and update hash handling 2025-04-22 12:01:40 +01:00
Giulio De Pasquale
c47c8a42ee refactor: nixos-* -> nixpkgs-* 2025-04-22 12:00:45 +01:00
Giulio De Pasquale
dd151c9f1a fix(update_cached_hashes.sh): update script to correctly parse and handle hash changes 2025-04-22 11:14:58 +01:00
60 changed files with 1814 additions and 1232 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
result
result/
.aider*
.env

435
flake.lock generated
View File

@ -8,11 +8,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1736955230,
"narHash": "sha256-uenf8fv2eG5bKM8C/UvFaiJMZ4IpUFaQxk9OH5t/1gA=",
"lastModified": 1747575206,
"narHash": "sha256-NwmAFuDUO/PFcgaGGr4j3ozG9Pe5hZ/ogitWhY+D81k=",
"owner": "ryantm",
"repo": "agenix",
"rev": "e600439ec4c273cf11e06fe4d9d906fb98fa097c",
"rev": "4835b1dc898959d8547a871ef484930675cb47f1",
"type": "github"
},
"original": {
@ -21,37 +21,6 @@
"type": "github"
}
},
"cachix": {
"inputs": {
"devenv": [
"teslamate-flake",
"devenv"
],
"flake-compat": [
"teslamate-flake",
"devenv"
],
"git-hooks": [
"teslamate-flake",
"devenv"
],
"nixpkgs": "nixpkgs_4"
},
"locked": {
"lastModified": 1728672398,
"narHash": "sha256-KxuGSoVUFnQLB2ZcYODW7AVPAh9JqRlD5BrfsC/Q4qs=",
"owner": "cachix",
"repo": "cachix",
"rev": "aac51f698309fd0f381149214b7eee213c66ef0a",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "latest",
"repo": "cachix",
"type": "github"
}
},
"darwin": {
"inputs": {
"nixpkgs": [
@ -60,11 +29,11 @@
]
},
"locked": {
"lastModified": 1700795494,
"narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=",
"lastModified": 1744478979,
"narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d",
"rev": "43975d782b418ebf4969e9ccba82466728c2851b",
"type": "github"
},
"original": {
@ -74,154 +43,6 @@
"type": "github"
}
},
"devenv": {
"inputs": {
"cachix": "cachix",
"flake-compat": "flake-compat",
"git-hooks": "git-hooks",
"nix": "nix",
"nixpkgs": "nixpkgs_6"
},
"locked": {
"lastModified": 1732298876,
"narHash": "sha256-WXlcDNMaMJeI4JO4VfQM2ZZCBJBds7j7N04tS9UjiYU=",
"owner": "cachix",
"repo": "devenv",
"rev": "741e23a22f3dc9e53075be3eaa795ea9ed6f5129",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"devenv-root": {
"flake": false,
"locked": {
"narHash": "sha256-d6xi4mKdjkX2JFicDIv5niSzpyI0m/Hnm8GGAIU04kY=",
"type": "file",
"url": "file:///dev/null"
},
"original": {
"type": "file",
"url": "file:///dev/null"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"teslamate-flake",
"devenv",
"nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1712014858,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": [
"teslamate-flake",
"nixpkgs"
]
},
"locked": {
"lastModified": 1730504689,
"narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "506278e768c2a08bec68eb62932193e341f55c90",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": [
"teslamate-flake",
"devenv"
],
"gitignore": "gitignore",
"nixpkgs": [
"teslamate-flake",
"devenv",
"nixpkgs"
],
"nixpkgs-stable": [
"teslamate-flake",
"devenv"
]
},
"locked": {
"lastModified": 1730302582,
"narHash": "sha256-W1MIJpADXQCgosJZT8qBYLRuZls2KSiKdpnTVdKBuvU=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "af8a16fe5c264f5e9e18bcee2859b40a656876cf",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"teslamate-flake",
"devenv",
"git-hooks",
"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"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
@ -230,11 +51,11 @@
]
},
"locked": {
"lastModified": 1703113217,
"narHash": "sha256-7ulcXOk63TIT2lVDSExj7XzFx09LpdSAPtvgtM7yQPE=",
"lastModified": 1745494811,
"narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "3bfaacf46133c037bb356193bd2f1765d9dc82c1",
"rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be",
"type": "github"
},
"original": {
@ -250,40 +71,24 @@
]
},
"locked": {
"lastModified": 1743387206,
"narHash": "sha256-24N3NAuZZbYqZ39NgToZgHUw6M7xHrtrAm18kv0+2Wo=",
"lastModified": 1748665073,
"narHash": "sha256-RMhjnPKWtCoIIHiuR9QKD7xfsKb3agxzMfJY8V9MOew=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "15c5f9d04fabd176f30286c8f52bbdb2c853a146",
"rev": "282e1e029cb6ab4811114fc85110613d72771dea",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "release-24.11",
"ref": "release-25.05",
"repo": "home-manager",
"type": "github"
}
},
"libgit2": {
"flake": false,
"locked": {
"lastModified": 1697646580,
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
"owner": "libgit2",
"repo": "libgit2",
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
"type": "github"
},
"original": {
"owner": "libgit2",
"repo": "libgit2",
"type": "github"
}
},
"local-unstable": {
"locked": {
"lastModified": 0,
"narHash": "sha256-uewgkTWbDOpOP+wEA3f03XEKsPHsJi0iDqBGQnxWQo0=",
"narHash": "sha256-eCA4jXsPHiBkrf1sNOfQPYS2g9DoCsICVzk4ec0cEdo=",
"path": "/home/giulio/dev/nixpkgs",
"type": "path"
},
@ -292,82 +97,29 @@
"type": "path"
}
},
"nix": {
"inputs": {
"flake-compat": [
"teslamate-flake",
"devenv"
],
"flake-parts": "flake-parts",
"libgit2": "libgit2",
"nixpkgs": "nixpkgs_5",
"nixpkgs-23-11": [
"teslamate-flake",
"devenv"
],
"nixpkgs-regression": [
"teslamate-flake",
"devenv"
],
"pre-commit-hooks": [
"teslamate-flake",
"devenv"
]
},
"locked": {
"lastModified": 1727438425,
"narHash": "sha256-X8ES7I1cfNhR9oKp06F6ir4Np70WGZU5sfCOuNBEwMg=",
"owner": "domenkozar",
"repo": "nix",
"rev": "f6c5ae4c1b2e411e6b1e6a8181cc84363d6a7546",
"type": "github"
},
"original": {
"owner": "domenkozar",
"ref": "devenv-2.24",
"repo": "nix",
"type": "github"
}
},
"nixos-master": {
"locked": {
"lastModified": 1743784178,
"narHash": "sha256-rxchbu1Zcthv7fV+KWiF79SjUaeMe3tiK5qYhg+u+pA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d142f5ee8a1bc234868d9ea5bcc7c0db708651e1",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "master",
"repo": "nixpkgs",
"type": "github"
}
},
"nixos-unstable": {
"locked": {
"lastModified": 1743689281,
"narHash": "sha256-y7Hg5lwWhEOgflEHRfzSH96BOt26LaYfrYWzZ+VoVdg=",
"lastModified": 1748929857,
"narHash": "sha256-lcZQ8RhsmhsK8u7LIFsJhsLh/pzR9yZ8yqpTzyGdj+Q=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2bfc080955153be0be56724be6fa5477b4eefabb",
"rev": "c2a03962b8e24e669fb37b7df10e7c79531ff1a4",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"rev": "c2a03962b8e24e669fb37b7df10e7c79531ff1a4",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1703013332,
"narHash": "sha256-+tFNwMvlXLbJZXiMHqYq77z/RfmpfpiI3yjL6o/Zo9M=",
"lastModified": 1745391562,
"narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "54aac082a4d9bb5bbc5c4e899603abfb76a3f6d6",
"rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
"type": "github"
},
"original": {
@ -377,19 +129,35 @@
"type": "github"
}
},
"nixpkgs_2": {
"nixpkgs-master": {
"locked": {
"lastModified": 1744440957,
"narHash": "sha256-FHlSkNqFmPxPJvy+6fNLaNeWnF1lZSgqVCl/eWaJRc4=",
"lastModified": 1749040375,
"narHash": "sha256-zwVvfxgrXcInI2E/dDg9v80OrvKUT7HtPECu53Khcq0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "26d499fc9f1d567283d5d56fcf367edd815dba1d",
"rev": "57afa2783caf7d6713f63c8e29fba6c52a3a5300",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "master",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1748889542,
"narHash": "sha256-Hb4iMhIbjX45GcrgOp3b8xnyli+ysRPqAgZ/LZgyT5k=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "10d7f8d34e5eb9c0f9a0485186c1ca691d2c5922",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "26d499fc9f1d567283d5d56fcf367edd815dba1d",
"rev": "10d7f8d34e5eb9c0f9a0485186c1ca691d2c5922",
"type": "github"
}
},
@ -409,70 +177,6 @@
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1730531603,
"narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_5": {
"locked": {
"lastModified": 1717432640,
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_6": {
"locked": {
"lastModified": 1716977621,
"narHash": "sha256-Q1UQzYcMJH4RscmpTkjlgqQDX5yi1tZL0O345Ri6vXQ=",
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "4267e705586473d3e5c8d50299e71503f16a6fb6",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"nixpkgs_7": {
"locked": {
"lastModified": 1732014248,
"narHash": "sha256-y/MEyuJ5oBWrWAic/14LaIr/u5E0wRVzyYsouYY3W6w=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "23e89b7da85c3640bbc2173fe04f4bd114342367",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nvidia-patch": {
"inputs": {
"nixpkgs": [
@ -481,11 +185,11 @@
"utils": "utils"
},
"locked": {
"lastModified": 1743670877,
"narHash": "sha256-OHuOhVCfx10VpWwl9T5Q+QB3To0N95flBR1rSwOiUHA=",
"lastModified": 1748931931,
"narHash": "sha256-0NUhiMITsYlXDjgcVbLayI0rgrEdf5NIbpW3oLueYUs=",
"owner": "icewind1991",
"repo": "nvidia-patch-nixos",
"rev": "e80a4919e88a8cb496f649234fb3fc7e992ece10",
"rev": "fa8f006a236349790c94801ac85e43f103b35baf",
"type": "github"
},
"original": {
@ -517,12 +221,11 @@
"agenix-flake": "agenix-flake",
"home-manager": "home-manager_2",
"local-unstable": "local-unstable",
"nixos-master": "nixos-master",
"nixos-unstable": "nixos-unstable",
"nixpkgs": "nixpkgs_2",
"nixpkgs-master": "nixpkgs-master",
"nvidia-patch": "nvidia-patch",
"pepeflake": "pepeflake",
"teslamate-flake": "teslamate-flake"
"pepeflake": "pepeflake"
}
},
"systems": {
@ -555,50 +258,6 @@
"type": "github"
}
},
"teslamate-flake": {
"inputs": {
"devenv": "devenv",
"devenv-root": "devenv-root",
"flake-parts": "flake-parts_2",
"nixpkgs": "nixpkgs_7",
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1732358620,
"narHash": "sha256-diQRtJYfzGIVLxrdBad3XKWCtR97rj9Q1ZJ9MmvJGRk=",
"owner": "teslamate-org",
"repo": "teslamate",
"rev": "0ec408c8e182fe64e9568b6f137cbfb528717e8e",
"type": "github"
},
"original": {
"owner": "teslamate-org",
"ref": "v1.32.0",
"repo": "teslamate",
"type": "github"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"teslamate-flake",
"nixpkgs"
]
},
"locked": {
"lastModified": 1732292307,
"narHash": "sha256-5WSng844vXt8uytT5djmqBCkopyle6ciFgteuA9bJpw=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "705df92694af7093dfbb27109ce16d828a79155f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
},
"utils": {
"inputs": {
"systems": "systems_2"

View File

@ -1,14 +1,13 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/26d499fc9f1d567283d5d56fcf367edd815dba1d";
nixos-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
nixos-master.url = "github:NixOS/nixpkgs/master";
nixpkgs.url = "github:NixOS/nixpkgs/10d7f8d34e5eb9c0f9a0485186c1ca691d2c5922";
nixos-unstable.url = "github:NixOS/nixpkgs/c2a03962b8e24e669fb37b7df10e7c79531ff1a4";
nixpkgs-master.url = "github:NixOS/nixpkgs/master";
local-unstable.url = "path:///home/giulio/dev/nixpkgs";
pepeflake.url = "git+https://git.giugl.io/peperunas/pepeflake";
teslamate-flake.url = "github:teslamate-org/teslamate/v1.32.0";
agenix-flake.url = "github:ryantm/agenix";
home-manager = {
url = "github:nix-community/home-manager/release-24.11";
url = "github:nix-community/home-manager/release-25.05";
inputs.nixpkgs.follows = "nixpkgs";
};
nvidia-patch = {
@ -21,10 +20,9 @@
{ self
, nixpkgs
, nixos-unstable
, nixos-master
, nixpkgs-master
, local-unstable
, home-manager
, teslamate-flake
, nvidia-patch
, agenix-flake
, pepeflake
@ -62,16 +60,14 @@
};
unstablePkgs = importNixpkgs { flake = nixos-unstable; };
masterPkgs = importNixpkgs { flake = nixos-master; };
masterPkgs = importNixpkgs { flake = nixpkgs-master; };
localPkgs = importNixpkgs { flake = local-unstable; };
teslamatePkgs = importNixpkgs { flake = teslamate-flake; };
agenixPkgs = importNixpkgs { flake = agenix-flake; };
pepePkgs = pepeflake.packages.${system} // pepeflake.legacyPackages.${system} or { };
additionalOverlays = [
(final: prev: { inherit unstablePkgs; })
(final: prev: { inherit localPkgs; })
(final: prev: { inherit teslamatePkgs; })
(final: prev: { inherit agenixPkgs; })
(final: prev: { inherit masterPkgs; })
(final: prev: { inherit pepePkgs; })
@ -104,7 +100,7 @@
});
pkgsLinuxX64Cuda = wrapPkgsSystem { system = sysLinuxX64; };
pkgsLinuxX64Cuda = wrapPkgsSystem { system = sysLinuxX64; cudaSupport = true; };
utilsLinuxX64Cuda = wrapUtils { pkgs = pkgsLinuxX64Cuda; };
pkgsLinuxAarch = wrapPkgsSystem { system = sysLinuxAarch; };
@ -122,7 +118,6 @@
roles = [ ];
}];
imports = [
teslamate-flake.nixosModules.default
agenix-flake.nixosModules.default
];
};

View File

@ -17,6 +17,9 @@
environmentFile = config.age.secrets.restic-environment.path;
repository = "b2:architect:/";
paths = [ "/var/lib" "/services" ];
exclude = [
"/var/lib/ollama"
];
pruneOpts = [
"--keep-daily 45"
"--keep-weekly 12"

View File

@ -1,25 +0,0 @@
{ config, lib, ... }:
let
domain = "htbaz.giugl.io";
in
{
services.bazarr = {
enable = true;
group = "media";
};
architect.vhost.${domain} = with config.architect.networks; {
dnsInterfaces = [ "tailscale" ];
locations."/" = {
allowLan = true;
port = 6767;
allow = [
tailscale.net
];
};
};
users.groups.media.members = [ "bazarr" ];
}

View File

@ -1,12 +1,9 @@
{ config, pkgs, lib, ... }:
{ config, pkgs, ... }:
let
macbookPubkey = (import ../pubkeys.nix).macbook;
pubkeys = [ macbookPubkey ];
domain = "devs.giugl.io";
utilities = import ./utilities.nix { inherit lib config; };
inherit (utilities) generateDeviceStrings;
in
{
imports = [
@ -15,46 +12,20 @@ in
./hardware.nix
./firewall.nix
./nginx.nix
./gitea.nix
./sonarr.nix
./radarr.nix
./bazarr.nix
./nzbget.nix
./nextcloud.nix
./minio.nix
./matrix.nix
./fail2ban.nix
./dns.nix
# ./minecraft.nix
./prowlarr.nix
./redlib.nix
# ./invidious.nix
./jellyfin.nix
# ./docker.nix
./tailscale.nix
./headscale.nix
./llm.nix
# ./photoprism.nix
./sunshine.nix
./jellyseer.nix
./postgres.nix
./netdata.nix
./homeassistant.nix
./searx.nix
];
age.identityPaths = [ "/root/.ssh/id_ed25519" ];
architect = {
networks.lan = {
interface = "enp6s0";
net = "10.0.0.0/24";
devices = {
architect = { address = "10.0.0.250"; hostname = "architect.${domain}"; };
router = { address = "10.0.0.1"; hostname = "router.${domain}"; };
dvr = { address = "10.0.0.3"; hostname = "dvr.${domain}"; };
};
};
firewall = {
openTCP = [ 22 ];
@ -77,8 +48,8 @@ in
};
};
kernelParams = with config.architect.networks.lan; [
"ip=${devices.architect.address}::${devices.router.address}:255.255.255.0::${interface}:off"
kernelParams = with config.pepe.core.network.interfaces.lan; [
"ip=${devices.architect.address}::${devices.brigettine.address}:255.255.255.0::${interface}:off"
];
kernel.sysctl = { "net.ipv4.ip_forward" = 1; };
@ -96,42 +67,17 @@ in
tmp.tmpfsSize = "50%";
};
networking = with config.architect.networks.lan; {
networking = with config.pepe.core.network.interfaces.lan; {
hostName = "architect";
hostId = "49350853";
useDHCP = false;
defaultGateway = devices.router.address;
defaultGateway = devices.brigettine.address;
interfaces = {
${interface}.ipv4.addresses = [{
address = devices.architect.address;
prefixLength = 24;
}];
};
extraHosts = (generateDeviceStrings config.architect.networks.lan.devices) + ''
# Blacklist
0.0.0.0 metrics.plex.tv
0.0.0.0 analytics.plex.tv
0.0.0.0 cdn.luckyorange.com
0.0.0.0 w1.luckyorange.com
0.0.0.0 browser.sentry-cdn.com
0.0.0.0 analytics.facebook.com
0.0.0.0 ads.facebook.com
0.0.0.0 extmaps-api.yandex.net
0.0.0.0 logservice.hicloud.com
0.0.0.0 logbak.hicloud.com
0.0.0.0 logservice1.hicloud.com
0.0.0.0 samsung-com.112.2o7.net
0.0.0.0 supportmetrics.apple.com
0.0.0.0 analytics.oneplus.cn
0.0.0.0 click.oneplus.cn
0.0.0.0 analytics-api.samsunghealthcn.com
'';
};
hardware.opengl = {
enable = true;
extraPackages = with pkgs; [ vaapiVdpau ];
};
services = {
@ -153,5 +99,177 @@ in
};
smartd.enable = true;
};
pepe = {
core = {
media = {
enable = true;
path = "/media";
};
network.interfaces = {
lan = {
interface = "enp6s0";
type = "lan";
net = "10.0.0.0/24";
devices = {
architect = { address = "10.0.0.250"; hostname = "architect.${domain}"; isEndpoint = true; };
brigettine = { address = "10.0.0.1"; hostname = "router.${domain}"; };
dreamel10 = { address = "10.0.0.199"; hostname = "dreamel10.${domain}"; };
reolinkcamera = { address = "10.0.0.200"; hostname = "reolinkcamera.${domain}"; };
lgtv = { address = "10.0.0.202"; hostname = "lgtv.${domain}"; };
};
};
};
};
services = {
gitea = {
enable = true;
domain = "git.giugl.io";
};
immich = {
enable = true;
domain = "photos.giugl.io";
package = pkgs.unstablePkgs.immich;
};
radarr = {
enable = true;
domain = "htrad.giugl.io";
package = pkgs.unstablePkgs.radarr;
};
sonarr = {
enable = true;
domain = "htson.giugl.io";
package = pkgs.unstablePkgs.sonarr;
};
bazarr = {
enable = true;
domain = "htbaz.giugl.io";
package = pkgs.unstablePkgs.bazarr;
};
nzbget = {
enable = true;
domain = "htnzb.giugl.io";
package = pkgs.unstablePkgs.nzbget;
};
jellyfin = {
enable = true;
domain = "media.giugl.io";
package = pkgs.unstablePkgs.jellyfin;
};
jellyseer = {
enable = true;
domain = "aumm-aumm.giugl.io";
};
prowlarr = {
enable = true;
domain = "htpro.giugl.io";
};
redlib = {
enable = true;
domain = "reddit.giugl.io";
package = pkgs.unstablePkgs.redlib;
settings = {
REDLIB_ROBOTS_DISABLE_INDEXING = "on";
REDLIB_DEFAULT_THEME = "dracula";
REDLIB_DEFAULT_SHOW_NSFW = "on";
REDLIB_DEFAULT_BLUR_NSFW = "off";
REDLIB_DEFAULT_USE_HLS = "on";
REDLIB_DEFAULT_HIDE_HLS_NOTIFICATION = "on";
};
};
llm = {
enable = true;
package = pkgs.unstablePkgs.ollama-cuda;
backendDomain = "ollama.giugl.io";
acceleration = "cuda";
};
homeassistant = {
enable = true;
package = pkgs.unstablePkgs.home-assistant;
domain = "home.giugl.io";
extraComponents = [
"otbr"
"litterrobot"
"apple_tv"
"homekit"
"homekit_controller"
"spotify"
"hue"
"sonos"
"tplink"
"ollama"
"wyoming"
"whisper"
"piper"
"isal"
"radarr"
"sonarr"
"mqtt"
"mqtt_eventstream"
"mqtt_json"
"mqtt_room"
"mqtt_statestream"
"github"
"webostv"
"reolink"
"onvif"
"xiaomi_miio"
"ring"
];
extraPackages = python3Packages: with pkgs.unstablePkgs.python3Packages; [
pyporscheconnectapi
];
config = {
http = {
server_host = "127.0.0.1";
server_port = 8123;
use_x_forwarded_for = true;
trusted_proxies = [ "127.0.0.1" ];
};
homeassistant = {
name = "Brigettine Square";
latitude = 52.1958;
longitude = 0.180746;
unit_system = "metric";
};
default_config = { };
automation = "!include automations.yaml";
frontend.themes = "!include_dir_merge_named themes";
};
};
headscale = {
enable = true;
domain = "vipienne.giugl.io";
settings = with config.pepe.core.network.interfaces.tailscale; {
server_url = "https://${domain}";
prefixes.v4 = net;
dns = {
magic_dns = false;
override_local_dns = true;
global = [ devices.architect.address ];
nameservers.global = [ devices.architect.address ];
};
log.level = "debug";
};
};
};
};
}

View File

@ -1,70 +1,13 @@
{ config, pkgs, ... }:
{ ... }:
with pkgs.lib;
let
generateCoreDNSConfig = domains:
let
generateForDomain = domain: conf:
concatMapStrings
(iface:
let
architectIP = config.architect.networks.${iface}.devices.architect.address;
interfaceNet = config.architect.networks.${iface}.net;
in
''
${domain} {
view ${iface} {
expr incidr(client_ip(), '${interfaceNet}')
}
template IN A ${domain} {
answer "${domain}. 60 IN A ${architectIP}"
}
template IN HTTPS ${domain} {
answer "${domain}. 60 IN HTTPS 1 . ipv4hint=\"${architectIP}\""
}
cache
log
}
''
)
conf.dnsInterfaces;
in
concatStrings (mapAttrsToList generateForDomain domains);
# Combine vhosts and the single domain
allDomains = config.architect.vhost // {
"architect.devs.giugl.io" = { dnsInterfaces = [ "lan" "tailscale" ]; };
};
domain = "adguard.giugl.io";
in
{
architect.vhost.${domain} = with config.architect.networks; {
dnsInterfaces = [ "tailscale" "lan" ];
locations."/" = {
port = config.services.adguardhome.port;
allowLan = true;
allow = [
tailscale.net
];
};
};
services = {
coredns = {
pepe.core.dns = {
enable = true;
config = ''
${generateCoreDNSConfig allDomains}
. {
cache
forward . 45.90.28.77 45.90.30.77
}
'';
nextDNSId = "d65174";
extraDomains = {
"architect.devs.giugl.io" = {
dnsInterfaces = [ "lan" "tailscale" ];
};
};
};
}

View File

@ -7,8 +7,8 @@
packageFirewall = pkgs.nftables;
bantime-increment.enable = true;
ignoreIP = [
config.architect.networks.lan.net
config.architect.networks.tailscale.net
config.pepe.core.network.interfaces.tailscale.net
config.pepe.core.network.interfaces.lan.net
];
};
}

View File

@ -1,20 +1,18 @@
{ config, lib, ... }:
let
openTCP = lib.concatMapStringsSep "," (x: toString x) config.architect.firewall.openTCP;
openUDP = lib.concatMapStringsSep "," (x: toString x) config.architect.firewall.openUDP;
openTCPVPN = lib.concatMapStringsSep "," (x: toString x) config.architect.firewall.openTCPVPN;
openUDPVPN = lib.concatMapStringsSep "," (x: toString x) config.architect.firewall.openUDPVPN;
firewallRules = config.pepe.core.firewall;
openTCP = lib.concatMapStringsSep "," (x: toString x) firewallRules.openTCP;
openUDP = lib.concatMapStringsSep "," (x: toString x) firewallRules.openUDP;
ifaces = config.pepe.core.network.interfaces;
deviceAddress = interface: device:
config.architect.networks.${interface}.devices.${device}.address;
ifaces.${interface}.devices.${device}.address;
gdevices = [
(deviceAddress "tailscale" "architect")
(deviceAddress "tailscale" "dodino")
(deviceAddress "tailscale" "manduria")
(deviceAddress "tailscale" "kmerr")
(deviceAddress "tailscale" "chuck")
];
in
{
@ -25,7 +23,7 @@ in
nftables = {
enable = true;
ruleset = with config.architect.networks; ''
ruleset = with config.pepe.core.network.interfaces; ''
table ip raw {
chain PREROUTING {
type filter hook prerouting priority raw; policy accept;

View File

@ -1,34 +0,0 @@
{ config, lib, ... }:
let
domain = "git.giugl.io";
in
{
architect = {
firewall.openTCP = [ config.services.gitea.settings.server.SSH_PORT ];
vhost.${domain} = {
dnsInterfaces = [ "lan" "tailscale" ];
locations."/" = {
port = config.services.gitea.settings.server.HTTP_PORT;
allowWAN = true;
};
};
};
services.gitea = {
enable = true;
database.type = "sqlite3";
appName = "Gitea";
# https://github.com/NixOS/nixpkgs/issues/235442#issuecomment-1574329453
lfs.enable = true;
settings = {
server = {
DOMAIN = domain;
ROOT_URL = "https://${domain}";
SSH_PORT = 22;
HTTP_PORT = 3001;
};
openid.enable_openid_signin = true;
};
};
}

View File

@ -56,7 +56,7 @@
options = [ "bind" ];
};
"/media" = {
"${config.pepe.core.media.path}" = lib.mkIf config.pepe.core.media.enable {
device = "nvmedata/media";
fsType = "zfs";
};

View File

@ -1,49 +0,0 @@
{ config, pkgs, ... }:
let
domain = "vipienne.giugl.io";
headscalePkg = pkgs.headscale;
in
{
environment.systemPackages = [ headscalePkg ];
architect = {
firewall = {
openUDP = [ config.services.tailscale.port ];
};
vhost.${domain} = {
dnsInterfaces = [ "lan" "tailscale" ];
locations."/" = {
port = config.services.headscale.port;
allowWAN = true;
proxyWebsockets = true;
};
};
};
services.headscale = {
enable = true;
package = headscalePkg;
port = 1194;
settings = {
server_url = "https://${domain}";
# log.level = "debug";
dns = {
magic_dns = false;
# base_domain = domain;
override_local_dns = true;
global = [
config.architect.networks.tailscale.devices.architect.address
];
nameservers.global = [
config.architect.networks.tailscale.devices.architect.address
];
};
logtail.enabled = false;
prefixes.v4 = config.architect.networks.tailscale.net;
noise.private_key_path = "/var/lib/headscale/noise_private.key";
};
};
}

View File

@ -1,115 +0,0 @@
{ config, pkgs, ... }:
let
domain = "home.giugl.io";
piperPort = 10200;
whisperPort = 10300;
in
{
services.go2rtc = {
enable = true;
settings.api.listen = "127.0.0.1:1984";
};
# services.wyoming = {
# faster-whisper = {
# servers."home" = {
# enable = true;
# uri = "tcp://127.0.0.1:${toString whisperPort}";
# model = "large-v3";
# device = "cuda";
# language = "en";
# };
# };
# piper = {
# servers."home" = {
# enable = true;
# uri = "tcp://127.0.0.1:${toString piperPort}";
# voice = "en-us-ryan-medium";
# lengthScale = 0.63;
# };
# };
# };
services.home-assistant = {
enable = true;
package = pkgs.unstablePkgs.home-assistant;
config = {
http = {
server_host = "127.0.0.1";
server_port = 8123;
use_x_forwarded_for = true;
trusted_proxies = [ "127.0.0.1" ];
};
homeassistant = {
name = "Brigettine Square";
latitude = 52.1958;
longitude = 0.180746;
unit_system = "metric";
};
default_config = { };
automation = "!include automations.yaml";
frontend.themes = "!include_dir_merge_named themes";
};
extraComponents = [
"otbr"
"litterrobot"
"apple_tv"
"homekit"
"homekit_controller"
"spotify"
"hue"
"sonos"
"tplink"
"ollama"
"wyoming"
"whisper"
"piper"
"isal"
"radarr"
"sonarr"
"mqtt"
"mqtt_eventstream"
"mqtt_json"
"mqtt_room"
"mqtt_statestream"
"github"
"webostv"
"reolink"
"onvif"
"xiaomi_miio"
"ring"
];
extraPackages = python3Packages: with pkgs.unstablePkgs.python3Packages; [
pyporscheconnectapi
];
};
services.mosquitto = {
enable = true;
listeners = [
{
address = "127.0.0.1";
acl = [ "pattern readwrite #" ];
omitPasswordAuth = true;
settings.allow_anonymous = true;
}
];
};
architect.vhost.${domain} = with config.architect.networks; {
dnsInterfaces = [ "tailscale" "lan" ];
locations."/" = {
port = config.services.home-assistant.config.http.server_port;
allowWAN = true;
allowLan = true;
proxyWebsockets = true;
allow = [
tailscale.net
];
};
};
}

View File

@ -1,51 +0,0 @@
{ config, pkgs, lib, ... }:
let
domain = "media.giugl.io";
port = 8096;
allowLan = true;
in
{
# needed since StateDirectory does not accept symlinks
systemd.services.jellyfin.serviceConfig.StateDirectory = lib.mkForce "";
architect.vhost.${domain} = with config.architect.networks; {
dnsInterfaces = [ "lan" "tailscale" ];
locations = {
"/" = {
inherit port allowLan;
allow = [
tailscale.net
];
};
"/socket" = {
inherit port allowLan;
proxyWebsockets = true;
allow = [
tailscale.net
];
};
};
};
services.jellyfin = {
enable = true;
group = "media";
package = pkgs.unstablePkgs.jellyfin;
};
users.groups = {
media.members = [ "jellyfin" ];
video.members = [ "jellyfin" ];
render.members = [ "jellyfin" ];
};
fileSystems."/tmp/jellyfin" = {
device = "none";
fsType = "tmpfs";
options = [ "defaults" "size=20G" "uid=jellyfin" ];
};
}

View File

@ -1,23 +0,0 @@
{ config, pkgs, ... }:
let
domain = "aumm-aumm.giugl.io";
in
{
services.jellyseerr = {
enable = true;
# package = pkgs.unstablePkgs.jellyseerr;
};
architect.vhost.${domain} = {
dnsInterfaces = [ "tailscale" "lan" ];
locations."/" = {
port = config.services.jellyseerr.port;
allowLan = true;
allow = [
config.architect.networks.tailscale.net
];
};
};
}

View File

@ -1,67 +0,0 @@
{ config, pkgs, ... }:
let
backendDomain = "ollama.giugl.io";
frontendDomain = "llm.giugl.io";
ollamaPkg = pkgs.unstablePkgs.ollama-cuda;
uiPkg = pkgs.unstablePkgs.open-webui;
tikaPkg = pkgs.unstablePkgs.tika;
in
{
environment = {
systemPackages = [ ollamaPkg ];
};
services = {
ollama = {
enable = true;
package = ollamaPkg;
acceleration = "cuda";
environmentVariables = {
OLLAMA_FLASH_ATTENTION = "1";
OLLAMA_NUM_PARALLEL = "2";
OLLAMA_KV_CACHE_TYPE = "q8_0";
};
};
open-webui = {
enable = true;
package = uiPkg;
};
tika = {
enable = true;
package = tikaPkg;
};
};
architect.vhost.${backendDomain} = {
dnsInterfaces = [ "tailscale" "lan" ];
locations."/" = {
host = config.services.ollama.host;
port = config.services.ollama.port;
allowLan = true;
allowWAN = true;
recommendedProxySettings = false;
extraConfig = ''
proxy_buffering off;
proxy_read_timeout 600s;
proxy_set_header Host localhost:${toString config.services.ollama.host};
'';
};
};
architect.vhost.${frontendDomain} = {
dnsInterfaces = [ "tailscale" "lan" ];
locations."/" = {
host = config.services.open-webui.host;
port = config.services.open-webui.port;
allowLan = true;
allowWAN = true;
proxyWebsockets = true;
};
};
}

View File

@ -1,35 +0,0 @@
{ config, lib, pkgs, ... }:
let
domain = "s3.giugl.io";
utilities = import ./utilities.nix { inherit lib config; };
inherit (utilities) architectInterfaceAddress;
in
{
services = {
minio = {
enable = true;
package = pkgs.minio_legacy_fs;
};
nginx.virtualHosts.${domain} = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://127.0.0.1:9000";
extraConfig = ''
client_max_body_size 500M;
allow ${config.architect.networks.lan.net};
allow ${config.architect.networks.tailscale.net};
deny all;
'';
};
};
};
networking.extraHosts = ''
${architectInterfaceAddress "lan"} ${domain}
${architectInterfaceAddress "tailscale"} ${domain}
'';
}

View File

@ -22,8 +22,6 @@ in
};
environment.systemPackages = with pkgs; [
nodejs-18_x
libtensorflow
ffmpeg
];
@ -60,7 +58,7 @@ in
enable = true;
hostName = domain;
https = true;
package = pkgs.nextcloud30;
package = pkgs.nextcloud31;
datadir = "/services/nextcloud";
configureRedis = true;
caching = {

View File

@ -1,148 +1,25 @@
{ config, lib, ... }:
with lib;
{
options.architect = {
firewall = {
openTCP = mkOption {
type = types.listOf types.int;
default = [ ];
firewall = lib.mkOption {
internal = true;
default = config.pepe.core.firewall;
};
openUDP = mkOption {
type = types.listOf types.int;
default = [ ];
networks = lib.mkOption {
internal = true;
default = config.pepe.core.network.interfaces;
};
vhost = lib.mkOption {
internal = true;
default = config.pepe.core.vhost.hosts;
};
};
networks = mkOption {
type = types.attrsOf (types.submodule {
options = {
interface = mkOption {
type = types.str;
description = "The network interface name.";
};
net = mkOption {
type = types.str;
description = "The network address in CIDR format.";
};
devices = mkOption {
type = types.attrsOf (types.submodule {
options = {
address = mkOption {
type = types.str;
description = "The IP address of the device.";
};
hostname = mkOption {
type = types.str;
description = "The hostname of the device.";
};
};
});
default = { };
description = "An attribute set of devices with their configurations.";
};
};
});
default = { };
description = "An attribute set of networks with their configurations.";
};
vhost = mkOption {
type = types.attrsOf (types.submodule {
options = {
dnsInterfaces = mkOption {
type = types.listOf types.str;
default = [ ];
description = "List of interfaces to add extra DNS hosts for this vhost.";
};
locations = mkOption {
type = types.attrsOf (types.submodule {
options = {
extraConfig = mkOption {
type = types.str;
description = "Extra configuration for the location.";
default = "";
};
allowLan = mkOption {
type = types.bool;
default = false;
};
proxyWebsockets = mkOption {
type = types.bool;
default = false;
};
host = mkOption {
type = types.str;
description = "The host for the location.";
default = "127.0.0.1";
};
port = mkOption {
type = types.int;
description = "The port number for the location.";
};
allow = mkOption {
type = types.listOf types.str;
default = [ ];
description = "IP address or CIDR block to allow.";
};
path = mkOption {
type = types.str;
default = "";
};
recommendedProxySettings = mkOption {
type = types.bool;
default = true;
description = "Force the use of recommended proxy configuration.";
};
allowWAN = mkOption {
type = types.bool;
default = false;
description = "If set to false, deny all WAN traffic.";
};
};
});
default = { };
description = "An attribute set of location configurations.";
};
};
});
default = { };
description = "An attribute set of domain configurations.";
};
};
# TODO: move to nginx
config = {
services.nginx.virtualHosts = mapAttrs
(domain: conf: {
forceSSL = true;
useACMEHost= "giugl.io";
locations = mapAttrs
(path: location: {
proxyPass = "http://${location.host}:${toString location.port}${location.path}";
proxyWebsockets = location.proxyWebsockets;
recommendedProxySettings = location.recommendedProxySettings;
extraConfig = ''
${concatMapStringsSep "\n" (allowCIDR: "allow ${allowCIDR};") location.allow}
${optionalString location.allowLan ''allow ${config.architect.networks."lan".net};''}
${optionalString (!location.allowWAN) "deny all;"}
'' + location.extraConfig;
})
conf.locations;
})
config.architect.vhost;
config.architect.networks.docker = {
interface = "docker0";
net = "172.17.0.0/16";
};
}

View File

@ -3,6 +3,6 @@
{
services.postgresql = {
enable = true;
package = lib.mkForce pkgs.postgresql;
package = lib.mkForce pkgs.postgresql_16;
};
}

View File

@ -1,28 +0,0 @@
{ config, pkgs, ... }:
let
domain = "htpro.giugl.io";
in
{
services.prowlarr = {
enable = true;
package = pkgs.unstablePkgs.prowlarr;
};
architect.vhost.${domain} = with config.architect.networks; {
dnsInterfaces = [ "tailscale" "lan" ];
locations."/" = {
port = 9696;
allowLan = true;
proxyWebsockets=true;
allow = [
tailscale.net
];
};
};
users.groups.media.members = [ "prowlarr" ];
}

View File

@ -1,26 +0,0 @@
{ config, pkgs, ... }:
let
domain = "htrad.giugl.io";
in
{
services.radarr = {
enable = true;
package = pkgs.unstablePkgs.radarr;
group = "media";
};
architect.vhost.${domain} = with config.architect.networks; {
dnsInterfaces = [ "tailscale" "lan" ];
locations."/" = {
port = 7878;
allowLan = true;
allow = [
tailscale.net
];
};
};
users.groups.media.members = [ "radarr" ];
}

View File

@ -1,26 +0,0 @@
{ config, pkgs, ... }:
let
domain = "htson.giugl.io";
in
{
services.sonarr = {
enable = true;
group = "media";
package = pkgs.unstablePkgs.sonarr;
};
architect.vhost.${domain} = with config.architect.networks; {
dnsInterfaces = [ "tailscale" "lan" ];
locations."/" = {
port = 8989;
allowLan = true;
allow = [
tailscale.net
];
};
};
users.groups.media.members = [ "sonarr" ];
}

View File

@ -38,22 +38,19 @@ let
sunshinePkg = (pkgs.unstablePkgs.sunshine.override { cudaSupport = true; });
in
{
pepe.core.graphics = {
enable = true;
nvidia = true;
};
boot.kernelModules = [ "uinput" ];
environment.systemPackages = with pkgs.unstablePkgs; [ gamemode heroic ];
hardware = {
pulseaudio.enable = false;
};
nvidia = {
modesetting.enable = true;
powerManagement.enable = false;
powerManagement.finegrained = false;
open = false;
nvidiaSettings = true;
package = config.boot.kernelPackages.nvidiaPackages.latest;
};
};
systemd.services.NetworkManager-wait-online.enable = pkgs.lib.mkForce false;
programs.steam = {
enable = true;
@ -159,7 +156,6 @@ in
xserver = {
enable = true;
videoDrivers = [ "nvidia" ];
desktopManager.xfce.enable = true;
monitorSection = ''

View File

@ -7,24 +7,26 @@ let
inherit (utilities) generateDeviceStrings;
in
{
architect = {
networks.tailscale = {
pepe.core = {
firewall.openUDP = [ 41641 ];
network.interfaces.tailscale = {
interface = "ts0";
net = "100.64.0.0/10";
type = "vpn";
devices = {
architect = { address = "100.64.0.1"; hostname = "architect.${domain}"; };
architect = { address = "100.64.0.1"; hostname = "architect.${domain}"; isEndpoint = true; };
kmerr = { address = "100.64.0.2"; hostname = "kmerr.${domain}"; };
parallels = { address = "100.64.0.3"; hostname = "parallels.${domain}"; };
chuck = { address = "100.64.0.4"; hostname = "chuck.${domain}"; };
dodino = { address = "100.64.0.5"; hostname = "dodino.${domain}"; };
work_laptop = { address = "100.64.0.4"; hostname = "work_laptop.${domain}"; };
work_desktop = { address = "100.64.0.5"; hostname = "work_desktop.${domain}"; };
manduria = { address = "100.64.0.6"; hostname = "manduria.${domain}"; };
tommy = { address = "100.64.0.7"; hostname = "tommy.${domain}"; };
ucsb-workstation = { address = "100.64.0.8"; hostname = "ucsb-workstation.${domain}"; };
alfredo = { address = "100.64.0.9"; hostname = "alfredo.${domain}"; };
appletv = { address = "100.64.0.13"; hostname = "appletv.${domain}"; };
watkinshouse = { address = "100.64.0.14"; hostname = "watkinshouse.${domain}"; };
afsun = { address = "100.64.0.15"; hostname = "afsun.${domain}"; };
jacopo-desktop = { address = "100.64.0.21"; hostname = "jacopo-desktop.${domain}"; };
jacopo-tv = { address = "100.64.0.22"; hostname = "jacopo-tv.${domain}"; };
jacopo-phone = { address = "100.64.0.28"; hostname = "jacopo-phone.${domain}"; };
};
};
};
@ -32,10 +34,10 @@ in
services = {
tailscale = {
enable = true;
interfaceName = config.architect.networks.tailscale.interface;
interfaceName = config.pepe.core.network.interfaces.tailscale.interface;
package = pkgs.unstablePkgs.tailscale;
};
};
networking.extraHosts = generateDeviceStrings config.architect.networks.tailscale.devices;
networking.extraHosts = generateDeviceStrings config.pepe.core.network.interfaces.tailscale.devices;
}

View File

@ -1,13 +1,16 @@
{ config, lib, ... }:
let
ifaces = config.pepe.core.network.interfaces;
in
{
# device.address device.hostname
generateDeviceStrings = devices: lib.concatStringsSep "\n"
(lib.mapAttrsToList (name: device: "${device.address} ${device.hostname}") devices);
getDeviceAddress = interface: device:
config.architect.networks.${interface}.devices.${device}.address;
ifaces.${interface}.devices.${device}.address;
architectInterfaceAddress = interface:
config.architect.networks.${interface}.devices.architect.address;
ifaces.${interface}.devices.architect.address;
}

View File

@ -31,13 +31,14 @@
(mkSysRole "common")
(mkSysRole "acme")
(mkUser { name = "root"; roles = [ ]; })
../modules
];
home-manager = {
useGlobalPkgs = true;
};
system.stateVersion = "24.11";
system.stateVersion = "25.05";
}
home-manager.nixosModules.home-manager

11
modules/core/default.nix Normal file
View File

@ -0,0 +1,11 @@
{...}: {
imports = [
./media.nix
./graphics.nix
./network.nix
./vhost.nix
./firewall.nix
./dns.nix
./docker.nix
];
}

169
modules/core/dns.nix Normal file
View File

@ -0,0 +1,169 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkOption types mkIf concatMapStrings concatStrings mapAttrsToList attrsets;
cfg = config.pepe.core.dns;
in
{
options.pepe.core.dns = {
enable = mkOption {
type = types.bool;
default = false;
description = "Whether to enable the DNS server.";
};
nextDNSId = mkOption {
type = types.str;
default = "d65174";
description = "NextDNS ID for DNS over TLS.";
};
extraDomains = mkOption {
type = types.attrsOf (types.submodule {
options = {
dnsInterfaces = mkOption {
type = types.listOf types.str;
default = [ ];
description = "List of interfaces to add DNS entries for this domain.";
};
};
});
default = { };
description = "Additional domains to add to DNS configuration.";
};
};
config = mkIf cfg.enable {
services.coredns = {
enable = true;
config =
let
# Function to generate domain-specific configurations
generateDomainConfig = domain: conf: ifaceName:
let
iface = config.pepe.core.network.interfaces.${ifaceName};
ifaceEndpoint = lib.head (lib.attrNames (lib.filterAttrs (_: device: device.isEndpoint) iface.devices));
serverIP = iface.devices.${ifaceEndpoint}.address;
interfaceNet = iface.net;
in
''
${domain} {
view ${ifaceName} {
expr incidr(client_ip(), '${interfaceNet}')
}
template IN A ${domain} {
answer "${domain}. 60 IN A ${serverIP}"
}
template IN HTTPS ${domain} {
answer "${domain}. 60 IN HTTPS 1 . ipv4hint=\"${serverIP}\""
}
cache
log
}
'';
# Function to generate device views for an interface
generateDeviceViews = ifaceName:
let
iface = config.pepe.core.network.interfaces.${ifaceName};
in
concatMapStrings
({ name, device }:
let
deviceIP = device.address;
serverName = "${name}-${cfg.nextDNSId}.dns.nextdns.io";
in
''
. {
view ${name} {
expr client_ip() == '${deviceIP}'
}
forward . tls://45.90.28.77 tls://45.90.30.77 {
tls_servername ${serverName}
health_check 5s
}
}
''
)
(attrsets.mapAttrsToList
(name: device: { inherit name device; })
iface.devices
);
# Collect all interfaces used across all domains
allInterfaces = lib.unique (lib.flatten
(lib.mapAttrsToList
(_: conf: conf.dnsInterfaces)
(config.pepe.core.vhost.hosts // cfg.extraDomains)
));
# Generate all device views once
allDeviceViews = concatMapStrings generateDeviceViews allInterfaces;
# Function to generate configurations for all domains
generateCoreDNSConfig = domains:
let
generateForDomain = domain: conf:
concatMapStrings
(ifaceName: generateDomainConfig domain conf ifaceName)
conf.dnsInterfaces;
in
concatStrings (mapAttrsToList generateForDomain domains);
allDomains = config.pepe.core.vhost.hosts // cfg.extraDomains;
in
let
# Function to generate DNS records for individual devices based on dnsResolvableName
generateDeviceHostRecords =
let
generateRecordsForInterface = ifaceName: ifaceConfig:
lib.concatStringsSep "\n" (lib.mapAttrsToList
(deviceName: deviceConfig:
if deviceConfig.hostname!= null then
let
deviceAddress = deviceConfig.address;
deviceIface = ifaceConfig.net;
deviceHost = deviceConfig.hostname;
in
''
${deviceHost} {
view ${ifaceName} {
expr incidr(client_ip(), '${deviceIface}')
}
template IN A ${deviceHost} {
answer "${deviceHost}. 60 IN A ${deviceAddress}"
}
cache
log
}
''
else ""
)
ifaceConfig.devices);
in
lib.concatStringsSep "\n" (lib.mapAttrsToList generateRecordsForInterface config.pepe.core.network.interfaces);
in
''
${generateCoreDNSConfig allDomains}
${generateDeviceHostRecords}
${allDeviceViews}
. {
forward . tls://45.90.28.77 tls://45.90.30.77 {
tls_servername "lan-${cfg.nextDNSId}.dns.nextdns.io"
health_check 5s
}
}
'';
};
};
}

60
modules/core/docker.nix Normal file
View File

@ -0,0 +1,60 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.core.docker;
in
{
options.pepe.core.docker = with lib; {
enable = mkEnableOption "Enable Docker";
nvidia = mkEnableOption "Enable NVIDIA Container Toolkit";
dataRoot = mkOption {
type = types.str;
default = "/var/lib/docker";
description = "Docker data root directory";
};
extraOptions = mkOption {
type = types.str;
default = "";
description = "Extra options for Docker daemon";
};
enableOnBoot = mkOption {
type = types.bool;
default = false;
description = "Start Docker on boot";
};
iptables = mkOption {
type = types.bool;
default = false;
description = "Whether Docker should manipulate iptables";
};
users = mkOption {
type = types.listOf types.str;
default = [];
description = "Users to add to the docker group";
};
};
config = mkIf cfg.enable {
hardware.nvidia-container-toolkit.enable = cfg.nvidia;
virtualisation = {
oci-containers.backend = "docker";
docker = {
enable = true;
extraOptions = cfg.extraOptions;
enableOnBoot = cfg.enableOnBoot;
daemon.settings = {
iptables = cfg.iptables;
data-root = cfg.dataRoot;
};
};
};
users.users = lib.genAttrs cfg.users (user: {
extraGroups = [ "docker" ];
});
};
}

27
modules/core/firewall.nix Normal file
View File

@ -0,0 +1,27 @@
{ config, lib, ... }:
let
inherit (lib) mkOption types;
cfg = config.pepe.core.firewall;
in
{
options.pepe.core.firewall = {
openTCP = mkOption {
type = types.listOf types.int;
default = [ ];
description = "TCP ports to open in the firewall";
};
openUDP = mkOption {
type = types.listOf types.int;
default = [ ];
description = "UDP ports to open in the firewall";
};
};
config = {
networking.firewall = {
allowedTCPPorts = cfg.openTCP;
allowedUDPPorts = cfg.openUDP;
};
};
}

39
modules/core/graphics.nix Normal file
View File

@ -0,0 +1,39 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.core.graphics;
in
{
options.pepe.core.graphics = with lib; {
enable = mkEnableOption "Enable graphics";
nvidia = mkEnableOption "Enable nvidia graphics";
};
config = mkIf cfg.enable {
hardware = {
graphics = {
enable = true;
extraPackages = with pkgs; mkIf cfg.nvidia [ vaapiVdpau ];
};
nvidia = mkIf cfg.nvidia {
modesetting.enable = true;
powerManagement.enable = false;
powerManagement.finegrained = false;
open = false;
nvidiaSettings = true;
package = config.boot.kernelPackages.nvidiaPackages.latest;
};
};
services = {
xserver = {
enable = true;
videoDrivers = mkIf cfg.nvidia [ "nvidia" ];
};
};
};
}

27
modules/core/media.nix Normal file
View File

@ -0,0 +1,27 @@
{ config, lib, ... }:
let
cfg = config.pepe.core.media;
in
{
options.pepe.core.media = with lib; {
enable = mkEnableOption "Enable media library";
group = mkOption {
type = types.str;
default = "media";
};
path = mkOption {
type = types.str;
default = null;
};
groupMembers = mkOption {
type = types.listOf types.str;
default = [];
};
};
config = lib.mkIf cfg.enable {
users.groups.${cfg.group}.members = [ cfg.group ] ++ cfg.groupMembers;
};
}

126
modules/core/network.nix Normal file
View File

@ -0,0 +1,126 @@
{ config, lib, ... }:
let
inherit (lib) mkOption types;
cfg = config.pepe.core.network;
in
{
options.pepe.core.network = {
interfaces = mkOption {
type = types.attrsOf (types.submodule {
options = {
interface = mkOption {
type = types.str;
description = "The network interface name.";
};
type = mkOption {
type = types.enum [ "lan" "wan" "vpn" ];
description = "The type of interface (lan, wan, or vpn).";
};
net = mkOption {
type = types.str;
description = "The network address in CIDR format.";
};
devices = mkOption {
type = types.attrsOf (types.submodule {
options = {
address = mkOption {
type = types.str;
description = "The IP address of the device.";
};
hostname = mkOption {
type = types.str;
description = "The hostname of the device.";
};
isEndpoint = mkOption {
type = types.bool;
default = false;
description = "Whether this device serves as a DNS endpoint for this interface.";
};
};
});
default = { };
description = "An attribute set of devices with their configurations.";
};
};
});
default = { };
description = "An attribute set of networks with their configurations.";
};
interfacesByType = mkOption {
type = types.attrsOf (types.listOf types.str);
default = { };
description = "Interfaces grouped by type (lan, wan, vpn) for easy access.";
internal = true;
};
dnsEndpoints = mkOption {
type = types.attrsOf (types.submodule {
options = {
interface = mkOption {
type = types.str;
description = "The interface this DNS endpoint belongs to.";
};
device = mkOption {
type = types.str;
description = "The device name that serves as the DNS endpoint.";
};
address = mkOption {
type = types.str;
description = "The IP address of the DNS endpoint.";
};
serverName = mkOption {
type = types.str;
default = "";
description = "DNS server name for TLS connections.";
};
};
});
default = { };
description = "DNS endpoints for each interface.";
internal = true;
};
};
config = {
# Create lists of interfaces by type for easy access elsewhere
pepe.core.network.interfacesByType = {
lan = lib.attrNames (lib.filterAttrs (_: iface: iface.type == "lan") cfg.interfaces);
wan = lib.attrNames (lib.filterAttrs (_: iface: iface.type == "wan") cfg.interfaces);
vpn = lib.attrNames (lib.filterAttrs (_: iface: iface.type == "vpn") cfg.interfaces);
};
# Collect DNS endpoints from all interfaces
pepe.core.network.dnsEndpoints =
let
collectEndpoints = ifaceName: iface:
lib.mapAttrs'
(deviceName: device:
lib.nameValuePair
"${ifaceName}-${deviceName}"
{
interface = ifaceName;
device = deviceName;
address = device.address;
serverName = device.dnsServerName;
}
)
(lib.filterAttrs (_: device: device.isDnsEndpoint) iface.devices);
in
lib.foldl
(acc: ifaceName:
acc // (collectEndpoints ifaceName cfg.interfaces.${ifaceName})
)
{ }
(lib.attrNames cfg.interfaces);
};
}

131
modules/core/vhost.nix Normal file
View File

@ -0,0 +1,131 @@
{ config, lib, ... }:
let
inherit (lib) mkOption types mapAttrs concatMapStringsSep optionalString mkIf;
cfg = config.pepe.core.vhost;
in
{
options.pepe.core.vhost = {
hosts = mkOption {
type = types.attrsOf (types.submodule {
options = {
locations = mkOption {
type = types.attrsOf (types.submodule {
options = {
extraConfig = mkOption {
type = types.str;
description = "Extra configuration for the location.";
default = "";
};
proxyWebsockets = mkOption {
type = types.bool;
default = false;
};
host = mkOption {
type = types.str;
description = "The host for the location.";
default = "127.0.0.1";
};
port = mkOption {
type = types.int;
description = "The port number for the location.";
};
allow = mkOption {
type = types.listOf types.str;
default = [ ];
description = "IP address or CIDR block to allow.";
};
allowVPN = mkOption {
type = types.bool;
default = false;
description = "If set to true, allow VPN traffic.";
};
allowLAN = mkOption {
type = types.bool;
default = false;
description = "If set to true, allow LAN traffic.";
};
allowWAN = mkOption {
type = types.bool;
default = false;
description = "If set to true, allow WAN traffic. If false, deny all WAN traffic.";
};
path = mkOption {
type = types.str;
default = "";
};
recommendedProxySettings = mkOption {
type = types.bool;
default = true;
description = "Force the use of recommended proxy configuration.";
};
};
});
default = { };
description = "An attribute set of location configurations.";
};
resolveLocally = mkOption {
type = types.bool;
default = true;
description = "If true, ensure the vhost is resolvable to 127.0.0.1 locally on this server.";
};
};
});
default = { };
description = "An attribute set of domain configurations.";
};
};
config = {
pepe.core.firewall.openTCP = [ 80 443 ];
# Configure DNS entries for vhosts when DNS is enabled
pepe.core.dns = mkIf config.pepe.core.dns.enable {
extraDomains = mapAttrs
(domain: conf: {
dnsInterfaces =
(lib.optionals (lib.any (loc: loc.allowLAN) (lib.attrValues conf.locations))
config.pepe.core.network.interfacesByType.lan) ++
(lib.optionals (lib.any (loc: loc.allowVPN) (lib.attrValues conf.locations))
config.pepe.core.network.interfacesByType.vpn);
})
cfg.hosts;
};
services.nginx.virtualHosts = mapAttrs
(domain: conf: {
forceSSL = true;
useACMEHost = "giugl.io";
locations = mapAttrs
(path: location: {
proxyPass = "http://${location.host}:${toString location.port}${location.path}";
proxyWebsockets = location.proxyWebsockets;
recommendedProxySettings = location.recommendedProxySettings;
extraConfig = ''
${concatMapStringsSep "\n" (allowCIDR: "allow ${allowCIDR};") location.allow}
${optionalString location.allowLAN (concatMapStringsSep "\n" (ifaceName: "allow ${config.pepe.core.network.interfaces.${ifaceName}.net};") config.pepe.core.network.interfacesByType.lan)}
${optionalString location.allowVPN (concatMapStringsSep "\n" (ifaceName: "allow ${config.pepe.core.network.interfaces.${ifaceName}.net};") config.pepe.core.network.interfacesByType.vpn)}
${optionalString (!location.allowWAN) "deny all;"}
'' + location.extraConfig;
})
conf.locations;
})
cfg.hosts;
networking.extraHosts = lib.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList
(domain: hostConf:
lib.optionals hostConf.resolveLocally "127.0.0.1 ${domain}"
)
cfg.hosts
));
};
}

7
modules/default.nix Normal file
View File

@ -0,0 +1,7 @@
{ ... }: {
imports = [
./services
./core
];
}

View File

@ -0,0 +1,35 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.bazarr;
in
{
options.pepe.services.bazarr = with lib; {
enable = mkEnableOption "Enable bazarr";
package = mkPackageOption pkgs "bazarr" { };
domain = mkOption {
type = types.str;
default = null;
};
};
config = mkIf cfg.enable {
services.bazarr = {
enable = true;
package = cfg.package;
group = "media";
};
pepe.core.vhost.hosts.${cfg.domain} = {
locations."/" = {
port = 6767;
allowLAN = true;
allowVPN = true;
};
};
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "bazarr" ];
};
}

View File

@ -0,0 +1,20 @@
{ ... }: {
imports = [
./bazarr
./gitea
./homeassistant
./immich
./jellyfin
./jellyseer
./lidarr
./llm
./minio
./navidrome
./nzbget
./prowlarr
./radarr
./redlib
./sonarr
./headscale
];
}

View File

@ -0,0 +1,53 @@
{ config, pkgs, lib, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.gitea;
in
{
options.pepe.services.gitea = with lib; {
enable = mkEnableOption "Enable gitea";
package = mkPackageOption pkgs "gitea" { };
domain = mkOption {
type = types.str;
default = null;
};
};
config = mkIf cfg.enable {
pepe.core = {
firewall.openTCP = [ config.services.gitea.settings.server.SSH_PORT ];
vhost.hosts.${cfg.domain} = {
locations."/" = {
port = config.services.gitea.settings.server.HTTP_PORT;
allowLAN = true;
allowVPN = true;
allowWAN = true;
};
};
};
services.gitea = {
enable = true;
package = cfg.package;
database.type = "sqlite3";
appName = "Gitea";
# https://github.com/NixOS/nixpkgs/issues/235442#issuecomment-1574329453
lfs.enable = true;
settings = {
server = {
DOMAIN = cfg.domain;
ROOT_URL = "https://${cfg.domain}";
SSH_PORT = 22;
HTTP_PORT = 3001;
};
service = {
DISABLE_REGISTRATION = true;
};
};
};
};
}

View File

@ -0,0 +1,59 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.headscale;
in
{
options.pepe.services.headscale = with lib; {
enable = mkEnableOption "Enable Headscale";
package = mkPackageOption pkgs "headscale" { };
domain = mkOption {
type = types.str;
default = null;
description = "Domain for the Headscale service.";
};
host = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Host for the Headscale service.";
};
port = mkOption {
type = types.int;
default = 1194;
description = "Port for the Headscale service.";
};
settings = mkOption {
type = types.attrsOf types.anything;
default = { };
description = "Arbitrary configuration settings for Headscale.";
};
};
config = mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
services.headscale = {
enable = true;
package = cfg.package;
port = cfg.port;
settings = cfg.settings;
};
pepe.core = {
firewall.openUDP = [ cfg.port ];
vhost.hosts.${cfg.domain} = {
locations."/" = {
host = cfg.host;
port = cfg.port;
allowWAN = true;
proxyWebsockets = true;
extraConfig = ''
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
proxy_buffering off;
'';
};
};
};
};
}

View File

@ -0,0 +1,69 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.homeassistant;
in
{
options.pepe.services.homeassistant = with lib; {
enable = mkEnableOption "Enable Home Assistant";
package = mkPackageOption pkgs "home-assistant" { };
domain = mkOption {
type = types.str;
default = null;
};
extraComponents = mkOption {
type = types.listOf types.str;
default = [];
description = "Additional components to enable in Home Assistant";
};
extraPackages = mkOption {
type = types.functionTo (types.listOf types.package);
default = _: [];
description = "Additional Python packages for Home Assistant";
};
config = mkOption {
type = types.attrs;
default = {};
description = "Home Assistant configuration";
};
};
config = mkIf cfg.enable {
services.home-assistant = {
enable = true;
package = cfg.package;
extraComponents = cfg.extraComponents;
extraPackages = cfg.extraPackages;
config = cfg.config;
};
services.mosquitto = {
enable = true;
listeners = [
{
address = "127.0.0.1";
acl = [ "pattern readwrite #" ];
omitPasswordAuth = true;
settings.allow_anonymous = true;
}
];
};
services.go2rtc = {
enable = true;
settings.api.listen = "127.0.0.1:1984";
};
pepe.core.vhost.hosts.${cfg.domain} = {
locations."/" = {
port = config.services.home-assistant.config.http.server_port or 8123;
allowLAN = true;
allowVPN = true;
allowWAN = true;
proxyWebsockets = true;
};
};
};
}

View File

@ -0,0 +1,42 @@
{ config, pkgs, lib, ... }:
let
cfg = config.pepe.services.immich;
in
{
options.pepe.services.immich = with lib; {
enable = mkEnableOption "Enable immich";
package = mkPackageOption pkgs "immich" { };
domain = mkOption {
type = types.str;
default = null;
};
};
config = lib.mkIf cfg.enable {
services = {
immich = {
enable = true;
package = cfg.package;
# accelerationDevices = null;
};
};
pepe.core.vhost.hosts.${cfg.domain} = {
locations."/" = {
host = "[::1]";
port = config.services.immich.port;
allowLAN = true;
allowVPN = true;
allowWAN = true;
proxyWebsockets = true;
extraConfig = ''
# allow large file uploads
client_max_body_size 50000M;
'';
};
};
users.users.immich.extraGroups = [ "video" "render" "media" "nextcloud" ];
};
}

View File

@ -0,0 +1,63 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf mkForce;
cfg = config.pepe.services.jellyfin;
in
{
options.pepe.services.jellyfin = with lib; {
enable = mkEnableOption "Enable jellyfin";
package = mkPackageOption pkgs "jellyfin" { };
domain = mkOption {
type = types.str;
default = null;
};
tmpfsSize = mkOption {
type = types.str;
default = "20G";
description = "Size of the tmpfs mount for Jellyfin";
};
};
config = mkIf cfg.enable {
# needed since StateDirectory does not accept symlinks
systemd.services.jellyfin.serviceConfig.StateDirectory = mkForce "";
pepe.core.vhost.hosts.${cfg.domain} = {
locations = {
"/" = {
port = 8096;
allowLAN = true;
allowVPN = true;
};
"/socket" = {
port = 8096;
allowLAN = true;
allowVPN = true;
proxyWebsockets = true;
};
};
};
services.jellyfin = {
enable = true;
group = "media";
package = cfg.package;
};
users.groups = {
video.members = [ "jellyfin" ];
render.members = [ "jellyfin" ];
};
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "jellyfin" ];
fileSystems."/tmp/jellyfin" = {
device = "none";
fsType = "tmpfs";
options = [ "defaults" "size=${cfg.tmpfsSize}" "uid=jellyfin" ];
};
};
}

View File

@ -0,0 +1,32 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.jellyseer;
in
{
options.pepe.services.jellyseer = with lib; {
enable = mkEnableOption "Enable jellyseer";
package = mkPackageOption pkgs "jellyseerr" { };
domain = mkOption {
type = types.str;
default = null;
};
};
config = mkIf cfg.enable {
services.jellyseerr = {
enable = true;
package = cfg.package;
};
pepe.core.vhost.hosts.${cfg.domain} = {
locations."/" = {
port = config.services.jellyseerr.port;
allowLAN = true;
allowVPN = true;
};
};
};
}

View File

@ -0,0 +1,36 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.lidarr;
in
{
options.pepe.services.lidarr = with lib; {
enable = mkEnableOption "Enable lidarr";
package = mkPackageOption pkgs "lidarr" { };
domain = mkOption {
type = types.str;
default = null;
};
};
config = mkIf cfg.enable {
services.lidarr = {
enable = true;
package = cfg.package;
group = "media";
};
pepe.core.vhost.hosts.${cfg.domain} = with config.pepe.core.network; {
dnsInterfaces = [ interfaceTypes.lan interfaceTypes.vpn ];
locations."/" = {
port = 8686;
allowLAN = true;
allowVPN = true;
};
};
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "lidarr" ];
};
}

View File

@ -0,0 +1,110 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf mkEnableOption mkPackageOption mkOption types optionalAttrs mkMerge;
cfg = config.pepe.services.llm;
in
{
options.pepe.services.llm = {
enable = mkEnableOption "Enable LLM backend service (Ollama)";
package = mkPackageOption pkgs "ollama" { };
backendDomain = mkOption {
type = types.nullOr types.str;
default = null;
description = "Domain for Ollama backend. If null, no vhost is created for the backend.";
};
acceleration = mkOption {
type = types.enum [ "none" "cuda" "rocm" ];
default = "none";
description = "Acceleration type for Ollama";
};
environmentVariables = mkOption {
type = types.attrsOf types.str;
default = {
OLLAMA_FLASH_ATTENTION = "1";
OLLAMA_NUM_PARALLEL = "2";
OLLAMA_KV_CACHE_TYPE = "q8_0";
};
description = "Environment variables for Ollama";
};
frontend = {
enable = mkEnableOption "Enable LLM frontend service (Open WebUI)"; # Defaults to false
uiPackage = mkPackageOption pkgs "open-webui" { };
tikaPackage = mkPackageOption pkgs "tika" { }; # Tika for document processing with Open WebUI
domain = mkOption {
type = types.nullOr types.str;
default = null;
description = "Domain for Open WebUI frontend. If null, no vhost is created for the frontend.";
};
};
};
config = mkMerge [
# Combined environment packages
{
environment.systemPackages =
(if cfg.enable then [ cfg.package ] else [ ]) ++
(if cfg.enable && cfg.frontend.enable then [ cfg.frontend.uiPackage cfg.frontend.tikaPackage ] else [ ]);
}
# Backend Ollama Service Configuration
(mkIf cfg.enable {
services.ollama = {
enable = true;
package = cfg.package;
acceleration = cfg.acceleration;
environmentVariables = cfg.environmentVariables;
};
pepe.core.vhost.hosts = optionalAttrs (cfg.backendDomain != null) {
"${cfg.backendDomain}" = {
locations."/" = {
host = config.services.ollama.host;
port = config.services.ollama.port;
allowLAN = true;
allowVPN = true;
allowWAN = true;
recommendedProxySettings = false;
extraConfig = ''
proxy_buffering off;
proxy_read_timeout 600s; # Ollama can take time to respond
proxy_set_header Host localhost:${toString config.services.ollama.port};
'';
};
};
};
})
# Frontend Open WebUI and Tika Service Configuration
(mkIf (cfg.enable && cfg.frontend.enable) {
services.open-webui = {
enable = true;
package = cfg.frontend.uiPackage;
};
services.tika = {
enable = true;
package = cfg.frontend.tikaPackage;
};
pepe.core.vhost.hosts = optionalAttrs (cfg.frontend.domain != null) {
"${cfg.frontend.domain}" = {
locations."/" = {
host = config.services.open-webui.host;
port = config.services.open-webui.port;
allowLAN = true;
allowVPN = true;
allowWAN = true;
proxyWebsockets = true;
};
};
};
})
];
}

View File

@ -0,0 +1,35 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.minio;
in
{
options.pepe.services.minio = with lib; {
enable = mkEnableOption "Enable MinIO S3-compatible object storage";
package = mkPackageOption pkgs "minio" {};
domain = mkOption {
type = types.str;
default = null;
};
};
config = mkIf cfg.enable {
services.minio = {
enable = true;
package = cfg.package;
};
pepe.core.vhost.hosts.${cfg.domain} = {
locations."/" = {
port = 9000;
allowLAN = true;
allowVPN = true;
extraConfig = ''
client_max_body_size 500M;
'';
};
};
};
}

View File

@ -0,0 +1,84 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.navidrome;
in
{
options.pepe.services.navidrome = with lib; {
enable = mkEnableOption "Enable navidrome";
package = mkPackageOption pkgs "navidrome" { };
domain = mkOption {
type = types.str;
default = null;
};
musicFolder = mkOption {
type = types.str;
default = "/media/Music";
description = "Path to the music library";
};
beetsConfig = mkOption {
type = types.str;
default = "/media/beets.conf";
description = "Path to the beets configuration file";
};
settings = mkOption {
type = types.attrs;
default = {};
description = "Additional settings for Navidrome";
};
};
config = mkIf cfg.enable {
services.navidrome = {
enable = true;
package = cfg.package;
settings = {
MusicFolder = cfg.musicFolder;
LastFM.enable = true;
LastFM.ApiKey = "5cef5cb5f9d31326b97d0f929ca9cf20";
LastFM.Secret = "d1296896126f4caae47407aecf080b25";
Spotify.ID = "3900c029b4f34f3fb61d554dda64794d";
Spotify.Secret = "d931ce5575a9401aa5ff8d37558cca0a";
EnableGravatar = true;
LogLevel = "WARN";
} // cfg.settings;
};
pepe.core.vhost.hosts.${cfg.domain} = with config.pepe.core.network; {
dnsInterfaces = [ interfaceTypes.lan interfaceTypes.vpn ];
locations."/" = {
port = 4533;
allowLAN = true;
allowVPN = true;
allowWAN = true;
};
};
systemd.services = {
"beets-update" = {
enable = true;
before = [ "beets-import.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.beets}/bin/beet -c ${cfg.beetsConfig} update";
};
};
"beets-import" = {
enable = true;
path = [ pkgs.imagemagick ];
requires = [ "beets-update.service" ];
after = [ "beets-update.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.beets}/bin/beet -c ${cfg.beetsConfig} import --flat -q ${cfg.musicFolder}";
};
startAt = "weekly";
};
};
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "navidrome" ];
};
}

View File

@ -0,0 +1,35 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.nzbget;
in
{
options.pepe.services.nzbget = with lib; {
enable = mkEnableOption "Enable nzbget";
package = mkPackageOption pkgs "nzbget" { };
domain = mkOption {
type = types.str;
default = null;
};
};
config = mkIf cfg.enable {
services.nzbget = {
enable = true;
package = cfg.package;
group = "media";
};
pepe.core.vhost.hosts.${cfg.domain} = {
locations."/" = {
port = 6789;
allowLAN = true;
allowVPN = true;
};
};
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "nzbget" ];
};
}

View File

@ -0,0 +1,35 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.prowlarr;
in
{
options.pepe.services.prowlarr = with lib; {
enable = mkEnableOption "Enable prowlarr";
package = mkPackageOption pkgs "prowlarr" { };
domain = mkOption {
type = types.str;
default = null;
};
};
config = mkIf cfg.enable {
services.prowlarr = {
enable = true;
package = cfg.package;
};
pepe.core.vhost.hosts.${cfg.domain} = {
locations."/" = {
port = 9696;
allowLAN = true;
allowVPN = true;
proxyWebsockets = true;
};
};
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "prowlarr" ];
};
}

View File

@ -0,0 +1,34 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.radarr;
in
{
options.pepe.services.radarr = with lib; {
enable = mkEnableOption "Enable radarr";
package = mkPackageOption pkgs "radarr" { };
domain = mkOption {
type = types.str;
default = null;
};
};
config = mkIf cfg.enable {
services.radarr = {
enable = true;
package = cfg.package;
};
pepe.core.vhost.hosts.${cfg.domain} = {
locations."/" = {
port = 7878;
allowLAN = true;
allowVPN = true;
};
};
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ config.services.radarr.group ];
};
}

View File

@ -0,0 +1,48 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.redlib;
in
{
options.pepe.services.redlib = with lib; {
enable = mkEnableOption "Enable Redlib";
package = mkPackageOption pkgs "redlib" { };
domain = mkOption {
type = types.str;
default = null;
};
settings = mkOption {
type = types.attrsOf types.str;
default = {
REDLIB_ROBOTS_DISABLE_INDEXING = "on";
REDLIB_DEFAULT_THEME = "dracula";
REDLIB_DEFAULT_SHOW_NSFW = "on";
REDLIB_DEFAULT_BLUR_NSFW = "off";
REDLIB_DEFAULT_USE_HLS = "on";
REDLIB_DEFAULT_HIDE_HLS_NOTIFICATION = "on";
};
description = "Environment variables for Redlib configuration";
};
};
config = mkIf cfg.enable {
services.redlib = {
enable = true;
port = 9090;
package = cfg.package;
};
systemd.services.redlib.environment = cfg.settings;
pepe.core.vhost.hosts.${cfg.domain} = {
locations."/" = {
port = config.services.redlib.port;
allowLAN = true;
allowVPN = true;
allowWAN = true;
};
};
};
}

View File

@ -0,0 +1,34 @@
{ config, lib, pkgs, ... }:
let
inherit (lib) mkIf;
cfg = config.pepe.services.sonarr;
in
{
options.pepe.services.sonarr = with lib; {
enable = mkEnableOption "Enable sonarr";
package = mkPackageOption pkgs "sonarr" { };
domain = mkOption {
type = types.str;
default = null;
};
};
config = mkIf cfg.enable {
services.sonarr = {
enable = true;
package = cfg.package;
};
pepe.core.vhost.hosts.${cfg.domain} = {
locations."/" = {
port = 8989;
allowLAN = true;
allowVPN = true;
};
};
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ config.services.sonarr.group ];
};
}

View File

@ -4,22 +4,22 @@ let
giuglioDomain = "giugl.io";
in
{
age.secrets.ovh = {
file = ../secrets/ovh.age;
age.secrets.cloudflare = {
file = ../secrets/cloudflare.age;
owner = "acme";
};
security.acme = {
acceptTerms = true;
certs.${giuglioDomain} =
{
dnsProvider = "ovh";
environmentFile = config.age.secrets.ovh.path;
dnsProvider = "cloudflare";
environmentFile = config.age.secrets.cloudflare.path;
extraDomainNames = [ "*.${giuglioDomain}" ];
};
defaults = {
email = "letsencrypt@depasquale.giugl.io";
dnsProvider = "ovh";
environmentFile = config.age.secrets.ovh.path;
dnsProvider = "cloudflare";
environmentFile = config.age.secrets.cloudflare.path;
};
};
}

View File

@ -8,7 +8,7 @@ in
sessionVariables = {
AICHAT_CONFIG_DIR = configDir;
};
packages = [ pkgs.unstablePkgs.aichat ];
packages = [ pkgs.aichat ];
file.".config/aichat/config.yaml".text = lib.readFile ./aichat/config.yaml;
file.".config/aichat/roles/commitmessage.md".text = lib.readFile ./aichat/roles/commitmessage.md;

View File

@ -15,9 +15,7 @@ let
tree
] ++ lib.optional (!pkgs.stdenv.isDarwin) pastebinit;
unstablePkgs = with pkgs.unstablePkgs; [
aider-chat-full
];
unstablePkgs = with pkgs.unstablePkgs; [ aider-chat ];
in
{
imports = [
@ -29,6 +27,6 @@ in
home = {
packages = stablePkgs ++ unstablePkgs;
stateVersion = "24.11";
stateVersion = "25.05";
};
}

28
secrets/cloudflare.age Normal file
View File

@ -0,0 +1,28 @@
age-encryption.org/v1
-> ssh-rsa QXZdow
pLJHkOUl7t8yhuq+vytj+LHENNT71NJH/gS4cEMNhEkzZjc8ScSrhVgLl/TMGImh
cb6yfRIccymVLL8gdXitIAk1srZjuwiZrFK4Ril/x8RKfV50GrHDMf+8Os3QNE05
VprnYCbyKj05+/fHSSUDnQmAAe7wvi4iA2Aa5E4DWE7t+QcMB5epPMBdJoWX6ELS
cYI7nDu32AIkYCODht9B5SChbwHACLqqG8CV5N2TfRBi6v7R2FaLhbbRvdAIQWQc
x2TGI1utRURtxgs/WhQ6Sco1QNrIEO89a/78OGxrIT/PMAukvx2J2WG6iH/2LgX0
H39680n3/YTTmL4OMWW+hKlzv4tdBsbgjR0sKRI/OzDrn/s0ZzA1JACwUn2ndOS/
0EcvW5VLLd2PHvwABm2Biw7mhilC4D6d9YZu/9uFbmPCzlXO3zmeeSnw630gDWxX
CRTEQMNE7+cdQy8j/upDBQOBnSSgmBMriuklsgcPZGnTkxWM7b9NOAeXavTucXhD
9PART4hQomlvGBzKM6Ien9kgeDG9OA9WkM+2rvLWQLDy3T9Qo37d/4qLg3sPNr4M
NUUSKRQKnA7i126ZrX/mUxcp3kJkCAsMX4GF6VMVobXshCSHqKhEWKwHuyPWI4rn
gHUqvSMKDujkA6v+9UaZESQt8jKl+N44MDUMdfYwPyE
-> ssh-ed25519 7eGqHw WIUvcH8xsrI0AcutXKxwhbrZifrb8vntIWCGDUW3qiI
3IuBdZRAGA/nfEuakP2/E+QA07jBJjBlNtotGLZlkZQ
-> ssh-rsa tO3rGg
DOBhMzioILjlrOAdycMzSwDxgww5p8QAlV/L7ECBrBFscoWageW4GOyZVjtE/7Ot
beG59oP8ra4lczXfPSOtY2qz8pN59vqw3WqG3TPMvR8xZDslVXE8nubfkoUohsG8
1ZibaP/ygQSYHUfnLzebYBhk1N4u6jeIcxJXgTLhWLlvkv9+AKAcoHhSWVbKMbz+
i8WLECJHuOeR43hJxuxvkPTWsu6HUB+yXT1J+dPcIe9W20CqX+CN0pjwSUJu0T0A
tZf2NfkYmFnho2IEdxdKnGRDE2lvQmZjf1oQn7GWFqywlVB3eCOR6K/s1Tb4I2W1
wybLuEndQBnUsUDQVs34OeN/5L3Pw40zksFSSVe3Fu5XxmWl1WemGWp1/jB7j6u7
7bnOlAMUzpqQ9yom0oxXYwEC9pUtqPwYGKeAV9o5U3vVXMDWtEXXMCe0oDjJY8js
e5xSOuaMi9CcVkU+HyjrEgw0uS4ymDWVghT4IVl8zNWeare5ALMcR/290xffaQyg
--- DIW17nFtjI4Oo+Qoi0YzeLH8A6IVAQwhtELkXWWhtwo
D*;ôCx<08>Auçd rß¾ö0ð£ú1Ldæoòr´&<26>JL4WíÌ!²=ê7:pÀØí*ûpVÙK³,0®rλâãu¼¡ã­¶óWEâ{£q½7,Ôßÿk“¾²<C2BE>ºÎàäxÔ+^xDâº0g“K,ª(zØwáC˘þ è{d}-FÜ
õ<EFBFBD>Ëþ¦TÌÍA„

View File

@ -1,29 +0,0 @@
age-encryption.org/v1
-> ssh-rsa QXZdow
aYgowxTfdGOqTYOZBbkg/dH7f+m6nvVF/8qZX0DE4hazln/QS9maWbkOwD7FLldm
HRNV/YwZZEhbujHbDqgxnXk7Q11KOA72864B6mF2VZUruyo0cnACqo7OyzwApqv/
+LPjGb9h/gCJpQ3a5Jdh202FfaNGAh358fZVDyd37XPSOykiIAAxgMlDyn+96OiM
P2vsyduWXDsqzCqtiNQrKVjryI5CIGOTAcYTgQ35S3uXFD8Gu27KfagUwZp2hdyp
3WmGl+ZTrPNdOwzLWGj/RXaeTslABn1Owmq1naASRvJpp97ToynRzkDA50rBqUyR
vGVB9IJxSjkSm3BJ4UAI6rpoz/6t2jkfNNE1cPix4AYjPAMyU+uiUSaZ/UBkwlXw
08rM1eGcBaErB1ExcDV5+jUCdJBfi6Q9vIG7Ty4wbN1PfztAhzEyzT0L1bTn1AKC
4S9n5lqFa1CdraK9eh2A+o9CNlkta+Z24ctPTVqBYtImBTKHOTofhr0omQdFV6M2
bhxsOoAAoNhwn/lWC2fAcgfPQrUOW524+eHyPjsvf4rNNv0bk5EP1J4vMrWr9rqJ
v5GEQ77YVXYQthiyg74XYc3Eo8sbtE+ncDoOquzdT385POd870qi1ht+JMY6OEmj
q8lxVau2SFTKPkkmZKmtoNrYdKp5+DsB3nOUKcIXofs
-> ssh-ed25519 7eGqHw cCrhq1kfav4TYAUOpP4O6fQ958O37Uad2jX9SUrnxn4
TSiMyrYsdblB5SFwZpw7HhmicWX1vNomhBP4HtlvHJo
-> ssh-rsa tO3rGg
J6oPMt6hiry6ks3hlAjUAY1AzEYU+7voto5XC+I6Fmyfabz9zaJ3TtbCPVF5BRNR
DOYLiD24EbcVoqECn2A2MRK1xH4owBD5YaE3Il2NwSJHhC+ZhROaMTu5mHxbzK/u
BF2MLRZ0Bwwq4szaHoFf12TFwNtIRZXS9m6l4jHdsxWj6x0iui18p3JLxij1cVwE
03rSWz+9c8bpZ6LHuPJAhatBZHSZwkKwH8Dn8NOxCLmVNRM4PyvJsj9lRn7fMwRY
64QI2z6bRAry6oINbVAAOsPlM0Ix+7hbFs/UstnENFqfcDvPzrrhALDhuDLIJpGu
WgAaMStZGjydy0oqHJceuduxVreqTlfiki7yruRFqRBgjMopwOsw5i9UPWR6SZ+E
cUCFeEynUMrmFSp5qvDX0WtkU2G/GRFEPaB+k+UN+JduIRb2RBCLt2uG0249TwO8
T4sq098XTM8wARgOv6n51lHFCPpM3iSbP5KMCYH9FhsJV0Qu9Q7157McNZuVL9Ie
--- KYLAPCcTkg/tF2c2ni4UaBTV5AhUleg8GgJH0oRQSK0
½;¬jŒ<6A>a羄ïÓÄ<C393>5`hÂŒø»æy;JúãÈå³C¢µ‡£ÏwX:eßøw³ù»ÜH
L<EFBFBD>he­jCÓ2¨ì"#˵„=Î/Dzˆ1ÒÅÿ¼™^Nû$ÃéM·úqN…v1µØÁÇ”ç¸T¦ÌñÙ—Ç0FsÕ(WeõöË…¡˜Ý8|^iYFQæ3œ ¡Õ­
A¤1­ïEÜÂÚM_=;•¸×jFÜVý[Ýät°¬{© w×…Ê<E280A6>Ö)

View File

@ -11,5 +11,5 @@ in
"nextcloud-database.age".publicKeys = pubkeys;
"restic-environment.age".publicKeys = pubkeys;
"restic-passwords.age".publicKeys = pubkeys;
"ovh.age".publicKeys = pubkeys;
"cloudflare.age".publicKeys = pubkeys;
}

View File

@ -1,14 +1,62 @@
#!/usr/bin/env bash
# this guy updates the hash of the last
# successful build of nixpkgs on hydra
# (so we don't have to rebuild EVERYTHING)
RELEASE=24.11
RELEASE=25.05
new=$(curl -sL "https://monitoring.nixos.org/prometheus/api/v1/query?query=channel_revision" | jq -r ".data.result[] | select(.metric.channel==\"nixos-${RELEASE}\") | .metric.revision")
old=$(jq -r ".nodes.nixpkgs.locked.rev" flake.lock)
update_channel() {
local channel_name="$1" # Hydra channel name (e.g., nixos-24.11)
local flake_input_name="$2" # Flake input name (e.g., nixpkgs)
local new old
echo "Old hash: ${old}"
echo "New hash: ${new}"
# Get latest revision from Hydra
new=$(curl -sL "https://monitoring.nixos.org/prometheus/api/v1/query?query=channel_revision" |
jq -r ".data.result[] | select(.metric.channel==\"${channel_name}\") | .metric.revision")
sed -i s/"${old}"/"${new}"/ flake.nix
# Get current revision from flake.lock using input name
old=$(jq -r ".nodes as \$nodes |
.nodes.root.inputs.[\"${flake_input_name}\"] as \$target_input |
\$nodes | to_entries[] |
select(.key == \$target_input) |
.value.locked.rev" flake.lock)
if [ "${old}" == "${new}" ]; then
return
fi
replace_hash "${flake_input_name}" "${new}"
echo "${new}"
}
replace_hash() {
local name="$1" hash="$2"
sed -i "s|\(${name}\.url = \"github:NixOS/nixpkgs/\)[^\"]*|\1${hash}|" flake.nix
# sed -i "s|${name}/${old}|${name}/${new}|" flake.nix
}
update_stable() {
echo "Checking NixOS ${RELEASE}..."
new_hash=$(update_channel "nixos-${RELEASE}" "nixpkgs")
if [ -z "$new_hash" ]; then
return
fi
echo "Updated stable to: ${new_hash}"
}
update_unstable() {
echo "Checking unstable..."
new_hash=$(update_channel "nixos-unstable" "nixos-unstable")
if [ -z "$new_hash" ]; then
return
fi
echo "Updated unstable to: ${new_hash}"
}
update_stable
update_unstable