Dotfiles, Secrets, and Personal Platforms

LESSON

Linux Workstations: Ownership, Reproducibility, and Repair

007 25 min beginner

Dotfiles, Secrets, and Personal Platforms

By the end of this lesson, you will be able to...

  • classify workstation state by reproducibility, sensitivity, mutability, and host specificity;

  • decide whether a file belongs in shared configuration, protected secret storage, backup or synchronization, a cache, or a host-specific record;

  • review a dotfiles change without mistaking Git ignore rules or a NixOS generation for protection of private or changing state.

Idea in one sentence: A personal platform becomes recoverable when configuration, secrets, mutable data, caches, and host facts each have an explicit home and recovery rule—not when everything is copied into one repository.

Core Insight

Maya's new laptop now has an ownership record and a NixOS configuration. She wants the final convenience: clone one dotfiles repository and make the machine feel like hers.

The tempting plan is to synchronize her whole home directory. It appears tidy: editor preferences, SSH configuration, browser profiles, API tokens, downloaded notes, caches, and machine settings all travel together.

That plan works only when every file has the same lifecycle. Her home directory does not. A private key is sensitive even when unchanged. Project notes are valuable because they change. A cache is disposable because it can be regenerated. A display scale can be correct on one laptop and wrong on another. A NixOS generation can restore system configuration without restoring any of these things.

The stronger model is:

Treat personal state as several classes with different homes: shared configuration, protected secrets, mutable data, derived caches, and host-specific facts. Reproduce, protect, back up, regenerate, or parameterize each class according to its properties.

The trade-off is explicit: dotfiles reduce setup time and make choices reviewable, but a broad sync can leak credentials, overwrite good local state, and preserve habits that no longer fit the machine.

The State Inventory Before the Repository

Before choosing a tool or directory layout, classify each item with four questions:

  1. Can another machine use the same content? If yes, it may be reproducible configuration.
  2. Would disclosure harm an account, person, or system? If yes, it is a secret or private record and needs protected storage.
  3. Does it change because the machine is used? If yes, it is mutable data, not merely configuration.
  4. Is it true only for this host or device? If yes, it needs a host-specific boundary rather than a global default.

Maya makes the following synthetic inventory:

Item Classification Home and recovery rule
Editor keybindings and terminal colors Shared, reproducible configuration Version-controlled dotfiles; apply to a new host, then verify the editor opens
~/.ssh/id_* private key Secret Protected secret/key storage and a separate revocation/recovery process; never a normal dotfiles file
~/notes/ project notes Mutable data Backup or synchronization with restore checks; do not treat a config commit as a backup
~/.cache/ render cache Derived cache Exclude and regenerate unless a specific workflow proves it is valuable to preserve
Laptop display scale and device-specific workaround Host-specific fact Per-host configuration/module or a documented local override; test on that device
/etc/nixos/configuration.nix and modules Reproducible system description Version-controlled with the host boundary made explicit; rebuild and verify runtime behavior

The table is a teaching model. Some files contain more than one class. A configuration file with an embedded token must be split or redesigned; putting it in a “config” directory does not make the token non-secret.

Git Is a Change Record, Not a Secret Boundary

Maya creates a repository with reviewed, non-secret configuration and templates:

dotfiles/
  git/.gitconfig
  terminal/config.toml
  editor/init.lua
  nix/hosts/cedar.nix
  nix/hosts/field.nix
  services/note-preview.env.example
  README.md

The example environment file names required variables but contains no real values. Its job is to make the secret interface visible without copying a credential into a repository.

Git ignore patterns are useful for intentionally untracked files. They are not a retroactive safety mechanism. The Git documentation is precise: .gitignore affects intentionally untracked files; files already tracked are not affected. A secret that was committed needs an incident response—remove it from active use, revoke or rotate the credential as appropriate, and then repair the repository state. Adding a pattern afterward does not make prior exposure disappear. gitignore documentation

This gives Maya a safer review loop before every configuration commit:

classify a changed file
  -> inspect the staged diff, not only the filename
  -> confirm no private value, mutable data, or host accident entered shared config
  -> commit the reproducible change with its intended host scope
  -> apply it on the target machine and run an acceptance check

The evidence step matters. A path named .env, private, or secrets is a warning, not proof. Conversely, an innocently named configuration file can contain a token, an email address, a private hostname, or a machine-specific path.

A Worked Migration: Two Laptops, One Personal Platform

Maya moves from laptop cedar to laptop field. She wants the same editor behavior and NixOS policy, but the new screen needs a different scale and the old SSH key should not be copied casually.

The naive migration is:

copy ~/.config and ~/.ssh
clone dotfiles
hope the new machine behaves like the old one

It fails in three different ways. Copying ~/.ssh treats a credential as ordinary configuration. Copying all of ~/.config can carry generated databases, stale paths, or application state. Reusing cedar's display setting can make field unpleasant or unusable.

Maya instead walks through the inventory.

Class Action on field Evidence of success Boundary if it fails
Shared editor/terminal config Apply the reviewed config Open a known project and run one known command Revert only that config change; do not erase project data
NixOS system description Select or create the field host module, then build/test it Candidate builds; selected services and paths behave as intended Use the previous generation or correct the module
Host display setting Set it in the host-specific location The local display is legible after login Keep it out of cedar's shared default
SSH credential Provision or authorize it through the chosen protected process A deliberately permitted connection authenticates Revoke/replace the key; do not retrieve it from a dotfiles commit
Notes and project data Restore from a data backup/sync process Open one known note and verify expected history Follow the data restore procedure, separate from config rebuild
Cache Leave absent initially Application can regenerate it Diagnose only if regeneration changes required behavior

So far, the same “personal setup” has become six smaller recovery paths. That is a feature. A failed terminal color change should not trigger a secret recovery, and a lost note should not be treated as a NixOS generation problem.

Secrets Need Their Own Interface

The lesson does not prescribe one secret manager. The right tool depends on your operating system, account model, threat model, backup requirements, and whether a service starts before you log in. The design requirement is simpler: know who may read the value, how the program receives it, how it is backed up or re-provisioned, and how it is revoked or rotated.

For example, Git itself can ask credential helpers to obtain credentials from external storage. Its documentation notes that helpers often integrate with operating-system or other secure storage. It also warns that the built-in credential-store helper writes passwords unencrypted to disk, protected only by filesystem permissions. Git credential documentation credential-store documentation

That is a useful boundary signal: “the file has restrictive permissions” is not the same claim as “the value is encrypted or safe to put in a shared repository.” When a service needs a secret, record the secret reference and delivery mechanism in the ownership record, never the value itself.

Mutable State Is Not a Failure of Declaration

NixOS makes the desired system description inspectable, but it still needs persistent state for parts of the running system. Its manual lists examples such as /nix, /boot, /var/lib/nixos, systemd state, and optionally the system journal; these have different roles from user documents and configuration modules. NixOS Manual: necessary system state

This is the important correction: reproducibility is not “nothing ever changes.” It is knowing which changes are declared, which changes are valuable data, which are private, and which can be discarded. A configuration rebuild should not silently erase the only copy of a project database; a backup restore should not silently reintroduce an old machine's credentials.

Common Boundary Errors

Confusion: “A .gitignore entry protects a secret.”

Why it is tempting: ignored files no longer appear as ordinary untracked work.

Better model: ignore rules help keep intentionally untracked paths untracked. They do not encrypt, revoke, remove an already tracked secret, or decide who can access a copy elsewhere.

Confusion: “All dotfiles should be shared across every host.”

Why it is tempting: one repository feels like one truth.

Better model: share a base only where the behavior should be the same. Split host modules and local overrides when hardware, account scope, display, network, or service role differs.

Confusion: “A NixOS generation backs up my personal platform.”

Why it is tempting: generations make a system configuration recoverable.

Better model: a generation recovers retained configuration state. User data, secrets, external accounts, and some runtime state need their own recovery evidence.

Confusion: “Caches are always safe to delete.”

Why it is tempting: many caches are derived.

Better model: treat a cache as disposable only after identifying its producer and confirming that regeneration has no unacceptable cost or lost state. The signal is a successful regeneration test, not the directory name alone.

Design Review: Can This State Cross Machines?

Before adding any path to a dotfiles repository, synchronization tool, or NixOS module, answer:

  1. Is this configuration, secret, mutable data, cache, or host fact?
  2. Who needs to read it, and on which machines?
  3. What happens if it leaks, is overwritten, or is absent on a new machine?
  4. Which system owns updates: Git, a secret store, a backup job, the application, or the package manager?
  5. What is the smallest acceptance check after restoring or applying it?
  6. What must be rotated, restored, regenerated, or kept host-local during recovery?

The next capstone uses these answers to make a recovery dossier. Its goal is not a beautiful repository. Its goal is a workstation another careful person could rebuild and diagnose without guessing which class of state they are touching.

Check Your Understanding

Check: A file called config.toml contains an API token and editor settings. Where does it belong?

Think first, then reveal.

Answer: It contains two state classes, so split the design. Keep the non-secret editor settings in reproducible configuration if appropriate; deliver the token through the chosen protected secret boundary. A filename cannot make a secret safe to commit.

Check: A secret was accidentally committed, and Maya adds it to .gitignore. What important problem remains?

Think first, then reveal.

Answer: The secret was already tracked or exposed. It must be treated as compromised according to its use: revoke or rotate it as appropriate, remove it from active use and the repository state, and investigate who may have received it. .gitignore alone affects only untracked files.

Practice: Create a Personal State Boundary Map

Choose five real paths from a Linux machine. Classify each as configuration, secret, mutable data, cache, or host-specific fact. For every path, write its owner, cross-machine policy, recovery action, and one acceptance check.

A good map includes at least one item that is not synchronized, explains why, and names a test that distinguishes successful restoration from merely having copied a file. If a path mixes classes, split the design rather than assigning one label to the whole directory.

Resources

Key Takeaways

PREVIOUS NixOS and Declarative Machines NEXT Capstone: Rebuild a Workstation From Notes