Skip to main content
This homelab provides a comprehensive development environment using Nix flakes, direnv, and custom shell hooks. The environment includes all necessary tools for managing NixOS configurations, secrets, and infrastructure.

Quick Start

If you already have Nix and direnv installed:
1

Clone the repository

git clone https://github.com/soriphoono/homelab.git
cd homelab
2

Allow direnv

direnv allow
This activates the development shell automatically when you enter the directory.
3

Verify tools are available

which alejandra agenix sops
All tools should be in your PATH.

Prerequisites

Install Nix

If Nix isn’t installed:
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
This installs Nix with flakes enabled by default.

Install direnv

For automatic shell activation:
# On NixOS
nixpkgs.direnv

# On other systems
curl -sfL https://direnv.net/install.sh | bash
Add to your shell profile (~/.bashrc or ~/.zshrc):
eval "$(direnv hook bash)"  # or 'zsh', 'fish'

Development Shell Configuration

The shell.nix file defines the development environment:
{
  pkgs,
  lib,
  config,
  ...
}:
with pkgs;
  mkShell {
    packages =
      [
        nil
        alejandra
        vulnix

        age
        agenix
        sops
        ssh-to-age
      ]
      ++ lib.optional stdenv.isLinux [
        disko
        nixos-facter
      ];

    shellHook = '''
      ${config.pre-commit.shellHook}
      source ${config.agenix-shell.installationScript}/bin/install-agenix-shell

      # Deploy GitHub Actions from actions.nix
      mkdir -p ./.github/workflows
      ${lib.concatStringsSep "\n" (lib.mapAttrsToList (name: file: let
          safeName = lib.removeSuffix ".yml" name;
        in '''
          cp -f ${file} ./.github/workflows/${safeName}.yml
          chmod +w ./.github/workflows/${safeName}.yml
        ''')
        config.githubActions.workflowFiles)}
    ''';
  }

Available Tools

Nix Development Tools

  • nil: Nix language server for IDE integration
  • alejandra: Nix code formatter
  • vulnix: Security vulnerability scanner for Nix packages

Secrets Management

  • age: Encryption tool
  • agenix: Nix secrets management
  • sops: Alternative secrets backend
  • ssh-to-age: Convert SSH keys to age format

System Tools (Linux only)

  • disko: Declarative disk partitioning
  • nixos-facter: Hardware detection and configuration generation

Direnv Integration

The .envrc file automatically activates the Nix shell:
use flake
This simple configuration:
  • Loads the development shell when entering the directory
  • Unloads when leaving the directory
  • Watches flake.nix for changes and reloads automatically

Direnv Commands

# Reload the environment
direnv reload

# Check current status
direnv status

# Manually allow after changes
direnv allow

Shell Hooks

The shell automatically runs several setup tasks:

1. Pre-commit Hooks

${config.pre-commit.shellHook}
Installs Git pre-commit hooks for:
  • Code formatting checks
  • Syntax validation
  • Security scans

2. Agenix Shell Integration

source ${config.agenix-shell.installationScript}/bin/install-agenix-shell
Loads encrypted secrets as environment variables. Secrets defined in secrets.nix become available:
echo $GITHUB_TOKEN  # Automatically decrypted and loaded

3. GitHub Actions Deployment

Automatically generates workflow files from actions.nix:
ls .github/workflows/
# Shows auto-generated CI workflows
This ensures CI configuration stays in sync with your Nix code.

IDE Integration

VS Code / VSCodium

Install the Nix extensions:
{
  "recommendations": [
    "jnoortheen.nix-ide",
    "mkhl.direnv"
  ]
}
The direnv extension automatically activates the environment in the integrated terminal.

Language Server

The nil language server provides:
  • Code completion
  • Go-to-definition
  • Error checking
  • Hover documentation
It’s automatically available in the shell and will be detected by your IDE.

Formatting Code

Use alejandra to format Nix files:
# Format a single file
alejandra systems/zephyrus/default.nix

# Format entire directory
alejandra .

# Check without modifying
alejandra --check .

Security Scanning

Check for vulnerable packages:
vulnix -S /run/current-system
This scans your system for packages with known CVEs.

Common Workflows

Testing Configuration Changes

# Test without activating
nixos-rebuild test --flake .#zephyrus

# Build and activate
nixos-rebuild switch --flake .#zephyrus

Managing Secrets

# Edit a secret
agenix -e secrets/github_token.age

# Verify secrets are loaded in shell
env | grep -i github

Building Installation Media

nix build .#nixosConfigurations.installer.config.system.build.isoImage

Environment Variables

The shell provides access to:
  • Decrypted secrets (uppercase names from secrets.nix)
  • Standard Nix variables (NIX_PATH, etc.)
  • Custom variables from your configuration

Troubleshooting

Direnv not activating

Check if you added the hook to your shell:
type direnv
# Should show: direnv is a function
If not, add to ~/.bashrc:
eval "$(direnv hook bash)"

Tools not in PATH

Ensure direnv is allowed:
direnv allow
Check the status:
direnv status

Secrets not loading

Verify your user has access in secrets.nix:
userSecrets = {
  github_token = ["yourusername"];
};
Ensure your private key is available:
ls ~/.ssh/id_ed25519
ls ~/.config/age/key.txt

Shell hook errors

Reload with debug output:
PS4='+ ' direnv allow 2>&1 | less
This shows detailed execution of shell hooks.

Updating the Environment

When you modify flake.nix or shell.nix:
  1. Direnv automatically detects changes
  2. Prompts you to reload with direnv allow
  3. Rebuilds the environment with new dependencies
Manual update:
nix flake update
direnv reload

Best Practices

  • Always use the dev shell for system operations
  • Don’t install tools globally that are in the shell
  • Commit .envrc but not .direnv/ cache
  • Test shell changes before committing
  • Keep secrets out of shell scripts

Adding New Tools

To add a tool to the development environment:
1

Edit shell.nix

Add the package to the packages list:
packages = [
  nil
  alejandra
  your-new-tool  # Add here
];
2

Reload the environment

direnv reload
The tool is now available in your PATH.
3

Verify availability

which your-new-tool

Non-NixOS Systems

The dev shell works on any system with Nix installed:
  • macOS: Full support except Linux-specific tools
  • WSL2: Full Linux functionality
  • Other Linux: Works without NixOS-specific tools
Linux-specific tools are automatically excluded on non-Linux systems:
++ lib.optional stdenv.isLinux [
  disko
  nixos-facter
]

Build docs developers (and LLMs) love