Kieran's opinionated (and probably slightly dumb) nix config
Nix 54.2%
Shell 22.9%
HTML 14.7%
JavaScript 2.3%
Go 2.1%
Other 3.8%
795 2 0

Clone this repository

https://tangled.org/dunkirk.sh/dots https://tangled.org/did:plc:krxbvxvis5skq7jj6eot23ul/dots
git@knot.dunkirk.sh:dunkirk.sh/dots git@knot.dunkirk.sh:did:plc:krxbvxvis5skq7jj6eot23ul/dots

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

Kieran's Dots#

nix rebuild with flake update

CAUTION

These dots are highly prone to change / breakage.

I am not a nix os expert (this is my first time touching nix), so I'm not sure if this will work or not. I'm just trying to get my dots up on github.

After 591 days of these dots being in constant operation, many many rebuilds, and 776 commits these dots have been rock solid and I have no complaints.

The layout#

~/dots
├── .github/workflows  # CI/CD (deploy-rs + per-service reusable workflow)
├── dots               # config files symlinked by home-manager
│   └── wallpapers
├── machines
│   ├── atalanta       # macOS M4 (nix-darwin)
│   ├── ember          # dell r210 server (basement)
│   ├── moonlark       # framework 13 (dead)
│   ├── nest           # shared tilde server (home-manager only)
│   ├── prattle        # oracle cloud x86_64
│   ├── tacyon         # rpi 5
│   └── terebithia     # oracle cloud aarch64 (main server)
├── modules
│   ├── lib
│   │   └── mkService.nix  # service factory (see Deployment section)
│   ├── home           # home-manager modules
│   │   ├── aesthetics # theming and wallpapers
│   │   ├── apps       # app configs (ghostty, helix, git, ssh, etc.)
│   │   ├── system     # shell, environment
│   │   └── wm/hyprland
│   └── nixos          # nixos modules
│       ├── apps       # system-level app configs
│       ├── services   # self-hosted services (mkService-based + custom)
│       │   ├── restic # backup system with CLI
│       │   └── bore   # tunnel proxy
│       └── system     # pam, wifi
├── packages           # custom nix packages
└── secrets            # agenix-encrypted secrets

Installation#

WARNING

Also to note that this configuration will not work if you do not change any of the secrets since they are encrypted.

You could install a NixOS machine, use the home-manager instructions, or use nix-darwin for macOS.

macOS with nix-darwin#

For macOS machines, you can use nix-darwin:

  1. Install Nix using the determinate systems installer:
curl -fsSL https://install.determinate.systems/nix | sh -s -- install
  1. Clone the repository:
git clone git@github.com:taciturnaxolotl/dots.git
cd dots
  1. Apply the configuration:
darwin-rebuild switch --flake .#atalanta

Home Manager#

Install nix via the determinate systems installer

curl -fsSL https://install.determinate.systems/nix | sh -s -- install --determinate

then copy ssh keys and chmod them

scp .ssh/id_rsa* nest:/home/kierank/.ssh/
ssh nest chmod 600 ~/.ssh/id_rsa*

and then clone the repo

git clone git@github.com:taciturnaxolotl/dots.git
cd dots

and execute the machine profile

nix-shell -p home-manager
home-manager switch --flake .#nest

setup atuin and import previous shell history

atuin login
atuin import

NixOS#

These instructions have been validated by installing on my friend's machine (Nat2-Dev/dots)

WARNING

This only currently works with prattle and terebithia as they have the proper disko configs setup.

For remote installations (like Oracle Cloud), use nixos-anywhere:

nix run github:nix-community/nixos-anywhere -- \
  --flake .#prattle \
  --generate-hardware-config nixos-facter ./machines/prattle/facter.json \
  --build-on-remote \
  root@<ip-address>

Replace prattle with your machine configuration and <ip-address> with your target machine's IP.

NOTE

Make sure your SSH key is in the target machine's authorized_keys and the machine configuration has the correct network settings. The --generate-hardware-config nixos-facter flag will generate a comprehensive hardware report using nixos-facter instead of the traditional nixos-generate-config.

Using the install script#

curl -L https://raw.githubusercontent.com/taciturnaxolotl/dots/main/install.sh -o install.sh
chmod +x install.sh
./install.sh

Post-install#

After first boot, log in with user kierank and the default password, then change it immediately:

passwd kierank

Move the config to your home directory and symlink:

sudo mv /etc/nixos ~/dots
sudo ln -s ~/dots /etc/nixos
sudo chown -R $(id -un):users ~/dots

Set up atuin for shell history sync:

atuin login
atuin sync

Deployment#

Two deploy paths: infrastructure (NixOS config changes in this repo) and application code (per-service repos).

Infrastructure#

Pushing to main here triggers .github/workflows/deploy.yaml which runs deploy-rs over Tailscale to rebuild NixOS on the target machine.

# manual deploy
nix run 'github:serokell/deploy-rs' -- --remote-build --ssh-user kierank .

Application code#

Each service repo has a minimal workflow calling the reusable .github/workflows/deploy-service.yml. On push to main:

  1. Connects to Tailscale (tag:deploy)
  2. SSHes as the service user (e.g., cachet@terebithia) via Tailscale SSH
  3. Snapshots the SQLite DB (if db_path is provided)
  4. git pull + bun install --frozen-lockfile + sudo systemctl restart
  5. Health check (HTTP URL or systemd status fallback)
  6. Auto-rollback on failure (restores DB snapshot + reverts to previous commit)

Per-app workflow — copy and change the with: values:

name: Deploy
on:
  push:
    branches: [main]
  workflow_dispatch:
jobs:
  deploy:
    uses: taciturnaxolotl/dots/.github/workflows/deploy-service.yml@main
    with:
      service: cachet
      health_url: https://cachet.dunkirk.sh/health
      db_path: /var/lib/cachet/data/cachet.db
    secrets:
      TS_OAUTH_CLIENT_ID: ${{ secrets.TS_OAUTH_CLIENT_ID }}
      TS_OAUTH_SECRET: ${{ secrets.TS_OAUTH_SECRET }}

Omit health_url to fall back to systemctl is-active. Omit db_path for stateless services.

mkService#

modules/lib/mkService.nix standardizes service modules. A call to mkService { ... } provides:

  • Systemd service with initial git clone (subsequent deploys via GitHub Actions)
  • Caddy reverse proxy with TLS via Cloudflare DNS and optional rate limiting
  • Data declarations (sqlite, postgres, files) that feed into automatic backups
  • Dedicated system user with sudo for restart/stop/start (enables per-user Tailscale ACLs)
  • Port conflict detection, security hardening, agenix secrets

Adding a new service: create a module in modules/nixos/services/, enable it in machines/terebithia/default.nix, and add a deploy workflow to the app repo. See modules/nixos/services/cachet.nix for a minimal example.

Secrets (agenix)#

Secrets are encrypted in secrets/*.age and declared in secrets/secrets.nix. Referenced as config.age.secrets.<name>.path — decrypted at activation time to /run/agenix/.

cd secrets && agenix -e myapp.age    # create/edit a secret

Backups#

Services are automatically backed up nightly using restic to Backblaze B2. Backup targets are auto-discovered from data.sqlite/data.postgres/data.files declarations in mkService modules.

The atelier-backup CLI provides an interactive TUI for managing backups:

sudo atelier-backup              # Interactive menu
sudo atelier-backup status       # Show backup status
sudo atelier-backup restore      # Restore wizard
sudo atelier-backup dr           # Disaster recovery

See modules/nixos/services/restic/README.md for setup and usage.

some odd things#

for helix if you want the grammar to work you must run the following as per this helix discussion

hx -g fetch
hx -g build

Screenshots#

I've stuck the rest of the screenshots in a spoiler to preserve space

Last updated: 2024-12-27

the github page of this repo nautilus file manager neofetch spotify with cava next to it zed with the hyprland config open cool-retro-term with neofetch

Credits#

Thanks a bunch to the following people for their dots, configs, and general inspiration which i've shamelessly stolen from:

📜 License#

The code is licensed under MIT! That means MIT allows for free use, modification, and distribution of the software, requiring only that the original copyright notice and disclaimer are included in copies. All artwork and images are copyright reserved but may be used with proper attribution to the authors.

© 2025-present Kieran Klukas