📅 Day 39 — Building a Portable Zsh Environment with GitHub Dotfiles
🎯 Goal
The goal of today was to build a portable and reproducible terminal environment.
Instead of manually configuring every system separately, the idea was to create a setup that can be deployed quickly on:
- Ubuntu
- Kali Linux
- macOS
This was achieved using a GitHub dotfiles repository combined with automated bootstrap scripts.
The core principle:
My terminal configuration should live in version control and be deployable anywhere.
🛠 What I Did
Created a Dotfiles Repository
A dotfiles repository stores configuration files used by the shell and other command-line tools.
Typical examples include:
.zshrc
.p10k.zsh
.gitconfig
.vimrc
These files control:
- shell behaviour
- prompt configuration
- plugin loading
- command aliases
- development environment settings
I created a repository called dotfiles and pushed it to GitHub so my shell configuration can be tracked and reused across machines.
Converted Shell Config Into Symlinks
To allow the shell to use the repository configuration, I replaced the original config files with symbolic links (filesystem pointers).
Resulting structure:
~/.zshrc → ~/dotfiles/.zshrc
~/.p10k.zsh → ~/dotfiles/.p10k.zsh
This means:
- the shell still loads the expected files
- the real configuration lives inside the Git repository
Any change to the repo automatically affects the shell configuration.
Installed and Standardized Zsh Plugins
Several plugins were installed to improve terminal usability.
zsh-autosuggestions
Suggests commands based on history.
Example:
typing
git sta
suggests
git status
zsh-syntax-highlighting
Colors commands depending on validity.
Examples:
valid commands → green
invalid commands → red
This provides immediate visual feedback when typing commands.
zsh-history-substring-search
Allows history navigation based on partial command input.
Typing:
git
then pressing arrow up cycles through previous git commands.
Installed Powerlevel10k
The shell prompt was customized using Powerlevel10k, a fast and highly configurable Zsh theme.
It displays useful contextual information directly in the prompt:
- current directory
- Git repository status
- command indicators
This improves readability and workflow efficiency.
Standardized the Environment Across Machines
The environment was reproduced on:
- Ubuntu VM (source configuration)
- Kali Linux VM
- macOS host
Ubuntu
Ubuntu was used as the source-of-truth configuration.
Steps included:
- creating ~/dotfiles
- copying .zshrc and .p10k.zsh
- initializing Git repository
- pushing configuration to GitHub
- converting local files to symlinks
Kali Linux
Kali initially launched terminals using bash (Bourne Again Shell) instead of Zsh.
Steps included:
- installing Zsh
- installing Oh My Zsh
- installing Powerlevel10k
- installing required plugins
- cloning dotfiles repository
- linking configuration files
QTerminal continued launching bash even after changing the default shell.
This was solved by adding the following line to ~/.bashrc:
exec zsh
This forces bash sessions to immediately switch to Zsh.
macOS
macOS already had:
- Zsh
- Oh My Zsh
- Homebrew
- Powerlevel10k
Steps included:
- cloning the dotfiles repository
- installing missing plugin zsh-history-substring-search
- backing up the existing .zshrc
- linking configuration files to the repo
To preserve macOS Ruby tooling, a conditional rbenv (Ruby version manager) block was added to the shared .zshrc.
Linux machines ignore it safely.
Created Bootstrap Setup Scripts
To automate future installations, two setup scripts were created.
Linux bootstrap
setup-linux.sh installs:
- Zsh
- Oh My Zsh
- Powerlevel10k
- plugins
- Nerd fonts
- dotfiles repository
- symlinked configuration
Typical usage:
git clone https://github.com/JuriBuora/dotfiles.git
cd dotfiles
./setup-linux.sh
macOS bootstrap
setup-mac.sh installs:
- Homebrew dependencies
- Oh My Zsh
- plugins
- fonts
- dotfiles repository
- configuration symlinks
Typical usage:
git clone https://github.com/JuriBuora/dotfiles.git
cd dotfiles
./setup-mac.sh
Solved Cross-Machine Git Synchronization Issues
Working from multiple machines created Git push conflicts.
Typical error:
push rejected because remote contains work you do not have locally
This occurs when another machine pushed changes first.
Correct workflow:
git pull –rebase origin main
git push
This avoids unnecessary merge commits and keeps history clean.
Standardized Git Identity
To ensure consistent commits across machines, global Git configuration was set:
git config –global user.name “Juri Buora”
git config –global user.email “juri3011@gmail.com”
git config –global pull.rebase true
🔗 Key Cybersecurity Connections
Consistent environments
Security professionals often work across multiple machines.
Portable environments improve:
- reliability
- speed
- tooling familiarity
Dotfiles repositories enable this consistency.
Infrastructure-as-Code mindset
This workflow reflects Infrastructure as Code (IaC) principles.
Configuration becomes:
- version controlled
- reproducible
- portable
This concept is widely used in:
- DevOps
- cloud engineering
- security engineering
Automation reduces human error
Manual setup leads to:
- inconsistent environments
- forgotten steps
- configuration drift
Automation scripts ensure identical setups.
⚠ Challenges
GitHub authentication
GitHub no longer accepts account passwords for Git operations.
Authentication must use Personal Access Tokens (PAT).
Divergent Git branches
Working from multiple machines caused branch divergence.
Using git pull --rebase resolves this cleanly.
Hidden configuration files
Files beginning with a dot are hidden.
To view them:
ls -la
📚 What I Learned
- dotfiles repositories enable portable shell environments
- symlinks allow version-controlled configuration
- Zsh plugins improve command-line productivity
- bootstrap scripts automate system setup
- disciplined Git workflows are necessary when using multiple machines
➡ Next Steps
- expand the dotfiles repository
- add useful aliases
- refine bootstrap scripts
- continue improving reproducible environments
🧠 Reflection
Today felt like building a professional command-line environment rather than just tweaking a terminal.
The key realization:
If something must be configured more than once, automate it.
🧩 Lessons Learned
What worked
dotfiles repository + bootstrap scripts created a clean reproducible setup
What broke
Git push failures and branch divergence
Why it broke
multiple machines modified the same repository
Fix / takeaway
always pull before pushing when working across machines
📈 Skill Progression Context
Today’s work strengthened engineering discipline around environment management and automation.
These skills are valuable for:
- DevSecOps workflows
- detection engineering environments
- cloud security tooling
- infrastructure automation
Portable environments reduce friction and allow faster security analysis work.
