Why I Built This
After years of reinstalling and reconfiguring my development environment every time I got a new machine or wiped my system, I wanted a setup that could be cloned, backed up, and restored with a single command. No more manual configuration. No more forgetting that one setting I tweaked six months ago. I kept postponing this until AI tools became capable enough to help with Linux system interaction.
This led me to build my i3 System Backup and Migration Kit — a version-controlled, portable Linux environment that travels with me across machines.
The Core Stack
My setup revolves around these components:
- i3 Window Manager: A tiling window manager that stays out of my way
- Rofi: Fast application launcher and window switcher
- Zsh + Oh My Zsh: A shell environment with hundreds of custom aliases
- Automated Backup Scripts: Complete system state capture
- One-Command Restore: Full environment replication
The i3 + Rofi Workflow
Window Management
i3 is a tiling window manager, which means windows automatically tile themselves without overlapping. No mouse-dragging to resize. No hunting for that tiny window edge. Your screen is always fully utilized.
# Core i3 keybindings
$mod+Return → Open terminal
$mod+d → Launch Rofi (application launcher)
$mod+Tab → Rofi window switcher
$mod+Shift+q → Kill window
$mod+1..0 → Switch workspace
$mod+Shift+←→↑↓ → Move windowMy workspace configuration is semantic - each number corresponds to a specific purpose:
1: Terminal → Alacritty, shell sessions
2: Web → Firefox, Chrome, Zen Browser
3: Code → VS Code, Cursor, Windsurf
4: Chat → Slack, Teams
5: Media → Spotify, YT Music
6: Files → Nautilus
7: Misc → VPN
8: Extra → Temporary work
9: Games → Steam
10: Social → Discord, WhatsAppRofi
Rofi is what makes this setup usable. It's not just an application launcher — it's a universal interface.
bindsym $mod+d exec --no-startup-id rofi -show drun # Launch apps
bindsym $mod+Tab exec "rofi -show window" # Switch windowsWhat makes Rofi useful is its plugin ecosystem and customization. Mine is themed with the Papirus icon set and uses the Hack font at 12pt. The configuration lives in a single file that gets backed up and restored automatically. Feel free to explore the repo (link at end) and modify as needed.
The Migration System
Complete Backup Capture
The backup-system.sh script captures everything:
Configuration Files:
- i3 window manager configuration
- Rofi launcher settings
- Polybar, Dunst, Picom configs
- GTK themes and fontconfig
- Custom application entries
System State:
- Complete package list (~2000+ packages)
- Manually installed packages (~200+ packages)
- i3-related packages
- PPA sources (9 third-party repos, some might be outdated. Use AI to fix)
- Snap packages (17 including Slack, Firefox)
- Flatpak packages (Zen Browser)
Environment:
.bashrc,.zshrc,.profile.Xresources,.xinitrc- Custom fonts
- Wallpapers
- User crontab
One-Command Restoration
On a fresh Ubuntu system, I run:
./restore-system.shThis script:
- Updates the system
- Installs essential i3 packages
- Restores PPA sources (interactive)
- Installs captured packages (interactive)
- Restores all configurations
- Sets up fonts and appearance
- Prompts for reboot
The entire process takes about 15-20 minutes and leaves me with the same environment I had before.
The Developer Shell
Zsh Setup
My .zshrc is a development platform. With Oh My Zsh as the foundation, I've built hundreds of aliases and functions that turn repetitive tasks into single keystrokes.
Git Workflow Aliases
# Status and viewing
gs → git status
gd → git diff
gds → git diff --staged
gl → git log --oneline --graph --decorate
glg → git log --graph --oneline --all --decorate
# Branching
gb → git branch
gba → git branch -a
gcb → git checkout -b
gclean → git branch --merged | xargs git branch -d
# Committing
gcm → git commit -m
gca → git commit --amend
gaa → git add .
# Enhanced workflow
gsave → git stash push -m "WIP: Auto-save"
gpop → git stash pop
gsync → git fetch --all && git pull --rebase
gfeature→ Create feature branch from mainDocker at Your Fingertips
d → docker
dc → docker-compose
dps → docker ps
dpsa → docker ps -a
dex → docker exec -it
dlog → docker logs -f --tail 100
dprune → docker system prune -a -f
dclean → Clean containers and dangling imagesProject Scaffolding Functions
These functions generate complete project structures with a single command:
# Django full-stack with DRF + HTMX + PostgreSQL + Celery
mkdjango myproject
# Vite + React + TypeScript + Tailwind
mkvite myproject
# Full-stack Django + React
mkfullstack myproject
# Python virtual environment project
mkpython myproject
# Node.js project with pnpm
mknode myprojectThe Django template alone generates:
- Virtual environment setup
- requirements.txt with Django 5.0, DRF, Celery, PostgreSQL adapter
- Complete settings.py with environment variables
- Celery configuration
- Docker + docker-compose setup
- HTMX-enabled base template
.envtemplate and.gitignore
Modern CLI Tools
I've replaced standard Unix tools with modern alternatives:
cat → batcat --style plain # Syntax highlighting
ls → eza --icons # Icons and git status
ll → eza -lah --icons --git # Detailed with git info
tree → eza --tree --icons # Tree view
find → fd # Fast, intuitive find
grep → rg # ripgrep - fast
top → btop # Process viewer with graphsFZF Integration
FZF turns the shell into an interactive fuzzy-finding tool:
Ctrl+T → Fuzzy find git files with preview
Ctrl+O → Navigate to projects interactively
Ctrl+R → Enhanced history searchAPI Testing Helpers
Built-in functions for testing REST APIs without leaving the terminal:
# JWT authentication workflow
jwt-login <url> <username> <password> # Store token
jwt-auth <url> <method> <data> # Make authenticated request
# Django API testing
django-login <url> <username> <password> # Session-based auth
django-api <url> <method> <data> # Make API calls
# Generic curl helpers
curl-get <url>
curl-post <url> <json-data>Development Server Management
django-stack → Start Django + Celery + Redis on available port
vite-dev → Start Vite dev server with auto port detection
fullstack-dev → Start both backend and frontend
stop-dev → Kill all dev servers on common ports
restart-api → Stop and restart API serverTool Replacements
| Old Tool | New Tool | Why |
|---|---|---|
ls |
eza |
Icons, git integration, better defaults |
cat |
bat |
Syntax highlighting, line numbers |
find |
fd |
Intuitive syntax, fast, respects .gitignore |
grep |
rg |
Recursive by default, fast, colorful |
top |
btop |
TUI, mouse support, graphs |
ps |
procs |
Colorful, modern output |
df |
duf |
Better disk usage visualization |
FZF: Fuzzy Everything
FZF is integrated into every part of my workflow:
# File finding with preview
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
# Directory navigation
export FZF_ALT_C_COMMAND='fd --type d --hidden --follow --exclude .git'Custom widgets provide:
- Git file selection with diff preview
- Project directory jumping
- Docker container log following
- History search
Starship Prompt
A minimal, fast prompt that shows:
- Current directory
- Git branch and status
- Programming language versions
- Command duration
- Exit codes
Pros and Cons
What Works
1. Portability Moving to a new machine takes 30 minutes instead of a week. My entire environment fits in a Git repository.
2. Version Control for Configuration Every change to my setup is tracked. I can see when I added an alias, what I changed in my i3 config, and roll back if something breaks.
3. Easy Experimentation Want to try a new tool? Install it, add it to the backup. If I don't like it, restore from backup.
4. Consistent Environment All my machines behave identically. I don't have to remember which machine has which setup.
5. Documentation The backup scripts serve as living documentation of my entire setup. New tools get automatically captured.
The Trade-offs
1. Ubuntu-Centric The setup is tied to Ubuntu/Debian. Porting to Arch or Fedora would require script modifications.
2. Hardware-Specific Configs Display outputs (HDMI-1, eDP-1), audio devices, and network interfaces vary between machines. These need manual adjustment after restoration.
3. i3 Learning Curve Tiling window managers have a learning curve. New users often struggle for the first week. The payoff is worth it, but it's not for everyone.
4. GUI Application Limitations Some GUI applications store configuration in non-standard locations or use dconf/gsettings which are harder to capture and restore.
5. Security The backup contains system configuration but not secrets. SSH keys, GPG keys, and API credentials must be backed up separately.
Migration in Action
Here's the workflow when I set up a new machine:
# On old machine
./backup-system.sh
tar -czf rofi-setup.tar.gz ~/projects/rofi_setup/
# Transfer to new machine via USB/cloud
# On new machine
tar -xzf rofi-setup.tar.gz
cd rofi_setup/
./restore-system.sh
# Answer interactive prompts:
# - Yes to PPA restoration
# - Selectively install packages
# - Yes to dotfile restoration
# - Reboot when done
# Post-restore tweaks:
# - Adjust display outputs in i3 config if needed
# - Import SSH/GPG keys
# - Login to applications (Slack, Spotify, etc.)Total time from unboxing to productive: ~30 minutes.
Key Takeaways
Treat dotfiles as code: Version control, document, and automate everything
Backup is not enough: You need automated restoration to test your backups
Interactive restoration over blind automation: The restore script asks before overwriting, installing PPAs, or installing packages
Capture package lists: Knowing what you installed is as important as how you configured it
Hardware abstraction: Keep hardware-specific configs (displays, audio) separate and documented
Modern CLI tools matter: The time saved by
eza,bat,fd, andrgcompounds daily
Conclusion
Building a portable Linux environment has been worth the initial setup time. The ability to replicate my environment anywhere has saved me countless hours.
If you're still manually configuring every new machine, start small. Version control your .zshrc. Write a script to install your essential packages. Build from there.
Repository: github.com/jangwanAnkit/rofi_setup
System: Ubuntu 22.04.5 LTS | i3 Window Manager | Zsh + Oh My Zsh