This commit is contained in:
Amaury JOLY
2026-03-10 18:51:49 +01:00
commit d6a66c16b8
25 changed files with 1653 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
01-trash/
result

519
README.md Normal file
View File

@@ -0,0 +1,519 @@
# NixOS Configuration
Configuration NixOS modulaire basée sur Flakes pour laptop.
## 📁 Structure
```
nixos-config/
├── flake.nix # Point d'entrée principal avec inputs et configurations
├── configuration.nix # Configuration racine importée par le flake
├── hosts/
│ └── laptop/
│ └── configuration.nix # Configuration matérielle spécifique au laptop
└── modules/
├── laptop/ # Modules spécifiques au laptop
│ ├── default.nix # Secrets management (sops-nix) et config de base
│ ├── users.nix # Définition utilisateur et packages
│ ├── gaming.nix # Gaming (Steam, xpadneo) - avec options
│ ├── virtualization.nix # Docker & VirtualBox - avec options
│ ├── printing.nix # Imprimantes - avec options
│ ├── power.nix # Power management - avec options
│ ├── bluetooth.nix # Bluetooth - avec options
│ └── zwift.nix # Zwift cycling simulator - avec options
└── nixos/ # Modules système génériques
├── base.nix # Configuration système de base (Nix, packages, fonts, locale)
├── yubikey.nix # Authentification YubiKey globale (login/sudo)
├── desktop-i3.nix # Window manager i3
├── net.nix # Réseau (DNS chiffré, WiFi settings)
├── wireless-networks.nix # Configuration des réseaux WiFi (SSID, auth)
└── parsec.nix # Parsec Cloud client
```
## ⚙️ Configuration Centralisée
Tous les paramètres personnalisables se trouvent dans [config.nix](config.nix) :
```nix
{
username = "alice"; # Votre username
userEmail = "amaury.joly"; # Email pour réseaux WPA-EAP
configFlakePath = /etc/nixos; # Chemin vers la config flake
timezone = "Europe/Paris"; # Timezone
locale = "fr_FR.UTF-8"; # Locale
hostname = "nixos"; # Hostname du système
}
```
**À adapter lors de la première installation :**
1. Ouvrir [config.nix](config.nix)
2. Remplacer les valeurs par vos préférences (username, email, timezone, etc.)
3. Ces valeurs sont ensuite utilisées automatiquement dans tous les modules
## 🎛️ Système d'Options Modulaires
La configuration utilise le système d'options NixOS pour activer/désactiver des fonctionnalités. Toutes les options sont définies dans [configuration.nix](configuration.nix) :
### Gaming
```nix
custom.gaming.enable = true; # Active Steam et support gaming
custom.gaming.enableXpadneo = true; # Driver pour manettes Xbox
```
### Virtualisation
```nix
custom.virtualization.docker.enable = true; # Active Docker
custom.virtualization.docker.dnsServers = [ "172.17.0.1" ]; # DNS pour containers
custom.virtualization.virtualbox.enable = true; # Active VirtualBox
```
### Impression
```nix
custom.printing.enable = true;
custom.printing.printers = [ # Liste des imprimantes
{
name = "Mon_Imprimante";
location = "Bureau";
deviceUri = "http://192.168.1.100";
model = "drv:///sample.drv/generic.ppd";
}
];
custom.printing.defaultPrinter = "Mon_Imprimante";
```
### Power Management
```nix
custom.power.enable = true;
custom.power.cpuGovernor = "powersave"; # ou "performance", "ondemand"
```
### Bluetooth
```nix
custom.bluetooth.enable = true;
custom.bluetooth.powerOnBoot = true; # Activer Bluetooth au démarrage
```
### Zwift
```nix
custom.zwift.enable = true; # Zwift cycling simulator
```
**💡 Avantages :**
-**Activation conditionnelle** : Désactiver une fonctionnalité = `enable = false;`
-**Documentation intégrée** : `nixos-option custom.gaming.enable` affiche la doc
-**Pas de code mort** : Les modules désactivés ne sont pas évalués
-**Réutilisable** : Facile de créer une config pour une autre machine
## 🚀 Déploiement
### Build et test (sans activer)
```bash
cd ~/src/nixos-config
nixos-rebuild build --flake .#laptop
```
### Activer la configuration
```bash
sudo nixos-rebuild switch --flake .#laptop
```
### Mettre à jour les inputs
```bash
nix flake update
sudo nixos-rebuild switch --flake .#laptop
```
### Avec nh (helper recommandé)
```bash
nh os switch # NH_OS_FLAKE est configuré automatiquement
```
## 🔐 Gestion des Secrets (sops-nix)
Cette configuration utilise [sops-nix](https://github.com/Mic92/sops-nix) pour gérer les secrets de manière sécurisée.
### Configuration initiale
1. **Générer une clé age** (si pas déjà fait) :
```bash
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
```
2. **Configurer sops pour la clé publique** :
```bash
# Afficher votre clé publique
age-keygen -y ~/.config/sops/age/keys.txt
# Créer .sops.yaml à la racine si nécessaire
cat > .sops.yaml << EOF
keys:
- &alice YOUR_PUBLIC_KEY_HERE
creation_rules:
- path_regex: secrets/.*\.yaml$
key_groups:
- age:
- *alice
EOF
```
3. **Créer et éditer les fichiers secrets** :
```bash
mkdir -p ~/.config/secrets/
# Pour les credentials WiFi (legacy - optionnel)
sops ~/.config/secrets/wireless.yaml
# Pour la configuration complète des réseaux WiFi (RECOMMANDÉ - tout chiffré)
sops ~/.config/secrets/wifi-networks.yaml
# Pour Zwift
sops ~/.config/secrets/zwift.yaml
```
### 📡 Configuration WiFi Sécurisée (Tout Chiffré)
**🔒 Nouveauté** : La configuration WiFi est maintenant **entièrement chiffrée** avec sops, incluant :
- ✅ Noms des réseaux (SSID)
- ✅ Identités/usernames
- ✅ Mots de passe
- ✅ Structure complète de configuration
**Avantages** :
- Aucune information sensible visible dans le code source
- Pas d'exposition des lieux (noms de réseaux maison/travail)
- Configuration complète dans un seul fichier chiffré
### Créer la configuration WiFi chiffrée
1. **Copier l'exemple de configuration** :
```bash
cp wifi-networks.yaml.example ~/.config/secrets/wifi-networks.yaml
```
2. **Éditer avec sops** :
```bash
sops ~/.config/secrets/wifi-networks.yaml
```
3. **Format du fichier** (syntaxe wpa_supplicant.conf) :
```yaml
# Réseau personnel (WPA-PSK)
network={
ssid="Mon_WiFi_Maison"
psk="mon_mot_de_passe_securise"
priority=100
}
# Réseau entreprise (WPA-EAP)
network={
ssid="Work_Network"
key_mgmt=WPA-EAP
eap=TTLS
identity="username@company.com"
password="password_entreprise"
phase2="auth=PAP"
priority=10
}
# Eduroam (université)
network={
ssid="eduroam"
key_mgmt=WPA-EAP
eap=PEAP
identity="etudiant@universite.fr"
password="mot_de_passe_univ"
}
# Réseau caché
network={
ssid="Hidden_Network"
psk="password"
scan_ssid=1
priority=50
}
```
### Ajouter un nouveau réseau WiFi
**Tout se fait dans le fichier chiffré !**
```bash
# Éditer le fichier chiffré
sops ~/.config/secrets/wifi-networks.yaml
# Ajouter un nouveau bloc network={...}
# Sauvegarder et quitter
# Appliquer la configuration
sudo nixos-rebuild switch --flake .#laptop
```
**Exemples de configuration selon le type de réseau** :
**WiFi personnel (WPA2)** :
```
network={
ssid="MonReseau"
psk="MotDePasse123"
priority=100
}
```
**WiFi entreprise (802.1X)** :
```
network={
ssid="CorpWiFi"
key_mgmt=WPA-EAP
eap=TTLS
identity="user@company.com"
password="my_password"
phase2="auth=PAP"
}
```
**Hotspot mobile** :
```
network={
ssid="iPhone_Alice"
psk="hotspot_pass"
scan_ssid=1
}
```
### Migration depuis l'ancienne configuration
Si vous aviez des réseaux définis en Nix (ancienne méthode), migrez-les vers le fichier chiffré :
1. Copier les configs depuis [modules/nixos/wireless-networks.nix](modules/nixos/wireless-networks.nix)
2. Convertir au format wpa_supplicant.conf
3. Ajouter dans `~/.config/secrets/wifi-networks.yaml`
4. Chiffrer avec sops
5. Les anciennes définitions seront ignorées
### Format du fichier zwift.yaml
```yaml
# Configuration Zwift ici
```
## 📦 Modules et Fonctionnalités
### 🖥️ Système de Base
**Base System** ([modules/nixos/base.nix](modules/nixos/base.nix))
- Configuration Nix avec flakes et nix-command
- Packages système essentiels (wget, jq, element-desktop, etc.)
- Fonts Nerd Fonts (DejaVu, Droid Sans Mono)
- Locale française (Europe/Paris - configurable)
- Shell Fish par défaut
**YubiKey Authentication** ([modules/nixos/yubikey.nix](modules/nixos/yubikey.nix))
- Active l'authentification YubiKey (U2F) pour `login` et `sudo`
- S'applique à tous les systèmes qui importent ce module
**Fingerprint (Laptop)** ([modules/laptop/fingerprint.nix](modules/laptop/fingerprint.nix))
- Active `fprintd` sur le laptop
- Ajoute l'authentification empreinte pour `login` et `sudo`
- Sur laptop, l'authentification peut se faire avec **YubiKey ou empreinte** selon la méthode disponible
**Networking** ([modules/nixos/net.nix](modules/nixos/net.nix))
- **DNS chiffré** : dnscrypt-proxy (primaire + backup dns0-eu)
- **WiFi** : wpa_supplicant avec multi-réseaux
- **Hostname** : Configurable via [config.nix](config.nix)
**Desktop** ([modules/nixos/desktop-i3.nix](modules/nixos/desktop-i3.nix))
- Window manager **i3**
- Terminal : **alacritty**
- Launcher : **rofi**
- Panel : **tint2**
- Notifications : **dunst**
### 🎮 Fonctionnalités Optionnelles (avec options)
**Gaming** ([modules/laptop/gaming.nix](modules/laptop/gaming.nix))
- Steam avec steam-hardware
- Driver xpadneo pour manettes Xbox (optionnel)
- Option : `custom.gaming.enable`
**Virtualization** ([modules/laptop/virtualization.nix](modules/laptop/virtualization.nix))
- Docker avec DNS personnalisé
- VirtualBox avec extension pack
- Options : `custom.virtualization.docker.enable`, `custom.virtualization.virtualbox.enable`
**Printing** ([modules/laptop/printing.nix](modules/laptop/printing.nix))
- CUPS avec configuration d'imprimantes
- Option : `custom.printing.enable`
**Power Management** ([modules/laptop/power.nix](modules/laptop/power.nix))
- CPU frequency governor configurable
- Option : `custom.power.enable`
**Bluetooth** ([modules/laptop/bluetooth.nix](modules/laptop/bluetooth.nix))
- Bluetooth avec blueman GUI
- Mode dual controller + experimental features
- Option : `custom.bluetooth.enable`
**Zwift** ([modules/laptop/zwift.nix](modules/laptop/zwift.nix))
- Zwift cycling simulator via Docker
- Ports réseau configurés automatiquement
- Option : `custom.zwift.enable`
### 👤 Utilisateur & Applications
**User Configuration** ([modules/laptop/users.nix](modules/laptop/users.nix))
Packages par catégorie :
- **Browsers** : Firefox
- **Office** : LibreOffice, OnlyOffice, Obsidian, TickTick, Nextcloud
- **Development** : VSCode, Git, Neovim, Zotero, tcpdump, Pandoc
- **Communication** : Slack, Thunderbird, Discord
- **Media** : VLC, Spotify, Mixxx, Pympress
- **Gaming** : Prismlauncher (Minecraft), Widelands, Moonlight
- **System** : Rclone, Fuse3, Pavucontrol
## 🔧 Flake Inputs
- **nixpkgs** : nixos-unstable channel
- **sops-nix** : Secrets management
- **parsec-cloud-nix** : Parsec Cloud client
- **claude-desktop** : Claude AI desktop app
- **zwift** : Zwift cycling simulator
## <20> Personnalisation
### Configuration de base
1. **Timezone et Locale** : Éditer [config.nix](config.nix)
```nix
timezone = "Europe/Paris";
locale = "fr_FR.UTF-8";
```
2. **Username et email** : Éditer [config.nix](config.nix)
```nix
username = "alice";
userEmail = "votre.email";
```
3. **Hostname** : Éditer [config.nix](config.nix)
```nix
hostname = "nixos";
```
### Activer/Désactiver des fonctionnalités
Dans [configuration.nix](configuration.nix), modifier les options `custom.*` :
```nix
# Désactiver le gaming
custom.gaming.enable = false;
# Activer uniquement Docker (pas VirtualBox)
custom.virtualization.docker.enable = true;
custom.virtualization.virtualbox.enable = false;
# Changer le CPU governor
custom.power.cpuGovernor = "performance"; # pour laptop branché
```
### Ajouter des packages utilisateur
Éditer [modules/laptop/users.nix](modules/laptop/users.nix) et ajouter dans la liste appropriée :
```nix
packages = with pkgs; [
# Development
python3
nodejs
# ... vos packages
];
```
### Ajouter une nouvelle fonctionnalité avec options
1. Créer `modules/laptop/ma-feature.nix` :
```nix
{ config, lib, pkgs, ... }:
{
options.custom.maFeature.enable = lib.mkEnableOption "ma fonctionnalité";
config = lib.mkIf config.custom.maFeature.enable {
# votre configuration
};
}
```
2. Importer dans [configuration.nix](configuration.nix)
3. Activer : `custom.maFeature.enable = true;`
## 🐛 Dépannage
### Lister les options disponibles
```bash
# Voir toutes les options custom.*
nixos-option custom
# Voir une option spécifique avec sa documentation
nixos-option custom.gaming.enable
```
### Erreurs de build
```bash
# Vérifier la syntaxe Nix
nix flake check
# Build avec logs détaillés
nixos-rebuild build --flake .#laptop --show-trace
```
### Secrets non déchiffrables
Vérifier que :
- La clé age existe : `~/.config/sops/age/keys.txt`
- Les fichiers secrets existent : `~/.config/secrets/*.yaml`
- Les permissions sont correctes (0400 recommandé)
### Problèmes DNS
```bash
# Vérifier dnscrypt-proxy
systemctl status dnscrypt-proxy
systemctl status dnscrypt-proxy-backup
# Tester la résolution
dig @127.0.0.1 example.com
```
## 📚 Ressources
- [NixOS Manual](https://nixos.org/manual/nixos/stable/)
- [Nix Flakes Guide](https://nixos.wiki/wiki/Flakes)
- [sops-nix Documentation](https://github.com/Mic92/sops-nix)
- [Home Manager](https://github.com/nix-community/home-manager) (à considérer pour config utilisateur)
## 📝 Notes
- **stateVersion** : Actuellement `24.05` - **NE PAS MODIFIER** après installation
- **Auto-upgrade** : Désactivé pour éviter les mises à jour imprévues
- **Unfree packages** : Activé globalement pour Steam, Slack, etc.
## 🔄 Maintenance
### Nettoyage du store Nix
```bash
# Via nh (automatique toutes les 4 jours, garde 3 générations)
nh clean all --keep-since 4d --keep 3
# Ou manuellement
nix-collect-garbage -d
sudo nix-collect-garbage -d
```
### Lister les générations
```bash
nixos-rebuild list-generations
```
### Rollback
```bash
sudo nixos-rebuild switch --rollback
# Ou au boot via GRUB
```

19
config.nix Normal file
View File

@@ -0,0 +1,19 @@
# Central Configuration
# Define user-specific and system-specific values here
# This file should be imported in flake.nix as specialArgs
{
# User configuration
username = "alice";
userEmail = "amaury.joly";
# System paths
configFlakePath = /etc/nixos;
# Timezone and locale
timezone = "Europe/Paris";
locale = "fr_FR.UTF-8";
# Hostname
hostname = "nixos";
}

62
configuration.nix Normal file
View File

@@ -0,0 +1,62 @@
{ config, pkgs, ... }:
{
imports = [
# Hardware configuration
./hosts/laptop/configuration.nix
# NixOS base modules
./modules/nixos/base.nix
./modules/nixos/yubikey.nix
./modules/nixos/desktop-i3.nix
./modules/nixos/net.nix
./modules/nixos/wireless-networks.nix
./modules/nixos/parsec.nix
# Laptop-specific modules
./modules/laptop/default.nix
./modules/laptop/fingerprint.nix
./modules/laptop/users.nix
./modules/laptop/bluetooth.nix
./modules/laptop/zwift.nix
# Optional feature modules (with options)
./modules/laptop/gaming.nix
./modules/laptop/virtualization.nix
./modules/laptop/printing.nix
./modules/laptop/power.nix
];
# Enable bootloader
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# Enable optional features via custom options
custom.gaming.enable = true;
custom.gaming.enableXpadneo = true;
custom.virtualization.docker.enable = true;
custom.virtualization.virtualbox.enable = true;
custom.printing.enable = true;
custom.printing.printers = [
{
name = "TOSHIBA_5eme_Luminy";
location = "Work";
deviceUri = "http://139.124.5.114";
model = "drv:///sample.drv/generic.ppd";
ppdOptions = {
PageSize = "A4";
};
}
];
custom.printing.defaultPrinter = "TOSHIBA_5eme_Luminy";
custom.power.enable = true;
custom.power.cpuGovernor = "powersave";
custom.bluetooth.enable = true;
custom.bluetooth.powerOnBoot = true;
custom.zwift.enable = true;
}

320
flake.lock generated Normal file
View File

@@ -0,0 +1,320 @@
{
"nodes": {
"claude-desktop": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1764098187,
"narHash": "sha256-H6JjWXhKqxZ8QLMoqndZx9e5x0Sv5AiipSmqvIxIbgo=",
"owner": "k3d3",
"repo": "claude-desktop-linux-flake",
"rev": "b2b040cb68231d2118906507d9cc8fd181ca6308",
"type": "github"
},
"original": {
"owner": "k3d3",
"repo": "claude-desktop-linux-flake",
"type": "github"
}
},
"fenix": {
"inputs": {
"nixpkgs": [
"parsec-cloud-nix",
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1773040819,
"narHash": "sha256-9sFursJ9PJoYQFyARzQEKcv5D5SaGU3xJtZDSqEMtek=",
"owner": "nix-community",
"repo": "fenix",
"rev": "6ed2afab20d32920f0984e619ff5f58b2b5d2948",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nix-github-actions": {
"inputs": {
"nixpkgs": [
"parsec-cloud-nix",
"poetry2nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1729742964,
"narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
"owner": "nix-community",
"repo": "nix-github-actions",
"rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nix-github-actions",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1772963539,
"narHash": "sha256-9jVDGZnvCckTGdYT53d/EfznygLskyLQXYwJLKMPsZs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9dcb002ca1690658be4a04645215baea8b95f31d",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1770141374,
"narHash": "sha256-yD4K/vRHPwXbJf5CK3JkptBA6nFWUKNX/jlFp2eKEQc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "41965737c1797c1d83cfb0b644ed0840a6220bd1",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"parsec-cloud-nix": {
"inputs": {
"fenix": "fenix",
"nixpkgs": [
"nixpkgs"
],
"poetry2nix": "poetry2nix"
},
"locked": {
"lastModified": 1773132441,
"narHash": "sha256-fv5MurEa6CZt6gwZ2Gr7CU8g4OyuMfTrmmEKO8MYPvc=",
"owner": "FirelightFlagboy",
"repo": "parsec-cloud-nix",
"rev": "cc60bedad264efec120f87a9fb536317878ee3c7",
"type": "github"
},
"original": {
"owner": "FirelightFlagboy",
"repo": "parsec-cloud-nix",
"type": "github"
}
},
"poetry2nix": {
"inputs": {
"flake-utils": "flake-utils_2",
"nix-github-actions": "nix-github-actions",
"nixpkgs": [
"parsec-cloud-nix",
"nixpkgs"
],
"systems": "systems_3",
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1743690424,
"narHash": "sha256-cX98bUuKuihOaRp8dNV1Mq7u6/CQZWTPth2IJPATBXc=",
"owner": "nix-community",
"repo": "poetry2nix",
"rev": "ce2369db77f45688172384bbeb962bc6c2ea6f94",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "poetry2nix",
"type": "github"
}
},
"root": {
"inputs": {
"claude-desktop": "claude-desktop",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"parsec-cloud-nix": "parsec-cloud-nix",
"sops-nix": "sops-nix",
"zwift": "zwift"
}
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1772938598,
"narHash": "sha256-cxHbp8na0qO5U3SPGkSLzg3g9C81gJEG/7WbYPktD6o=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "51966da92da795f1cda89bef70d7c61266d4123a",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
},
"sops-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1773096132,
"narHash": "sha256-M3zEnq9OElB7zqc+mjgPlByPm1O5t2fbUrH3t/Hm5Ag=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "d1ff3b1034d5bab5d7d8086a7803c5a5968cd784",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"parsec-cloud-nix",
"poetry2nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1730120726,
"narHash": "sha256-LqHYIxMrl/1p3/kvm2ir925tZ8DkI0KA10djk8wecSk=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "9ef337e492a5555d8e17a51c911ff1f02635be15",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
},
"zwift": {
"inputs": {
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1772604980,
"narHash": "sha256-LepcA4EUgPHmQ05nYYmRvSkAB27oqm8CjfJuxPNp12k=",
"owner": "netbrain",
"repo": "zwift",
"rev": "1cd77e180d6963e843d3b56793adaaecafe83214",
"type": "github"
},
"original": {
"owner": "netbrain",
"repo": "zwift",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

56
flake.nix Normal file
View File

@@ -0,0 +1,56 @@
{
inputs = {
sops-nix.url = "github:Mic92/sops-nix";
sops-nix.inputs.nixpkgs.follows = "nixpkgs";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
parsec-cloud-nix = {
url = "github:FirelightFlagboy/parsec-cloud-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
claude-desktop = {
url = "github:k3d3/claude-desktop-linux-flake";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
zwift.url = "github:netbrain/zwift";
};
outputs = { self, nixpkgs, sops-nix, zwift, flake-utils, parsec-cloud-nix, claude-desktop, ... }:
let
customConfig = import ./config.nix;
in
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
};
in {
}) //
{
nixosConfigurations.laptop = nixpkgs.lib.nixosSystem {
modules = [
sops-nix.nixosModules.sops
zwift.nixosModules.zwift
./configuration.nix
({ pkgs, lib, ...}:
{
environment.systemPackages = with pkgs; [
claude-desktop.packages.${pkgs.stdenv.hostPlatform.system}.claude-desktop-with-fhs
];
})
];
specialArgs = {
inherit customConfig;
parsec-cloud-nix = parsec-cloud-nix;
claude-desktop = claude-desktop;
};
};
};
}

View File

@@ -0,0 +1,41 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "usbhid" "sd_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/e9209e4f-94b4-45ef-bed6-9435c96ee864";
fsType = "ext4";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/E59B-B8FC";
fsType = "vfat";
options = [ "fmask=0077" "dmask=0077" ];
};
swapDevices =
[ { device = "/dev/disk/by-uuid/e8cd6918-bc63-4d24-b8eb-6a1170844a80"; }
];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp0s31f6.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp0s20f3.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View File

@@ -0,0 +1,33 @@
# Module: Bluetooth Configuration
# Description: Enables Bluetooth with dual controller mode and experimental features
# Services: bluetooth, blueman (GUI manager)
{ config, lib, ... }:
{
options.custom.bluetooth = {
enable = lib.mkEnableOption "Bluetooth support with blueman GUI";
powerOnBoot = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Power on Bluetooth adapter on boot";
};
};
config = lib.mkIf config.custom.bluetooth.enable {
hardware.bluetooth = {
enable = true;
powerOnBoot = config.custom.bluetooth.powerOnBoot;
settings = {
General = {
ControllerMode = "dual";
Privacy = "device";
JustWorksRepairing = "always";
Experimental = true;
};
};
};
services.blueman.enable = true;
};
}

View File

@@ -0,0 +1,36 @@
# Module: Laptop Secrets & Base Configuration
# Description: Secrets management (sops-nix) and keyboard layout
# Services: sops-nix
# Dependencies: sops-nix for secrets management
# Note: Other laptop features (gaming, virtualization, etc.) are in separate modules
{ customConfig, ... }:
let
userHome = "/home/${customConfig.username}";
in
{
sops.validateSopsFiles = false;
sops.age.keyFile = "${userHome}/.config/sops/age/keys.txt";
# WiFi networks configuration - entire network list encrypted
sops.secrets.wifi-networks = {
path = "/run/secrets/wifi-networks.conf";
sopsFile = ../../secrets/wifi-networks.yaml;
format = "yaml";
key = "wifi-networks";
owner = "wpa_supplicant";
group = "wpa_supplicant";
mode = "0400";
};
sops.secrets.zwift = {
path = "${userHome}/.config/zwift/config";
sopsFile = ../../secrets/zwift.yaml;
owner = customConfig.username;
group = "users";
mode = "0400";
};
services.xserver.xkb.layout = "fr";
}

View File

@@ -0,0 +1,10 @@
{ pkgs, ... }:
{
services.fprintd.enable = true;
services.fprintd.tod.enable = true;
services.fprintd.tod.driver = pkgs.libfprint-2-tod1-goodix-550a;
security.pam.services.login.fprintAuth = true;
security.pam.services.sudo.fprintAuth = true;
}

29
modules/laptop/gaming.nix Normal file
View File

@@ -0,0 +1,29 @@
# Module: Gaming Support
# Description: Enables Steam and gamepad drivers (xpadneo for Xbox controllers)
# Services: Steam, steam-hardware
{ config, lib, pkgs, ... }:
{
options.custom.gaming = {
enable = lib.mkEnableOption "gaming support (Steam, gamepad drivers)";
enableXpadneo = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Enable xpadneo driver for Xbox controllers";
};
};
config = lib.mkIf config.custom.gaming.enable {
hardware.steam-hardware.enable = true;
programs.steam = {
enable = true;
};
boot.extraModulePackages = lib.mkIf config.custom.gaming.enableXpadneo [
pkgs.linuxPackages.xpadneo
];
};
}

21
modules/laptop/power.nix Normal file
View File

@@ -0,0 +1,21 @@
# Module: Power Management
# Description: CPU frequency governor and power management settings
# Services: powerManagement
{ config, lib, ... }:
{
options.custom.power = {
enable = lib.mkEnableOption "power management configuration";
cpuGovernor = lib.mkOption {
type = lib.types.str;
default = "powersave";
description = "CPU frequency governor (powersave, performance, ondemand, etc.)";
};
};
config = lib.mkIf config.custom.power.enable {
powerManagement.cpuFreqGovernor = config.custom.power.cpuGovernor;
};
}

View File

@@ -0,0 +1,33 @@
# Module: Printing Configuration
# Description: CUPS printing service with configured printers
# Services: printing (CUPS)
{ config, lib, ... }:
{
options.custom.printing = {
enable = lib.mkEnableOption "printing support (CUPS)";
printers = lib.mkOption {
type = lib.types.listOf lib.types.attrs;
default = [];
description = "List of printers to configure";
};
defaultPrinter = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Default printer name";
};
};
config = lib.mkIf config.custom.printing.enable {
services.printing.enable = true;
hardware.printers = lib.mkIf (config.custom.printing.printers != []) {
ensurePrinters = config.custom.printing.printers;
ensureDefaultPrinter = lib.mkIf (config.custom.printing.defaultPrinter != null)
config.custom.printing.defaultPrinter;
};
};
}

60
modules/laptop/users.nix Normal file
View File

@@ -0,0 +1,60 @@
# Module: User Configuration
# Description: Defines the main user 'alice' with groups, permissions, and user packages
# Packages: Browsers (Firefox), Office (LibreOffice), Development (VSCode, Git),
# Media (VLC, Spotify), Communication (Slack, Thunderbird), and more
{ pkgs, customConfig, ... }:
{
users.users."${customConfig.username}" = {
isNormalUser = true;
home = "/home/${customConfig.username}";
# Base groups - docker/vboxusers are added by virtualization.nix if enabled
extraGroups = [ "wheel" "audio" "dialout" "plugdev" ];
packages = with pkgs; [
# Browsers & Web
firefox
# Office & Productivity
libreoffice
onlyoffice-desktopeditors
obsidian
ticktick
nextcloud-client
# Development
neovim
git
vscode
zotero
tcpdump
pandoc
libsecret
# Communication
slack
thunderbird
discord
# Media & Creative
vlc
spotify
mixxx
pympress
# Gaming & Entertainment
prismlauncher # Minecraft launcher
widelands # Strategy game
wasistlos # Game
moonlight-qt # Game streaming
# System & Cloud
rclone
fuse3
pavucontrol
tree
sops
age
];
};
}

View File

@@ -0,0 +1,42 @@
# Module: Virtualization
# Description: Docker and VirtualBox virtualization support
# Services: Docker daemon, VirtualBox
{ config, lib, pkgs, customConfig, ... }:
{
options.custom.virtualization = {
docker = {
enable = lib.mkEnableOption "Docker container runtime";
dnsServers = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "172.17.0.1" ];
description = "DNS servers for Docker containers (points to dnscrypt-proxy)";
};
};
virtualbox = {
enable = lib.mkEnableOption "VirtualBox virtualization";
};
};
config = lib.mkMerge [
(lib.mkIf config.custom.virtualization.docker.enable {
virtualisation.docker = {
enable = true;
daemon.settings = {
# Docker DNS points to dnscrypt-proxy configured in net.nix
dns = config.custom.virtualization.docker.dnsServers;
};
};
users.users."${customConfig.username}".extraGroups = [ "docker" ];
})
(lib.mkIf config.custom.virtualization.virtualbox.enable {
virtualisation.virtualbox.host.enable = true;
users.users."${customConfig.username}".extraGroups = [ "vboxusers" ];
})
];
}

35
modules/laptop/zwift.nix Normal file
View File

@@ -0,0 +1,35 @@
# Module: Zwift Configuration
# Description: Configures Zwift cycling simulator via Docker with proper networking
# Services: Zwift Docker container
# Ports: UDP 3022, 3024 / TCP 21587, 21588
{ config, lib, pkgs, customConfig, ... }:
{
options.custom.zwift = {
enable = lib.mkEnableOption "Zwift cycling simulator";
};
config = lib.mkIf config.custom.zwift.enable {
programs.zwift = {
enable = true;
image = "docker.io/netbrain/zwift";
version = "latest"; # FIXME: Pin to specific version for reproducibility
containerTool = "docker";
zwiftWorkoutDir = "/var/lib/zwift/workouts";
zwiftActivityDir = "/var/lib/zwift/activities";
zwiftLogDir = "/var/lib/zwift/logs";
zwiftScreenshotsDir = "/var/lib/zwift/screenshots";
zwiftFg = true;
networking = "bridge";
# Use actual user UID/GID instead of hardcoded 1000
zwiftUid = toString config.users.users."${customConfig.username}".uid;
zwiftGid = toString config.users.groups.users.gid;
};
networking.firewall = {
allowedUDPPorts = [ 3022 3024 ];
allowedTCPPorts = [ 21587 21588 ];
};
};
}

63
modules/nixos/base.nix Normal file
View File

@@ -0,0 +1,63 @@
# Module: Base System Configuration
# Description: Core NixOS configuration with Nix settings, base packages, fonts,
# localization (FR), Fish shell, and security (GPG)
# Services: gvfs, udisks2, gnupg-agent
{ pkgs, customConfig, ... }:
{
nix.settings = {
experimental-features = [ "nix-command" "flakes" ];
substituters = [
"https://cache.nixos.org/"
"https://parsec-cloud.cachix.org"
];
trusted-public-keys = [
"parsec-cloud.cachix.org-1:MuWfCBKBfuUWqwB6xKFK0armIJ+A+Mi++HohuB6YvTk="
];
};
programs.nh = {
enable = true;
clean.enable = true;
clean.extraArgs = "--keep-since 4d --keep 3";
flake = builtins.toString customConfig.configFlakePath;
};
nixpkgs.config.allowUnfree = true;
time.timeZone = customConfig.timezone;
services.gvfs.enable = true;
services.udisks2.enable = true;
i18n.defaultLocale = customConfig.locale;
programs.fish.enable = true;
users.defaultUserShell = pkgs.fish;
environment.systemPackages = with pkgs; [
wget
jq
linuxPackages.cpupower
element-desktop
ntfs3g
zip
unzip
];
fonts.packages = with pkgs; [
nerd-fonts.dejavu-sans-mono
nerd-fonts.droid-sans-mono
];
programs.gnupg.agent = {
enable = true;
enableSSHSupport = true;
};
# WARNING: DO NOT CHANGE this value after installation!
# See: https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion
system.stateVersion = "24.05";
}

View File

@@ -0,0 +1,31 @@
# Module: i3 Window Manager Configuration
# Description: Enables X11 with i3 window manager and associated desktop tools
# Services: xserver with i3
# Packages: alacritty (terminal), tint2 (panel), rofi (launcher), i3lock, dunst
{ pkgs, ... }:
{
services.xserver.enable = true;
services.xserver.windowManager.i3.enable = true;
services.xserver.autorun = true;
environment.systemPackages = with pkgs; [
alacritty
tint2
awesome
maim
xclip
dunst
xss-lock
dex
rofi
i3status
i3blocks
oh-my-posh
glances
arandr
nautilus
brightnessctl
];
}

98
modules/nixos/net.nix Normal file
View File

@@ -0,0 +1,98 @@
# Module: Network Configuration
# Description: Network setup with dnscrypt-proxy for encrypted DNS, WiFi networks
# configuration via wpa_supplicant, and hostname settings
# Services: dnscrypt-proxy (primary + backup), wpa_supplicant
# Security: WiFi credentials stored via sops-nix secrets
{ config, lib, pkgs, customConfig, ... }:
let
backupToml = pkgs.writeText "dnscrypt-proxy-backup.toml" ''
listen_addresses = ["127.0.0.2:53"]
server_names = ["dns0-eu"]
[sources.public-resolvers]
urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md']
cache_file = '/var/lib/dnscrypt-proxy-backup/public-resolvers.md'
minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
refresh_delay = 72
'';
userHome = "/home/${customConfig.username}";
in
{
networking.nftables.enable = true;
networking.firewall = {
enable = true;
allowPing = true;
# allowedTCPPorts = [ ... ]; # keep closed by default
interfaces.docker0 = {
allowedUDPPorts = [ 53 ];
allowedTCPPorts = [ 53 ];
};
};
networking.hostName = customConfig.hostname;
# Pick only one of the below networking options.
networking.wireless.enable = true;
# networking.wireless.userControlled = true;
# networking.wireless.secretsFile = config.sops.secrets.wifi.path;
# Load encrypted WiFi networks configuration via wpa_supplicant include files.
# This is supported by the NixOS module and keeps SSIDs out of the Nix store.
networking.wireless.extraConfigFiles = lib.mkIf (config.sops.secrets ? wifi-networks) [
config.sops.secrets.wifi-networks.path
];
networking.wireless.enableHardening = false;
# systemd.services.wpa_supplicant.after = [ "sops-install-secrets.service" ];
# systemd.services.wpa_supplicant.requires = [ "sops-install-secrets.service" ];
# You can also define networks in Nix if you prefer (less secure - names visible):
# networking.wireless.networks = { ... };
networking.interfaces.lo.ipv4.addresses = [
{ address = "127.0.0.1"; prefixLength = 8; }
{ address = "127.0.0.2"; prefixLength = 8; }
];
networking.nameservers = [ "127.0.0.1" "127.0.0.2" ];
# networking.networkmanager.dns = "none";
services.resolved.enable = false;
services.dnscrypt-proxy = {
enable = true;
settings = {
listen_addresses = [ "127.0.0.1:53" "172.17.0.1:53" ];
server_names = [ "amaury" ];
bootstrap_resolvers = [];
sources = {};
static = {
"amaury".stamp = "sdns://AgcAAAAAAAAADTgyLjY0LjIzNy4yNDYADWFtYXVyeWpvbHkuZnIUL2Rucy1xdWVyeS9pZC1hbWF1cnk";
};
cache = true;
ignore_system_dns = true;
timeout = 5000;
};
};
systemd.services."dnscrypt-proxy-backup" = {
description = "dnscrypt-proxy backup (dns0-eu)";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy -config ${backupToml}";
Restart = "on-failure";
NoNewPrivileges = true;
DynamicUser = true;
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
};
};
systemd.services.dnscrypt-proxy.serviceConfig = {
StateDirectory = "dnscrypt-proxy";
};
}

28
modules/nixos/parsec.nix Normal file
View File

@@ -0,0 +1,28 @@
# Module: Parsec Cloud Client
# Description: Installs Parsec Cloud client (v3) with CLI and GUI
# Dependencies: parsec-cloud-nix flake input
# Note: Requires increased Node.js heap size during build (workaround)
{ pkgs, parsec-cloud-nix, ... }:
let
pc = parsec-cloud-nix.packages.${pkgs.stdenv.hostPlatform.system};
# WORKAROUND: Parsec build runs out of memory without increased heap size
# This increases Node.js memory limit from default 512MB to 8GB
nativeBuildPatched = pc.parsec-cloud.v3.native-client-build.overrideAttrs (old: {
NODE_OPTIONS = "--max-old-space-size=8192";
});
parsecClientPatched = pc.parsec-cloud.v3.client.override {
native-client-build = nativeBuildPatched;
};
parsecCli = pc.parsec-cloud.v3.cli;
in
{
environment.systemPackages = [
parsecClientPatched
parsecCli
];
}

View File

@@ -0,0 +1,16 @@
# Module: Wireless Networks Configuration (Encrypted)
# Description: WiFi networks configuration fully encrypted with sops-nix
# Security: Network names, SSIDs, and all configuration stored in encrypted secrets
# Files: ~/.config/secrets/wifi-networks.yaml (encrypted with sops)
# Note: The actual networks are loaded at runtime from the encrypted file
{ config, lib, pkgs, ... }:
{
# WiFi networks are loaded from encrypted file at runtime
# The file is in wpa_supplicant.conf format and gets included by wpa_supplicant
# This approach keeps network names and configuration completely private
# Note: If wifi-networks secret doesn't exist yet, this won't cause errors
# You can still use the old method (networking.wireless.networks in Nix) if needed
}

13
modules/nixos/yubikey.nix Normal file
View File

@@ -0,0 +1,13 @@
# Module: YubiKey Authentication
# Description: Enables YubiKey-based PAM auth for login and sudo across systems
{ pkgs, ... }:
{
security.pam.services = {
login.u2fAuth = true;
sudo.u2fAuth = true;
};
services.udev.packages = [ pkgs.yubikey-personalization ];
}

View File

@@ -0,0 +1,54 @@
# Example WiFi Networks Configuration (to be encrypted with sops)
# This file should be encrypted and stored at: ~/.config/secrets/wifi-networks.yaml
#
# Format: wpa_supplicant.conf syntax
# After editing, encrypt with: sops ~/.config/secrets/wifi-networks.yaml
#
# This example shows different network types:
# - WPA-PSK (simple password)
# - WPA-EAP (enterprise, eduroam)
# - Hidden networks
# - Priority settings
# Home WiFi (WPA-PSK)
network={
ssid="My_Home_Network"
psk="my_secure_password_here"
priority=100
}
# Work WiFi (WPA-EAP with TTLS)
network={
ssid="Work_Network"
key_mgmt=WPA-EAP
eap=TTLS
identity="username@company.com"
password="my_work_password"
phase2="auth=PAP"
priority=10
}
# Eduroam (university)
network={
ssid="eduroam"
key_mgmt=WPA-EAP
eap=PEAP
identity="student.id@university.edu"
password="university_password"
priority=5
}
# Mobile hotspot (hidden network)
network={
ssid="MyPhone"
psk="phone_hotspot_password"
scan_ssid=1
priority=50
}
# Public network (open, no password)
network={
ssid="PublicWiFi"
key_mgmt=NONE
priority=1
}

View File

@@ -0,0 +1,16 @@
wifi-networks: ENC[AES256_GCM,data:dl44GBBxdbWbk8loC5aH5RYwL3CwRMwf25VptiRQBNKjWpdY8SBI2mEm3rNPmeXXI/aElcCukr/OJx/uFTK6QfgUYJHz+Hybhu06k0+Iti3RUrWc/yk8OTiqhamMIdxNf3Jz330wTWHx87fCvVFveRti74Ccr0xcvS94Uj/JyCmZVs6Bj7koxnoI2ixsiziNBzK/iCT9t/z0LJWlpmCeaNfdqxnjTKuaCgYDOpe3Ukt/YPL6VTSv4kkMnEKNi+yvlpcjp2QfXXbYMLv6rf59nZcz8Ml7OL2y3DfbFbi2yarr2ZPbYYa5HbvyZm4C19/otspzazl2dXkApmgYg1i49UGla0Y1V0v91nIDbazg10w6T3hcluQvK5UNIPbntb4dq+boy1OzrojrnI8vzdydck7dluMPoAxxaGpCP1vj4+Mgq7v1R4jytrWpJFiRkZQW55UmK7R/BkinkyhTUoHh9a3yOC2KM3oyeR+LnHlzBhcItWqhvozMs/pGmQHU3+OkXvcDf4I2tQYJ5jXoNJsG/jseYsNDhgcatlb/MmuJf2Bjc1lPSGCd8jCyXyz9tZx468boczazsSO5OsPIVL76Z/x4zZj6JFXz9rUTtD8nE1juJO2JWFxMkihrtfvIWxE0+kMrxBUlE8Nw8jeBaa9E69a44SKT3N2q5ZlFZGbRj+2l7Eo7i3T61gmTrUCLZ/nyQOlZcr7T0LnJxvbbJo3GvkiZddA9HMWxRRqX8Ee1QKOvk1ufBhW3CqNtaVWxewE4Fkf/f2ejI2666NYo3fn+voUNPEwYPNobLgvtQZd8AckAiw==,iv:o8zTQ7Z7Ycq/0Q3shVM4hQmBgQp3UIlKkq25lF0Puu8=,tag:Vs84synGs0VBJmCGOcTqlg==,type:str]
sops:
age:
- recipient: age1hhyew9sv8lqqfeza92jkxsdudhsgaef66cxalp06ez2cm9k6aqysc7mlf7
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwdktBTVA2d2dmNkt0Sm9N
QnpTKzhRK3FpRlFZOXR1RElFZkRRdUJhY244Cjl5blh3MFBlZ0RWMnA4Ly84OVVS
Ti9FRUh1WmtOTTAxVFArUjZVdFdpQjQKLS0tIEQvZnZXZWlvd2ZqMjIyTFRaYWxv
NENiek9YeUhXNFhuZkZzRnBIYXdGY2cKpfSlzP7uK6VFl71OYfoHBxAwrKfpJSNT
QQUngSh6VBrWeJIxoMkJ7O+xSgwZnWc0fnrB+OpoRqy5YVctSmHERg==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-03-06T15:09:08Z"
mac: ENC[AES256_GCM,data:IaMzycI+z+icBoTlIdNfQ/wSm4KRVKj4KoDCvXhQivGdScnOiC4a/fKz1pzL7/PNRgjETUmZ0MJhicT0lTS7FJ+dTgjkDAvpXx+24ML8iVoufny7ho6VOMlPPAVkmtbIAgXq6BFTABTHu9/Y/qKGjHAA0MgPUhPn3Ku1pROQTVc=,iv:y6hUJibLuojG4WAGq85e39Qpj3b1kj9GVqzzIoNRq3w=,tag:jv4thwXAJUHciEi2Mn8VcQ==,type:str]
unencrypted_suffix: _unencrypted
version: 3.12.1

16
secrets/zwift.yaml Normal file
View File

@@ -0,0 +1,16 @@
zwift: ENC[AES256_GCM,data:4tgwyldDGDSPqkgJGG/8jOO0Gd9lvj1gallBbylzXOSev3FR8HdQZVVAtmdBv+krrhxyfXZI/IdH9SBkkZbMaH3UrtXqOEtNIFF8iLSU9hFYG1DGC0yRYCg=,iv:h22Ew6slSvT1MD2DzwxkDe88o3FgFQyiWQioANB/uKs=,tag:IbmwhF7TYA/SH8jmPAWZvw==,type:str]
sops:
age:
- recipient: age1hhyew9sv8lqqfeza92jkxsdudhsgaef66cxalp06ez2cm9k6aqysc7mlf7
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjWEhTTnZ0NkVtZXJVTFZQ
cWFGVCtKZmhwMWw3bkZWNzZKbTR0VGVmVFZFCkREdnJ2TTBmaTByZEg4cU92STFZ
Tk9EMUs5YkN1TnFEMlZxR1dsT0kvVmsKLS0tIE9XQlVwTUFyM0FzcnNHTUppdUVt
VjRrejZZUSs0QlQ0TXlIM1FOZU1MZEkK0ZYeL/LWgpMW72pghDlD6kilNgWUgirf
7ZPdbf3Y+vWh+ifYUSIWbsvWtx0w0e1zeI/TuJ6R6dYgTZZTuffBMA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-03-05T12:41:54Z"
mac: ENC[AES256_GCM,data:ifyhtI2m5dCPqxLbA6aRTBBdWgDfIG0LOHF036amyUKbg1xv8ZliEwsVWF+ADuAhZo5IeasdstbzUBF2Fw6yv+/6IvdH0MmX65mJega5XTFXAZRskdZBqOgXNGuKSJ71YUR8nt0EdHfFNuPR53iLmSDKYSJSXza1wA3Hjsku8WE=,iv:uv904RwND4wPRty9tIdYZfAG94H4q6AGqaDh2nOH/TI=,tag:VpCt+LKmuoNCVcNHGeWGeg==,type:str]
unencrypted_suffix: _unencrypted
version: 3.12.1