feat: add iso and readme
This commit is contained in:
172
README.md
Normal file
172
README.md
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# Cloonar Assistant
|
||||||
|
|
||||||
|
This repository contains a NixOS module (`cloonar-assistant`) designed to help configure a home network appliance or router with various integrated services.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* **VLAN-based Network Segmentation:** Creates multiple VLANs (`lan`, `server`, `infrastructure`, `multimedia`, `smart`, `guest`) for network isolation.
|
||||||
|
* **DHCP Server:** Uses Kea DHCP to provide IP addresses for each configured VLAN.
|
||||||
|
* **DNS Resolver:** Configures Unbound DNS for local hostname resolution (integrating with Kea DHCP leases) and secure DNS-over-TLS forwarding for external queries.
|
||||||
|
* **Firewall:** Implements a stateful firewall using `nftables` with granular rules for inter-VLAN traffic, WAN access, and NAT.
|
||||||
|
* **WireGuard VPN:** Sets up a WireGuard VPN server for secure remote access.
|
||||||
|
* **Dynamic DNS:** Includes a client (`updns-client`) to update a specified domain name with the system's current public IP address via `updns.cloonar.com`.
|
||||||
|
* **Home Assistant:** Runs Home Assistant in a systemd container with a MariaDB backend and an Nginx reverse proxy.
|
||||||
|
* **SSL Certificates:** Automatically obtains and renews SSL certificates for the specified domain using ACME (Let's Encrypt).
|
||||||
|
* **ISO Build Utility:** Provides configuration to build a bootable ISO for automated minimal NixOS installation (useful for bootstrapping).
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
* A machine running NixOS where you want to apply this configuration.
|
||||||
|
|
||||||
|
## Configuration (Module Usage)
|
||||||
|
|
||||||
|
The primary way to use `cloonar-assistant` is by importing its module into your own NixOS `configuration.nix`.
|
||||||
|
|
||||||
|
1. **Import the Module:** Fetch the module source using `builtins.fetchTarball` and add it to your `imports`.
|
||||||
|
2. **Configure Options:** Enable and configure the desired features under the `cloonar-assistant` attribute set.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# /etc/nixos/configuration.nix
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
# Fetch the source code for the cloonar-assistant module
|
||||||
|
cloonar-assistant-src = builtins.fetchTarball "https://git.cloonar.com/Cloonar/cloonar-assistant/archive/master.tar.gz";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
# Import the main module
|
||||||
|
"${cloonar-assistant-src}/modules/cloonar-assistant"
|
||||||
|
|
||||||
|
# Include your hardware-configuration.nix and other custom modules
|
||||||
|
./hardware-configuration.nix
|
||||||
|
# ...
|
||||||
|
];
|
||||||
|
|
||||||
|
# --- Configure Cloonar Assistant Options ---
|
||||||
|
cloonar-assistant = {
|
||||||
|
# Required: Define the first two octets for your internal networks
|
||||||
|
networkPrefix = "10.42"; # Example: Results in 10.42.96.0/24, 10.42.97.0/24, etc.
|
||||||
|
|
||||||
|
# Required: Define the domain name for local services and DDNS
|
||||||
|
domain = "home.example.com"; # Example
|
||||||
|
|
||||||
|
# Required: Define the network interface connected to the WAN/Internet
|
||||||
|
firewall.interfaces.wan = "eth0"; # Example
|
||||||
|
|
||||||
|
# Required: Define the network interface for internal VLANs
|
||||||
|
# Set to null if you only have one interface (WAN)
|
||||||
|
firewall.interfaces.internal = "eth1"; # Example
|
||||||
|
|
||||||
|
# Enable VPN Server
|
||||||
|
vpn.enable = true;
|
||||||
|
vpn.privateKeyFile = "/path/to/your/wireguard_private_key"; # Store securely!
|
||||||
|
vpn.clients = [
|
||||||
|
{ name = "myphone"; publicKey = "..."; allowedIPs = [ "${config.cloonar-assistant.networkPrefix}.98.2/32" ]; }
|
||||||
|
# ... more clients
|
||||||
|
];
|
||||||
|
|
||||||
|
# Enable Dynamic DNS Updates
|
||||||
|
updns.enable = true;
|
||||||
|
updns.key = "your-updns-key"; # Key provided by updns-client.cloonar.com
|
||||||
|
updns.secretFile = "/path/to/your/updns_secret"; # Store securely!
|
||||||
|
|
||||||
|
# Enable setup mode (allows WAN access for initial setup - disable for production)
|
||||||
|
setup = false;
|
||||||
|
|
||||||
|
# ... other options can be configured as needed.
|
||||||
|
};
|
||||||
|
|
||||||
|
# --- Other System Configuration ---
|
||||||
|
networking.hostName = "myrouter"; # Example hostname
|
||||||
|
|
||||||
|
# Ensure necessary packages for fetching are available if not using flakes
|
||||||
|
environment.systemPackages = [ pkgs.nix ];
|
||||||
|
|
||||||
|
system.stateVersion = "23.11"; # Set to your NixOS version
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Module Options
|
||||||
|
|
||||||
|
The main configuration options are available under the `cloonar-assistant` attribute set in your `configuration.nix`. Refer to `modules/cloonar-assistant/default.nix` within the fetched source for a detailed definition of all available options and their defaults. Key areas include:
|
||||||
|
|
||||||
|
* `cloonar-assistant.networkPrefix`
|
||||||
|
* `cloonar-assistant.domain`
|
||||||
|
* `cloonar-assistant.firewall.*` (including `interfaces.wan`, `interfaces.internal`)
|
||||||
|
* `cloonar-assistant.vpn.*`
|
||||||
|
* `cloonar-assistant.updns.*`
|
||||||
|
* `cloonar-assistant.setup`
|
||||||
|
|
||||||
|
## ISO Build Utility (Optional)
|
||||||
|
|
||||||
|
This repository also includes configuration in the `iso/` directory to build a bootable `.iso` file.
|
||||||
|
|
||||||
|
**Purpose:** This ISO performs a fully automated, minimal NixOS installation on a target machine. It partitions the disk (creating a boot partition and a LUKS-encrypted root partition using `/dev/zero` as the keyfile - **WARNING: This is insecure and intended only for bootstrapping**), formats filesystems, and installs a base NixOS system defined in `iso/configuration.nix`. It does **not** install the `cloonar-assistant` configuration itself. It's primarily useful for quickly bootstrapping a bare-metal machine before applying your custom NixOS configuration (which imports the `cloonar-assistant` module).
|
||||||
|
|
||||||
|
**Build Command (Non-Flake):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix-build ./iso/default.nix
|
||||||
|
```
|
||||||
|
|
||||||
|
This command should be run from the root of this repository checkout. The resulting ISO will be in the `result/` directory.
|
||||||
|
|
||||||
|
**ISO Installation Flow:**
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
subgraph "ISO Build & Install Utility"
|
||||||
|
A["Run nix-build command"] --> B("Generates ISO file");
|
||||||
|
B --> C{"Boot target machine from ISO"};
|
||||||
|
C --> D["Automated Install Script runs"];
|
||||||
|
D --> E{"Partitions Disk (BOOT + LUKS)"};
|
||||||
|
E --> F{"Formats Filesystems (FAT32 + EXT4)"};
|
||||||
|
F --> G{"Mounts Filesystems"};
|
||||||
|
G --> H["Installs base NixOS using iso/configuration.nix"];
|
||||||
|
H --> I("System reboots into minimal NixOS");
|
||||||
|
I --> J{"User creates custom config<br>importing cloonar-assistant module"};
|
||||||
|
J --> K["Run nixos-rebuild switch"];
|
||||||
|
K --> L("System running full configuration");
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Network Architecture
|
||||||
|
|
||||||
|
The module sets up the following logical network structure when the firewall and VLANs are enabled:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
subgraph "Network Architecture"
|
||||||
|
Internet -- WAN --> R("Router/Firewall");
|
||||||
|
subgraph "Internal Network (VLANs on configured internal interface)"
|
||||||
|
R -- "VLAN 96" --> LAN["LAN Subnet<br>${config.cloonar-assistant.networkPrefix}.96.0/24"];
|
||||||
|
R -- "VLAN 97" --> SRV["Server Subnet<br>${config.cloonar-assistant.networkPrefix}.97.0/24"];
|
||||||
|
R -- "VLAN 101" --> INF["Infrastructure Subnet<br>${config.cloonar-assistant.networkPrefix}.101.0/24"];
|
||||||
|
R -- "VLAN 99" --> MM["Multimedia Subnet<br>${config.cloonar-assistant.networkPrefix}.99.0/24"];
|
||||||
|
R -- "VLAN 100" --> SMT["Smart Home Subnet<br>${config.cloonar-assistant.networkPrefix}.100.0/24"];
|
||||||
|
R -- "VLAN 254" --> GST["Guest Subnet<br>${config.cloonar-assistant.networkPrefix}.254.0/24"];
|
||||||
|
end
|
||||||
|
subgraph "VPN"
|
||||||
|
VPNClient -- "UDP 51820" --> R;
|
||||||
|
R -- "wg_cloonar" --> VPNNet["VPN Subnet<br>${config.cloonar-assistant.networkPrefix}.98.0/24"];
|
||||||
|
end
|
||||||
|
subgraph "Services on Router"
|
||||||
|
R --> DHCP("Kea DHCP");
|
||||||
|
R --> DNS("Unbound DNS");
|
||||||
|
R --> Firewall("NFTables");
|
||||||
|
R --> DynDNS("UpDNS Client");
|
||||||
|
R --> HAProxy("Nginx Proxy");
|
||||||
|
HAProxy --> HACont[("Container: Home Assistant")];
|
||||||
|
end
|
||||||
|
SRV --> HACont;
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Module Overview
|
||||||
|
|
||||||
|
* `modules/cloonar-assistant/`: Contains the main NixOS module definition (`default.nix`) and imports submodules.
|
||||||
|
* `modules/cloonar-assistant/networking/`: Configures network interfaces, VLANs, DHCP (Kea), DNS (Unbound), firewall (`nftables`), and WireGuard.
|
||||||
|
* `modules/cloonar-assistant/updns/`: Configures the dynamic DNS client service.
|
||||||
|
* `modules/cloonar-assistant/home-assistant/`: Configures the Home Assistant systemd container, MariaDB database, Nginx reverse proxy, and ACME SSL certificates.
|
||||||
|
* `modules/cloonar-assistant/multiroom-audio/`: Currently unused, planned for future multiroom audio features.
|
||||||
|
* `iso/`: Contains configuration files (`default.nix`, `configuration.nix`) for building the optional automated installation ISO.
|
||||||
52
iso/configuration.nix
Normal file
52
iso/configuration.nix
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{ config, lib, pkgs, ... }: {
|
||||||
|
imports = [
|
||||||
|
<nixpkgs/nixos/modules/profiles/all-hardware.nix>
|
||||||
|
<nixpkgs/nixos/modules/profiles/base.nix>
|
||||||
|
];
|
||||||
|
|
||||||
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
|
||||||
|
zramSwap.enable = true;
|
||||||
|
|
||||||
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
|
||||||
|
networking.hostName = "install";
|
||||||
|
|
||||||
|
services.openssh.enable = true;
|
||||||
|
services.openssh.settings.PermitRootLogin = "yes";
|
||||||
|
|
||||||
|
users.mutableUsers = false;
|
||||||
|
users.users.root = {
|
||||||
|
# Password is "linux"
|
||||||
|
hashedPassword = lib.mkForce "$6$7IKExnDde920x.YH$ggegnnKJYdmg1Wt33fxuPpM.MmIaX32LXVyjL8ed7ohT385lKotFGzRpitncQ3pd9Lci1QCFGRn2tVJGxkFAm0";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.avahi = {
|
||||||
|
enable = true;
|
||||||
|
ipv4 = true;
|
||||||
|
ipv6 = true;
|
||||||
|
nssmdns = true;
|
||||||
|
publish = { enable = true; domain = true; addresses = true; };
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
coreutils
|
||||||
|
curl
|
||||||
|
file
|
||||||
|
git
|
||||||
|
htop
|
||||||
|
lsof
|
||||||
|
nano
|
||||||
|
openssl
|
||||||
|
pciutils
|
||||||
|
pv
|
||||||
|
tmux
|
||||||
|
tree
|
||||||
|
unar
|
||||||
|
vim_configurable
|
||||||
|
wget
|
||||||
|
zip
|
||||||
|
];
|
||||||
|
|
||||||
|
system.stateVersion = "23.05"; # Did you read the comment?
|
||||||
|
}
|
||||||
86
iso/default.nix
Normal file
86
iso/default.nix
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
system ? "x86_64-linux",
|
||||||
|
}:
|
||||||
|
(import <nixpkgs/nixos/lib/eval-config.nix> {
|
||||||
|
inherit system;
|
||||||
|
modules = [
|
||||||
|
<nixpkgs/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix>
|
||||||
|
./configuration.nix
|
||||||
|
({ config, pkgs, lib, ... }: {
|
||||||
|
systemd.services.install = {
|
||||||
|
description = "Bootstrap a NixOS installation";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "network.target" "polkit.service" ];
|
||||||
|
path = [ "/run/current-system/sw/" ];
|
||||||
|
script = with pkgs; ''
|
||||||
|
echo 'journalctl -fb -n100 -uinstall' >>~nixos/.bash_history
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
wait-for() {
|
||||||
|
for _ in seq 10; do
|
||||||
|
if $@; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
dev=/dev/sda
|
||||||
|
[ -b /dev/nvme0n1 ] && dev=/dev/nvme0n1
|
||||||
|
[ -b /dev/vda ] && dev=/dev/vda
|
||||||
|
|
||||||
|
${utillinux}/bin/sfdisk --wipe=always $dev <<-END
|
||||||
|
label: gpt
|
||||||
|
|
||||||
|
name=BOOT, size=512MiB, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B
|
||||||
|
name=NIXOS
|
||||||
|
END
|
||||||
|
|
||||||
|
sync
|
||||||
|
wait-for [ -b /dev/disk/by-partlabel/BOOT ]
|
||||||
|
|
||||||
|
mkfs.fat -F 32 -n boot /dev/disk/by-partlabel/BOOT
|
||||||
|
wait-for mkfs.fat -F 32 -n boot /dev/disk/by-partlabel/BOOT
|
||||||
|
|
||||||
|
wait-for [ -b /dev/disk/by-partlabel/NIXOS ]
|
||||||
|
${cryptsetup}/bin/cryptsetup luksFormat --type=luks2 --label=root /dev/disk/by-partlabel/NIXOS /dev/zero --keyfile-size=1
|
||||||
|
${cryptsetup}/bin/cryptsetup luksOpen /dev/disk/by-partlabel/NIXOS root --key-file=/dev/zero --keyfile-size=1
|
||||||
|
mkfs.ext4 -L nixos /dev/mapper/root
|
||||||
|
|
||||||
|
sync
|
||||||
|
mount /dev/mapper/root /mnt
|
||||||
|
|
||||||
|
mkdir /mnt/boot
|
||||||
|
wait-for mount /dev/disk/by-label/boot /mnt/boot
|
||||||
|
|
||||||
|
install -D ${./configuration.nix} /mnt/etc/nixos/configuration.nix
|
||||||
|
install -D ${./hardware-configuration.nix} /mnt/etc/nixos/hardware-configuration.nix
|
||||||
|
|
||||||
|
sed -i -E 's/(\w*)#installer-only /\1/' /mnt/etc/nixos/*
|
||||||
|
|
||||||
|
${config.system.build.nixos-install}/bin/nixos-install \
|
||||||
|
--system ${(import <nixpkgs/nixos/lib/eval-config.nix> {
|
||||||
|
inherit system;
|
||||||
|
modules = [
|
||||||
|
./configuration.nix
|
||||||
|
./hardware-configuration.nix
|
||||||
|
];
|
||||||
|
}).config.system.build.toplevel} \
|
||||||
|
--no-root-passwd \
|
||||||
|
--cores 0
|
||||||
|
|
||||||
|
echo 'Shutting off in 1min'
|
||||||
|
${systemd}/bin/shutdown +1
|
||||||
|
'';
|
||||||
|
environment = config.nix.envVars // {
|
||||||
|
inherit (config.environment.sessionVariables) NIX_PATH;
|
||||||
|
HOME = "/root";
|
||||||
|
};
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}).config.system.build.isoImage
|
||||||
26
iso/hardware-configuration.nix
Normal file
26
iso/hardware-configuration.nix
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{ config, pkgs, ... }: {
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = "/dev/disk/by-label/boot";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.initrd.luks.devices.root = {
|
||||||
|
device = "/dev/disk/by-label/root";
|
||||||
|
|
||||||
|
# WARNING: Leaks some metadata, see cryptsetup man page for --allow-discards.
|
||||||
|
allowDiscards = true;
|
||||||
|
|
||||||
|
# Set your own key with:
|
||||||
|
# cryptsetup luksChangeKey /dev/disk/by-label/root --key-file=/dev/zero --keyfile-size=1
|
||||||
|
# You can then delete the rest of this block.
|
||||||
|
keyFile = "/dev/zero";
|
||||||
|
keyFileSize = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/mapper/root";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user