# NixOS Homelab Mini PC
Jan 5, 2025
![[f31b95a50a6f8e7e7e44eab90d9700c314d8f157a3dad29d809f7788ca93e27a58eb06b65ed80c021afc9a1dbe103d4bfd55b01e55c8b650f944ab930b651905.png|300]]
Setting up a GMKtec NucBox G5 with NixOS for a home lab environment.
## Hardware Overview
The NucBox G5 features Intel's N97 processor, offering an excellent balance of performance and efficiency for homelab use.
### Core Components
- Intel N97 (12th Gen Alder Lake): 4C/4T up to 3.6GHz
- 12GB LPDDR5 @ 4800MT/s
- 512GB M.2 SATA SSD
- Intel UHD Graphics (24 EUs @ 1.2GHz)
### Connectivity
- 2x USB 3.2 Gen 2 Type-A
- USB-C (power + display)
- HDMI 2.0 (4K@60Hz)
- Gigabit Ethernet
- WiFi 6 (Intel AX201) + BT 5.2
### Physical Specs
- Size: 72 x 72 x 44.5mm
- Weight: 168g
- VESA mountable
## Performance
### N97 vs N100
The N97 outperforms the N100 with:
- 1.2GHz vs 750MHz GPU clock
- 12W vs 6W TDP
- Better sustained performance
### Power & Thermal
- Power: 12V 3A (36W) Type-C
- TDP: 8-15W (12W optimal)
- Fan: 1800-5000 RPM
- Load temps: ~80°C
- Noise: Minimal to noticeable, but not disruptive
## Installation
### BIOS Setup
```
Power & Performance:
- Power Limit: 15W
- GT frequency: 1200MHz
- Load Optimized Defaults (F3)
Boot:
- Secure Boot: Disabled
- Boot Mode: UEFI
```
### NixOS Installation
1. Create bootable USB:
```bash
dd if=nix.iso of=/dev/sdX bs=4M status=progress
```
2. Boot sequence:
- Power on
- F7 within 3s
- Select USB
3. Partition disk:
```bash
sudo -s
fdisk /dev/sda
# Create GPT layout
g
# Boot partition (500MB)
n, 1, {ENTER}, +500M, t, 1
# Swap (4GB)
n, 2, {ENTER}, +4096M, t, 19
# Root partition
n, 3, {ENTER}, {ENTER}
w
```
4. Format partitions:
```bash
mkfs.fat /dev/sda1
mkswap /dev/sda2 && swapon /dev/sda2
mkfs.ext4 /dev/sda3
```
5. Mount and generate config:
```bash
mount /dev/sda3 /mnt
mkdir /mnt/boot
mount /dev/sda1 /mnt/boot
nixos-generate-config --root /mnt/
```
6. Configure wireless networking:
```nix
networking = {
networkmanager.enable = true;
wireless.enable = false;
wireless.networks."YOUR_WIFI_NAME" = {
psk = "YOUR_WIFI_PASSWORD";
};
interfaces.wlp1s0 = {
useDHCP = false;
ipv4.addresses = [{
address = "192.168.1.100";
prefixLength = 24;
}];
};
defaultGateway = "192.168.1.1";
nameservers = [ "8.8.8.8" "8.8.4.4" ];
};
```
7. Install and configure:
```bash
nixos-install
# Set root password when prompted
reboot
# After reboot
chmod -R 700 /boot
nmcli device wifi connect "YOUR_WIFI_NAME" password "YOUR_PASSWORD"
```
8. Basic system config:
```nix
networking.hostName = "hl-ldn-c1-h1";
networking.networkmanager.enable = true;
time.timeZone = "Europe/London";
services.openssh = {
enable = true;
settings = {
PasswordAuthentication = true;
KbdInteractiveAuthentication = false;
PermitRootLogin = "yes";
};
};
systemd.services.NetworkManager = {
enable = true;
wantedBy = [ "multi-user.target" ];
};
systemd.services.dmesg-persist = {
description = "Persist dmesg output";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.util-linux}/bin/dmesg -D";
RemainAfterExit = true;
};
};
```
9. Apply changes:
```bash
nixos-rebuild switch
```
**Tips**
- Backup BIOS settings before changes
- USB boot issues? Reconnect after setting 15W TDP
- The N97 plays nice with Linux - expect smooth sailing
I've setup a new private repository `name/nix` where I'll keep my various nixOS configurations going forward:
![[c43e67c556348683fa5a89f9c3e4da8644684ca132f3e927cda655e92c8a1a0dc1e5edf628fc9c9c4bdcf86cd44e26204da8272dc4b5f830679badcba952b2d1.png]]
### Stats
A quick btop output post-setup:
![[95c6cb1ad95333ceb196d3bd2811f95d0991d45c36cf1790a0ccbb654dbe09d031504b36009d93fe85651c5e60f8a722f27331bd01d0cfa4ee3a45d520942ec0.png]]
## Patching VSCode support
(Following [nix-community/nixos-vscode-server](https://github.com/nix-community/nixos-vscode-server))
1. Install as a tarball:
```nix
{
imports = [
(fetchTarball "https://github.com/nix-community/nixos-vscode-server/tarball/master")
];
services.vscode-server.enable = true;
}
```
2. Apply changes:
```bash
nixos-rebuild switch
```
3. Enable the service:
```bash
systemctl --user enable auto-fix-vscode-server.service
```
4. Start the service (or reboot):
```bash
systemctl --user start auto-fix-vscode-server.service
```
5. Additional symlink to workaround garbage collection:
```bash
ln -sfT /run/current-system/etc/systemd/user/auto-fix-vscode-server.service ~/.config/systemd/user/auto-fix-vscode-server.service
```
6. Test VSCode Remote Explorer:
![[49705a5eaa9c433f2ee8aa064be44658b2420330a7b905ec6c1df9721a32eadfdc9c5adc6844fbab6736def09c0f810dd718becef6a559175b92b87357a722d4.png]]
## Setup a new user account
1. Configure a new user account:
```nix
users.users.ops = {
isNormalUser = true;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = [
"ssh-rsa ........== char@rack"
];
};
```
2. Rebuild configuration:
```bash
nixos-rebuild switch
```
3. Set a password for the new account:
```bash
passwd ops
```
4. Update SSH configuration:
```nix
services.openssh = {
enable = true;
settings = {
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
PermitRootLogin = "yes";
};
};
```
5. Rebuild configuration:
```bash
nixos-rebuild switch
```
I'd recommend the VSCode ['save-as-root'](https://marketplace.visualstudio.com/items?itemName=yy0931.save-as-root) extension for saving protected files while SSH'd under your normal user account.
## Docker Setup
1. Add these lines to your `/etc/nixos/configuration.nix`:
```nix
virtualisation.docker.enable = true;
users.users.<your-username>.extraGroups = [ "docker" ];
```
2. Add the Docker Compose package to your system packages:
```nix
environment.systemPackages = with pkgs; [ docker-compose ];
```
3. After adding these lines, run:
```bash
sudo nixos-rebuild switch
```
4. Confirm docker and docker compose commands work as expected:
```bash
[ops@hl-ldn-c1-h1:/]$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[ops@hl-ldn-c1-h1:/]$ sudo docker-compose
Usage: docker compose [OPTIONS] COMMAND
Define and run multi-container applications with Docker
```
## GitHub Access
### Generate SSH Key
1. Create a new ED25519 SSH key:
```bash
[ops@hl-ldn-c1-h1:~]$ ssh-keygen -t ed25519 -C "
[email protected]"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/ops/.ssh/id_ed25519):
Created directory '/home/ops/.ssh'.
Enter passphrase for "/home/ops/.ssh/id_ed25519" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ops/.ssh/id_ed25519
Your public key has been saved in /home/ops/.ssh/id_ed25519.pub
```
2. Start the SSH agent and add your key:
```bash
[ops@hl-ldn-c1-h1:~]$ eval "$(ssh-agent -s)"
Agent pid 14708
[ops@hl-ldn-c1-h1:~]$ ssh-add ~/.ssh/id_ed25519
Enter passphrase for /home/ops/.ssh/id_ed25519:
Identity added: /home/ops/.ssh/id_ed25519 (
[email protected])
[ops@hl-ldn-c1-h1:~]$ chmod 400 ~/.ssh/id_ed25519
```
### Add Key to GitHub
1. Copy your public key:
```bash
[ops@hl-ldn-c1-h1:~]$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGgaec5Q3+cOE7UYfutK9BZp11avMn/ibNBeT1nodo56
[email protected]
```
2. Go to GitHub Settings → SSH Keys → [New SSH Key](https://github.com/settings/ssh/new)
3. Paste your public key
### Clone a repository
1. Clone a private repository:
```bash
[ops@hl-ldn-c1-h1:~]$ git clone
[email protected]:name/lab.git
Cloning into 'lab'...
The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'github.com' (ED25519) to the list of known hosts.
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (6/6), done.
```
2. Confirm it's worked as expected:
```bash
[ops@hl-ldn-c1-h1:~]$ ls lab/
README.md
```
3. Set your Git username and email:
```bash
[ops@hl-ldn-c1-h1:~/lab]$ git config --global user.name "char"
[ops@hl-ldn-c1-h1:~/lab]$ git config --global user.email "
[email protected]"
```
## Cloudflare Deployment
### Setup Cloudflared
1. Enable the Cloudflared service in your NixOS configuration:
```nix
services.cloudflared = { enable = true; };
```
2. Rebuild configuration:
```bash
nixos-rebuild switch
```
3. Generate authentication credentials by running:
```bash
nix run nixpkgs#cloudflared -- tunnel login
```
This creates a cert.pem file in ~/.cloudflared/.
4. Create a new tunnel with:
```bash
nix run nixpkgs#cloudflared -- tunnel create hl-ldn-c1-h1
```
This generates a credentials file with a UUID format.
5. Add the tunnel and service configuration to your NixOS config:
```nix
services.cloudflared = {
enable = true;
};
systemd.services.cloudflared = {
description = "Cloudflare Tunnel";
after = [ "network-online.target" "systemd-resolved.service" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkgs.cloudflared}/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run";
Restart = "always";
RestartSec = "5s";
User = "ops";
Group = "users";
};
};
environment.etc."cloudflared/config.yml".text = ''
tunnel: fd903294-bdff-4ce4-9524-a9ee52610024
credentials-file: /home/ops/.cloudflared/fd903294-bdff-4ce4-9524-a9ee52610024.json
ingress:
- hostname: "*.char.blog"
service: http://localhost:80
- hostname: "char.blog"
service: http://localhost:80
- service: http_status:404
'';
```
6. After configuration, create a CNAME record in your Cloudflare DNS settings pointing to `<tunnel-id>.cfargotunnel.com`.
7. You can now expose services via a reverse proxy like Nginx Proxy Manager:
![[0fd57f383c82ccd7f877bf518f367ca53abf44b6cfb2faa61699f5d958a947d331a506a9e8dc15bd31edd8d2c37034db0f89caa59d2de3aab14fde263c20cc76.png]]
*You will need to set your SSL/TLS encryption settings to be FULL in Cloudflare.*
The traffic flow becomes:
```plaintext
Internet -> Cloudflare -> Tunnel -> NPM -> Your Services
```