This post documents my dotfiles repository and how I use it to bootstrap and maintain Linux workstations with a strong emphasis on WSL2. The repo lives at github.com/irish1986/dotfiles and focuses on repeatable, idempotent configuration using Ansible.
The core goal is simple: I want a versioned, repeatable setup for Ubuntu that I can apply to multiple machines (personal and professional), including WSL2 on Windows 11. The playbooks are written to be idempotent so I can run them anytime to reconcile drift.
What’s inside#
The repository is structured like a full configuration project rather than a single dotfiles dump:
- Ansible playbooks and roles for system configuration.
- Inventory and group variables for environment-specific customization.
- Pre and post task hooks to keep the flow modular.
- Scripts for bootstrap and maintenance tasks.
- CI automation and pre-commit checks for consistency.
My primary use case is WSL2. The README documents the flow I follow:
- Provision WSL2 — clean slate or fresh distro install.
- SSH keys — ensure a working key in GitHub (either native WSL2 or copied from Windows).
- Bootstrap install — run the setup script to initialize the environment.
The bootstrap command is in the repository README.md and invokes a shell script that installs dependencies and sets up the baseline playbook execution.
The main playbook#
Here’s the main playbook file pulled directly from the repo:
---
- name: DotFiles Config
hosts: localhost
connection: local
gather_facts: true
any_errors_fatal: false
pre_tasks:
- name: Detect environment
ansible.builtin.import_tasks: pre_tasks/whoami.yml
tasks:
- name: Set roles
block:
- name: Run roles
ansible.builtin.include_role:
name: "{{ item }}"
with_items:
- docker
- git
- hugo
- nvm
- python
- ssh
- system
- zsh
rescue:
- name: Rescue roles | Update
ansible.builtin.debug:
msg: Playbook encountered an issue while setting role, only update role will be run.
always:
- name: Default roles | Update
ansible.builtin.include_role:
name: "{{ item }}"
with_items:
- update
post_tasks:
- name: Status message
ansible.builtin.import_tasks: post_tasks/end.yml
The roles playbook#
Every feature of my .dotfiles is implemented using an independent Ansible roles. This allows me to add and remove feature fairly easily when deploying on different hardware without requiring an entire reworks of the workflows.
Why this approach works for me#
- Idempotent let me reapply changes safely.
- Roles keep responsibilities isolated and easier to evolve.
- Automation make onboarding fast and consistent.
References#
This repository is inspired by a couple of excellent projects:

