Modularizing system configuration #3

Merged
wymiller merged 10 commits from modular into master 2024-12-27 00:27:25 -06:00
15 changed files with 848 additions and 45 deletions
Showing only changes of commit adabefd821 - Show all commits

180
modules/apps/gaming.nix Normal file
View File

@ -0,0 +1,180 @@
{
config,
lib,
pkgs,
...
}: let
cfg = config.gaming;
in {
options.gaming = {
steam = {
enable = lib.mkEnableOption "Steam gaming platform";
firewall = {
remotePlay = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Open firewall ports for Steam Remote Play";
};
localNetworkGameTransfers = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Open firewall ports for local network game transfers";
};
};
};
gamemode = {
enable = lib.mkEnableOption "Gamemode performance optimization";
config = lib.mkOption {
type = lib.types.attrs;
default = {};
description = "Custom Gamemode configuration options";
};
};
gamescope = {
enable = lib.mkEnableOption "Gamescope gaming compositor";
settings = {
resolution = lib.mkOption {
type = lib.types.nullOr (lib.types.submodule {
options = {
width = lib.mkOption {
type = lib.types.int;
description = "Gamescope rendering width";
};
height = lib.mkOption {
type = lib.types.int;
description = "Gamescope rendering height";
};
};
});
default = null;
description = "Gamescope rendering resolution";
};
refreshRate = lib.mkOption {
type = lib.types.nullOr lib.types.int;
default = null;
description = "Gamescope rendering refresh rate";
};
};
};
lutris = {
enable = lib.mkEnableOption "Lutris game manager and launcher";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.lutris;
description = "Lutris package to use (allows for custom or alternative packages)";
};
wine = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Enable Wine support for Lutris";
};
package = lib.mkOption {
type = lib.types.package;
default = pkgs.wineWow;
description = "Wine package to use with Lutris";
};
};
# Compatibility layers for Lutris
compatibility = {
protonSupport = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Enable Proton-like compatibility layers for Lutris";
};
extraTools = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [];
description = "Additional compatibility tools for Lutris";
};
};
# Additional system packages for Lutris
extraPackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [];
description = "Additional packages to install alongside Lutris";
};
};
minecraft = lib.mkOption {
enable = lib.mkEnableOption "Minecraft in the form of PrismLauncher, a tool for launching Minecraft";
};
ffxiv = lib.mkOption {
enable = lib.mkEnableOption "Final Fantasy XIV and it's accompanied (unofficial) launcher";
};
};
config = {
programs.steam = lib.mkIf cfg.steam.enable {
enable = true;
remotePlay.openFirewall = cfg.steam.firewall.remotePlay;
localNetworkGameTransfers.openFirewall = cfg.steam.firewall.localNetworkGameTransfers;
};
programs.gamemode = lib.mkIf cfg.gamemode.enable {
enable = true;
settings = cfg.gamemode.config;
};
programs.gamescope = lib.mkIf cfg.gamescope.enable {
enable = true;
# Apply custom resolution if specified
args =
lib.optional (cfg.gamescope.settings.resolution != null) [
"-w"
(toString cfg.gamescope.settings.resolution.width)
"-h"
(toString cfg.gamescope.settings.resolution.height)
]
++ lib.optional (cfg.gamescope.settings.refreshRate != null) [
"-r"
(toString cfg.gamescope.settings.refreshRate)
];
};
environment.systemPackages =
lib.mkIf cfg.lutris.enable (
# Base Lutris package
[cfg.lutris.package]
++
# Wine packages if enabled
(lib.optionals cfg.lutris.wine.enable [
cfg.lutris.wine.package
pkgs.winetricks
])
++
# Proton and compatibility tools
(lib.optionals cfg.lutris.compatibility.protonSupport [
pkgs.proton-ge-custom
])
++
# Extra compatibility tools
cfg.lutris.compatibility.extraTools
++
# User-specified extra packages
cfg.lutris.extraPackages
)
lib.mkIf
cfg.minecraft.enable [pkgs.prismlauncher]
lib.mkIf
cfg.ffxiv.enable [pkgs.xivlauncher];
# Wine configuration
programs.wine = lib.mkIf (cfg.lutris.enable && cfg.lutris.wine.enable) {
enable = true;
package = cfg.lutris.wine.package;
};
};
}

0
modules/apps/xdg.nix Normal file
View File

View File

@ -5,16 +5,8 @@
hostname,
...
} @ args: {
# Set up networking configuration
networking.hostName = hostname;
# networking.computerName = hostname;
# networking.firewall.enable = true; # VERY important, do not touch
# networking.firewall.allowedTCPPorts = [];
# networking.firewall.allowedUDPPorts = [];
# networking.networkmanager.enable = pkgs.stdenv.isLinux; # Linux tool for managing network connections
# system.defaults.smb.NetBIOSName = hostname;
# Set up user accounts
# Don't forget to set a password with passwd!
users.users."${userName}" = lib.mkMerge [
{

View File

@ -7,3 +7,7 @@ Licensed by the Mozilla Public License v2
## Synopsis
This directory is where the machine-specific configuration files for hostname `cloud` live, my primary desktop. These files get called by the root `flake.nix` file.
### `TODO` list
- Migrate to (disko)[https://github.com/nix-community/disko]

View File

@ -3,9 +3,12 @@
pkgs,
userName,
...
}: {
}: let
timeZone = null;
in {
imports = [
../../apps/flatpak.nix
../../pwrMgmt
../../sound/pipewire.nix
../../sound/shairport.nix
../../virtualization/podman.nix
@ -24,7 +27,7 @@
hardware.bluetooth.enable = true;
# Set your timezone
time.timeZone = "America/Detroit";
time.timeZone = timeZone ? "America/Detroit";
# Enable touchpad
services.libinput.enable = true;
@ -35,11 +38,6 @@
neovim
git
wireguard-tools
buildah
podman-tui
podman-compose
podman-desktop
toolbox
grim
slurp
playerctl
@ -83,25 +81,63 @@
# Enable Polkit
security.polkit.enable = true;
# Enable power management
powerManagement = {
enable = true;
powertop.enable = false; # TODO: to be enabled on laptops
cpuFreqGovernor = "performace";
# Gaming module (see ../../apps/gaming.nix)
customGaming = {
steam = {
enable = true;
firewall = {
remotePlay = true;
localNetworkGameTransfers = true;
};
};
gamemode.enable = true;
gamescope.enable = true;
lutris = {
enable = true;
wine = {
enable = true;
package = pkgs.wine;
};
compatibility = {
protonSupport = true;
extraTools = with pkgs; [
proton-ge-custom
];
};
extraPackages = with pkgs; [
gamemode
mangohud
];
};
minecraft.enable = true;
};
# Enable Steam and open various firewall ports when applicable
programs.steam = {
# Power management (see ../../pwrMgmt/default.nix)
customPowerManagement = {
enable = true;
remotePlay.openFirewall = true;
localNetworkGameTransfers.openFirewall = true;
cpuFreqGovernor = "performance";
powertop.enable = false;
};
# Enable gamemode (gamemode, gamemoded, gamemoderun) when needed
programs.gamemode.enable = true;
podman = {
podman = {
enable = true;
extraPackages = with pkgs; [
docker-credential-helpers
toolbox
cosign
crane
podman-tui
podman-desktop
];
};
};
# Enable gamescope (compositor) when needed
programs.gamescope.enable = true;
customNetworking = {
firewall.enable = true;
networkManager.enable = true;
};
# Enable dconf
programs.dconf.enable = true;
@ -135,17 +171,5 @@
networking.firewall.allowedUDPPorts = [];
networking.networkmanager.enable = true; # Linux tool for managing network connections
# Enable Podman (OCI containers)
virtualisation.podman = {
enable = true;
dockerSocket.enable = true;
defaultNetwork.settings.dns_enabled = true;
};
# users.users."${userName}" = {
# group = "${userName}";
# isNormalUser = true;
# };
system.stateVersion = "24.05";
}

View File

@ -167,6 +167,17 @@
system.stateVersion = 5;
containers.podman = {
enable = true;
dockerCompat = false;
extraPackages = with pkgs; [
podman-tui
docker-credential-helpers
cosign
crane
];
};
# Set your time zone.
time.timeZone = "America/Detroit";
}

View File

@ -0,0 +1,90 @@
# Network and networking modules
This directory houses all network, firewall, DHCP, DNS, and all other related networking enablement.
## `core.nix`
This is where the firewall and NetworkManager live. For the firewall, you have pre-defined options that will open ports for you by enabling some network service.
For example:
```nix
tcpPorts.web.enable = true;
udpPorts.dns.enable = true;
```
Here's a more featureful example of how you would enable a firewall and set up NetworkManager:
```nix
customNetworking = {
firewall = {
enable = true;
# Open web service ports
tcpPorts.web.enable = true;
# Custom TCP ports
tcpPorts.allowedPorts = [ 8080 22 ];
# Custom UDP ports
udpPorts.allowedPorts = [ 5000 ];
};
networkManager = {
enable = true;
extraPlugins = with pkgs; [
# Additional NetworkManager plugins
networkmanager-openvpn
networkmanager-openconnect
];
};
};
```
As shown above, you'll have to open ports for services you would want to access remotely.
## DNS
There are two options here: BIND9 (or simply Bind) or Technitium DNS server. Enabling both DNS servers will throw an error and your configuration will not build.
You'll have to import `./dns.nix` for the services to be enabled.
Here's an example of what configuration might look like:
```nix
dns.bind = {
enable = true;
settings = {
interfaces = [ "127.0.0.1" "192.168.100.100" ];
zones = [
{
name = "example.com";
type = "master";
file = "/etc/named/zones/example.com.zone";
}
];
extraConfig = ''
// Additional BIND configuration
options {
directory "/var/named";
recursion yes;
}
'';
}
};
```
_or_
```nix
dns.technitium = {
enable = true;
settings = {
address = "192.168.100.0";
port = 5380;
extraOptions = {
LOG_LEVEL = "info";
};
}
};
```

145
modules/networking/core.nix Normal file
View File

@ -0,0 +1,145 @@
{
config,
lib,
pkgs,
...
}: let
cfg = config.customNetworking;
in {
options.customNetworking = {
# Firewall Configuration
firewall = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Enable system firewall";
};
tcpPorts = {
# Predefined, default common service ports
ssh = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Open SSH service port (22)";
};
};
web = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Open common web service ports (80, 443)";
};
};
smtp = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Open SMTP service ports (25, 465, 587)";
};
};
imap = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Open IMAP service ports (143, 993)";
};
};
mysql = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Open MySQL service port (3306)";
};
};
mssql = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Open Microsoft SQL Server service port (1433)";
};
};
postgres = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Open Postgres service port (5432)";
};
};
allowedPorts = lib.mkOption {
type = lib.types.listOf lib.types.port;
default = [];
description = "List of custom TCP ports to open";
};
};
udpPorts = {
dns = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Open DNS service port (53)";
};
};
ntp = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Open NTP service port (123)";
};
};
allowedPorts = lib.mkOption {
type = lib.types.listOf lib.types.port;
default = [];
description = "List of custom UDP ports to open";
};
};
};
networkManager = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Enable NetworkManager for network connection management";
};
extraPlugins = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [];
description = "Additional NetworkManager plugins to install";
};
};
};
config = {
networking.firewall = {
enable = cfg.firewall.enable;
allowedTCPPorts =
(
lib.optionals
cfg.firewall.tcpPorts.ssh.enable [22]
cfg.firewall.tcpPorts.web.enable [80 443]
cfg.firewall.tcpPorts.smtp.enable [25 465 587]
cfg.firewall.tcpPorts.imap.enable [143 993]
cfg.firewall.tcpPorts.mysql.enable [3306]
cfg.firewall.tcpPorts.mssql.enable [1433]
cfg.firewall.tcpPorts.postgres.enable [5432]
)
++ cfg.firewall.tcpPorts.allowedPorts;
allowedUDPPorts =
(
lib.optionals
cfg.firewall.udpPorts.dns.enable [53]
cfg.firewall.udpPorts.ntp.enable [123]
)
++ cfg.firewall.udpPorts.allowedPorts;
};
networking.networkmanager = {
enable = cfg.networkManager.enable;
packages = cfg.networkManager.extraPlugins;
};
};
}

133
modules/networking/dns.nix Normal file
View File

@ -0,0 +1,133 @@
{
config,
lib,
pkgs,
...
}: let
cfg = config.dns;
in {
options.dns = {
bind = {
enable = lib.mkEnableOption "BIND DNS server";
settings = {
interfaces = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = ["127.0.0.1"];
description = "Network interfaces BIND should listen on";
};
zones = lib.mkOption {
type = lib.types.listOf (lib.types.submodule {
options = {
name = lib.mkOption {
type = lib.types.str;
description = "Name of the DNS zone";
};
type = lib.mkOption {
type = lib.types.enum ["master" "slave"];
default = "master";
description = "Type of DNS zone";
};
file = lib.mkOption {
type = lib.types.str;
default = "";
description = "Path to zone file";
};
};
});
default = [];
description = "DNS zones to configure";
};
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
description = "Additional BIND configuration options";
};
};
};
technitium = {
enable = lib.mkEnableOption "Technitium DNS server";
settings = {
address = lib.mkOption {
type = lib.types.str;
default = "0.0.0.0";
description = "IP address Technitium should listen on";
};
port = lib.mkOption {
type = lib.types.port;
default = 5380;
description = "Port for Technitium DNS server";
};
extraOptions = lib.mkOption {
type = lib.types.attrs;
default = {};
description = "Additional Technitium configuration options";
};
};
};
};
# Validate that only one DNS server is enabled
imports = [
(lib.mkIf (cfg.bind.enable && cfg.technitium.enable) (throw "Only one DNS server can be enabled at a time"))
];
# Implementation of the configuration
config = lib.mkMerge [
# BIND DNS Server Configuration
(lib.mkIf cfg.bind.enable {
services.named = {
enable = true;
interfaces = cfg.bind.settings.interfaces;
zones =
map (zone: {
name = zone.name;
type = zone.type;
file = zone.file;
})
cfg.bind.settings.zones;
extraConfig = cfg.bind.settings.extraConfig;
};
networking.firewall = {
allowedTCPPorts = [53];
allowedUDPPorts = [53];
};
environment.systemPackages = [pkgs.bind];
})
# Technitium DNS Server Configuration
(lib.mkIf cfg.technitium.enable {
# Create a systemd service for Technitium
systemd.services.technitium-dns = {
description = "Technitium DNS Server";
wantedBy = ["multi-user.target"];
serviceConfig = {
ExecStart = "${pkgs.technitium}/bin/dns-server-start.sh";
Restart = "on-failure";
};
# Environment configuration
environment =
{
DNS_LISTEN_ADDRESS = cfg.technitium.settings.address;
DNS_LISTEN_PORT = toString cfg.technitium.settings.port;
}
// lib.mapAttrs' (
name: value:
lib.nameValuePair "DNS_${lib.toUpper name}" (toString value)
)
cfg.technitium.settings.extraOptions;
};
networking.firewall = {
allowedTCPPorts = [cfg.technitium.settings.port];
allowedUDPPorts = [cfg.technitium.settings.port];
};
environment.systemPackages = [pkgs.technitium];
})
];
}

48
modules/pwrMgmt/README.md Normal file
View File

@ -0,0 +1,48 @@
# Power management modules
This directory houses my own custom defined power management settings. These are set in the machine-specific configurations (typically).
## Examples
Given that this configuration is in the `machine/<hostname>` directory (where hostname is the name of the computer your configuring):
### Desktop configuration
```nix
imports = [
../../pwrMgmt
# other configuration files here...
];
customPowerManagement = {
enable = true;
cpuFreqGovernor = "performance";
powertop.enable = false;
};
```
### Laptop configuration
```nix
imports = [
../../pwrMgmt
# other configuration files here...
];
customPowerManagement = {
enable = true;
cpuFreqGovernor = "powersave";
powertop = {
enable = true;
autotuneOnBoot = true;
};
battery = {
enable = true;
startChargeThreshold = 40;
stopChargeThreshold = 75;
};
};
```
Remember, these are just examples. Please suit these examples to fit your specific hardware.

View File

@ -0,0 +1,73 @@
{
config,
lib,
...
}: let
# Define a more flexible power management module
cfg = config.pwrMgnt;
in {
# Define options for customizable power management
options.pwrMgnt = {
enable = lib.mkEnableOption "Custom power management configuration";
cpuFreqGovernor = lib.mkOption {
type = lib.types.enum [
"performance"
"powersave"
"ondemand"
"conservative"
];
default = "performance";
description = "CPU frequency scaling governor to use";
};
# PowerTop Configuration
powertop = {
enable = lib.mkEnableOption "PowerTop power management tool";
autotuneOnBoot = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Automatically tune power settings on boot";
};
};
# Battery-specific settings (for laptops)
battery = {
enable = lib.mkEnableOption "Battery-specific power management";
startChargeThreshold = lib.mkOption {
type = lib.types.int;
default = 20;
description = "Percentage at which to start charging";
};
stopChargeThreshold = lib.mkOption {
type = lib.types.int;
default = 80;
description = "Percentage at which to stop charging";
};
};
};
config = lib.mkIf cfg.enable {
powerManagement = {
enable = true;
cpuFreqGovernor = cfg.cpuFreqGovernor;
};
services.powertop.enable = cfg.powertop.enable;
systemd.services.battery-charge-threshold = lib.mkIf cfg.battery.enable {
description = "Set battery charge thresholds";
wantedBy = ["multi-user.target"];
script = ''
if [ -f /sys/class/power_supply/BAT0/charge_start_threshold ]; then
echo ${toString cfg.battery.startChargeThreshold} > /sys/class/power_supply/BAT0/charge_start_threshold
fi
if [ -f /sys/class/power_supply/BAT0/charge_stop_threshold ]; then
echo ${toString cfg.battery.stopChargeThreshold} > /sys/class/power_supply/BAT0/charge_stop_threshold
fi
'';
};
};
}

19
modules/sound/README.md Normal file
View File

@ -0,0 +1,19 @@
# Sound and audio modules
This directory houses all sound and audio modules for a given system.
## Pipewire
Pipewire is the new kid on the block, and frankly, this new kid cleans the streets. With Pulseaudio and ALSA compatibility, this is basically the _defacto_ audio solution for every Linux workstation.
Although, for some use cases, expect me to write a Pulseaudio or an ALSA module here soon :P
All that's needed to get this working to import the `./pipewire.nix` into your machine's configuration.
## Shairport
This is a program where your computer is enabled with AirPlay! How cool is that??
All that's needed to get this working to import the `./shairport.nix` into your machine's configuration.
Note that this _only_ works with Pipewire.

View File

@ -0,0 +1,51 @@
# Virtualization modules
This directory houses all virtualization and container related enablement. Cloud native anyone??
## Hardware virtualization
This is for running virtual machines on the bare metal.
All that's needed to get this working to import the `./hardware.nix` into your machine's configuration.
## Docker (OCI containers)
This is for running the Docker runtime (rootful or rootless, rootful by default) to run OCI containers.
All that's needed to get this working to import the `./docker.nix` into your machine's configuration.
Note: I don't use Docker too much as I use Podman for development. I'd check the Podman documentation.
## Podman/Buildah (OCI containers)
This is for running the Podman runtime (rootless) to run OCI containers.
You will need to import `./podman.nix` into your machine configuration. Additionally, there's some added configuration to suit your needs.
Example:
```nix
podman = {
podman = {
enable = true;
extraPackages = with pkgs; [
docker-credential-helpers
toolbox
cosign
crane
podman-tui
podman-desktop
];
};
};
```
To get a full, comprehensive list of what you can do with the podman module, please check out (podman.nix)[./podman.nix]!
## Kubernetes
Coming soon!
## LXC/LXD
I don't have anything in the way of a nix configuration for LXC/LXD as I don't have a use-case for them. Come back later!

View File

@ -2,5 +2,6 @@
virtualisation.docker = {
enable = true;
enableOnBoot = true;
rootless = false;
};
}

View File

@ -1,7 +1,39 @@
{...}: {
virtualisation.podman = {
enable = true;
dockerSocket.enable = true;
defaultNetwork.settings.dns_enabled = true;
{
config,
lib,
pkgs,
...
}: let
cfg = config.containers;
in {
options.containers = {
podman = {
enable = lib.mkEnableOption "Podman container runtime";
dockerCompat = lib.mkEnableOption "Enable Docker compatibility";
extraPackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [];
description = "Additional packages to install when Podman is enabled";
};
};
};
config = lib.mkIf cfg.podman.enable {
virtualisation.podman = {
enable = true;
dockerCompat = cfg.podman.dockerCompat;
enableOnBoot = true;
defaultNetwork.settings.dns_enabled = true;
};
environment.systemPackages =
[
pkgs.podman-compose
pkgs.buildah
pkgs.skopeo
pkgs.dive
pkgs.container-diff
]
++ cfg.podman.extraPackages;
};
}