Automated setup script for configuring Debian/Ubuntu on Windows Subsystem for Linux (WSL).
- 🚀 Automated Installation: One command to set up your entire WSL environment
- 🔧 Modular Design: Run individual setup scripts independently
- 🔄 Idempotent: Safe to run multiple times without breaking existing setup
- 💾 Automatic Backups: Creates timestamped backups before overwriting files
- 📦 Comprehensive Packages: Installs all essential development tools
- 🎨 Color-coded Output: Clear visual feedback during installation
- 📝 Detailed Logging: Complete logs saved to
setup.log
- Essential build tools (ca-certificates, curl, git, gnupg, etc.)
- Documentation tools (man-db)
- Docker (with Docker Compose, Buildx)
- Node.js (via NVM)
- Bun (JavaScript runtime)
- Tailscale (VPN/mesh networking)
- Claude Code (AI-powered code assistant)
- Chrome for Testing (headless browser with all dependencies)
- WSL boot configuration (
/etc/wsl.conf) - Filesystem mount table (
/etc/fstab) - Custom mount script (
~/mount__data.sh) - Bash aliases (
~/.bash_aliases) - SSH keys and configuration (
~/.ssh/) - Application configs (
~/.config/)
wsl-setup-script/
├── README.md # This file
├── .gitignore # Git ignore rules
├── config.sh.example # Configuration template
├── config.sh # Your config (create from example)
├── setup-wsl.sh # Main setup script
├── setup.log # Installation log (generated)
├── scripts/
│ ├── install-packages.sh # Package installation
│ ├── configure-mount.sh # Mount configuration
│ └── setup-dotfiles.sh # Dotfiles setup
├── files/
│ ├── mount__data.sh # VHDX mount script
│ ├── wsl.conf # WSL configuration
│ └── fstab # Filesystem table
└── dotfiles/
├── .bash_aliases.example # Shell aliases template
├── .bash_aliases # Your aliases (create from example)
├── .ssh/ # SSH keys (ignored by git)
└── .config/ # Application configs
IMPORTANT: First get the scripts into your WSL environment and set executable permissions:
# Option A: Clone from git (recommended)
git clone <your-repo-url> ~/wsl-setup-script
# Option B: Copy from Windows filesystem
# cp -r /mnt/<drive>/path/to/wsl-setup-script ~/wsl-setup-script
# Navigate to the directory
cd ~/wsl-setup-script
# Set executable permissions for all shell scripts
sudo find ./ -type f -name "*.sh" -exec chmod +x {} \;Copy the example files and edit them to match your environment:
# Copy the example configuration
cp config.sh.example config.sh
# Copy the example bash aliases (optional but recommended)
cp dotfiles/.bash_aliases.example dotfiles/.bash_aliases
# Edit with your settings
nano config.sh
nano dotfiles/.bash_aliases # Customize your aliasesIMPORTANT - Update these in config.sh:
TARGET_USER- Your WSL username (change fromyourusername)TARGET_HOME- Your home directory (will be/home/yourusername)CHROME_INSTALL_PATH- Where to install Chrome for Testing (optional)
Optional - Customize dotfiles/.bash_aliases:
- Add your custom shell aliases and shortcuts
- Update
cdpalias to point to your project directory
# Make sure you're in the right directory
cd ~/wsl-setup-script
# Run the main setup script
./setup-wsl.shThis will:
- Install all packages
- Configure mount settings
- Set up dotfiles
# Make sure you're in the right directory
cd ~/wsl-setup-script
# Run only what you need
./scripts/install-packages.sh # Step 1: Install packages
./scripts/configure-mount.sh # Step 2: Configure mounts
./scripts/setup-dotfiles.sh # Step 3: Setup dotfilesAfter setup completes, restart WSL from Windows PowerShell:
wsl --shutdownThen start your WSL distribution again.
source ~/.bashrcFirst, copy the example configuration:
cp config.sh.example config.shThe config.sh file contains all configurable paths and settings:
TARGET_USER="yourusername" # Your WSL username
TARGET_HOME="/home/${TARGET_USER}" # Your home directoryCHROME_INSTALL_PATH="${TARGET_HOME}/chrome" # Chrome installation
NVM_DIR="${TARGET_HOME}/.nvm" # Node Version Manager
BUN_INSTALL="${TARGET_HOME}/.bun" # Bun runtime# IMPORTANT: Use single quotes for Windows paths to prevent backslash escaping
VHDX_PATH='D:\WSL\your-vhdx-name.vhdx' # Windows path to VHDX file
VHDX_MOUNT_NAME="__data" # Mount name
CUSTOM_MOUNT_POINT="/mnt/${VHDX_MOUNT_NAME}" # Linux mount pointWARNING: When setting VHDX_PATH, you MUST use single quotes ('...') instead of double quotes ("..."). This prevents bash from interpreting backslashes as escape characters.
Example:
- ✅ Correct:
VHDX_PATH='D:\WSL\__data\project.vhdx' - ❌ Wrong:
VHDX_PATH="D:\WSL\__data\project.vhdx"(backslashes will be removed)
ENABLE_BACKUPS="true" # Create backups before overwriting
BACKUP_SUFFIX=".backup.TIMESTAMP" # Backup file suffixYou can customize which packages to install by editing the arrays in config.sh:
# Add/remove system packages
SYSTEM_PACKAGES=(
ca-certificates
curl
git
# Add your packages here
)
# Chrome dependencies (needed for headless browser)
CHROME_DEPENDENCIES=(
libnspr4
libnss3
# All required Chrome libraries
)setup-wsl.sh
├── Check system requirements
├── Confirm with user
├── Run install-packages.sh
│ ├── Update system
│ ├── Install Tailscale
│ ├── Install Docker
│ ├── Install Chrome dependencies
│ ├── Install NVM & Node
│ ├── Install Bun
│ ├── Install Chrome for Testing
│ └── Install Claude Code
├── Run configure-mount.sh
│ ├── Copy wsl.conf → /etc/
│ ├── Copy fstab → /etc/
│ ├── Copy mount__data.sh → ~/
│ └── Configure sudo for mount script
└── Run setup-dotfiles.sh
├── Copy .bash_aliases → ~/
├── Copy .ssh/ → ~/.ssh/
├── Copy .config/ → ~/.config/
└── Set proper permissions
All scripts check if tools/files already exist before making changes:
- Packages: Checks if command exists before installing
- Files: Backs up existing files before overwriting
- Configuration: Skips if already configured
This means you can safely re-run scripts without breaking your setup.
When enabled (ENABLE_BACKUPS="true"), the scripts create backups:
- Format:
filename.backup.YYYYMMDD_HHMMSS - Example:
.bashrc.backup.20231122_143052 - Location: Same directory as original file
The setup configures WSL to automatically mount a VHDX on boot:
- wsl.conf: Enables systemd and runs mount script on boot
- fstab: Configures drive mounting (C: and D:)
- mount__data.sh: Script to mount VHDX at
/mnt/__data
When WSL starts:
- Systemd executes
~/mount__data.sh - Script unmounts any existing VHDX
- Script mounts new VHDX to
/mnt/__data - Creates symlink
/mnt/wsl/__data→/mnt/__data
If you get "Permission denied" when running scripts, set executable permissions:
cd ~/wsl-setup-script
sudo find ./ -type f -name "*.sh" -exec chmod +x {} \;After installation, log out and log back in:
exit
# Then restart your WSL distributionOr use newgrp:
newgrp dockerReload your shell:
source ~/.bashrc
# OR
source ~/.nvm/nvm.shRestart WSL completely:
# From Windows PowerShell
wsl --shutdownCheck the mount script configuration in files/mount__data.sh:
- Verify VHDX path is correct
- Ensure VHDX file exists
- Check Windows disk path is accessible
Common Issue: If your VHDX path has backslashes stripped (e.g., D:\WSL\__data\project.vhdx becomes D:WSL__dataproject.vhdx), this means you used double quotes instead of single quotes in config.sh. Fix it by changing:
# Change this:
VHDX_PATH="D:\WSL\__data\project.vhdx"
# To this:
VHDX_PATH='D:\WSL\__data\project.vhdx'Then re-run ./scripts/configure-mount.sh and restart WSL.
If Chrome fails to run, install missing dependencies:
sudo apt install -y libnspr4 libnss3 libatk1.0-0 libatk-bridge2.0-0 \
libcups2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 \
libxrandr2 libgbm1 libcairo2 libpango-1.0-0 libasound2All operations are logged to setup.log:
tail -f setup.log # Follow log in real-time
less setup.log # Browse full log
grep ERROR setup.log # Find errorsEdit config.sh and add to SYSTEM_PACKAGES array:
SYSTEM_PACKAGES=(
ca-certificates
curl
git
your-package-here
)- Create new script in
scripts/directory - Add to
setup-wsl.shmain function - Make executable:
chmod +x scripts/your-script.sh
Edit config.sh before running setup:
- Source paths:
FILES_DIR,DOTFILES_DIR - Destination paths:
TARGET_HOME,CHROME_INSTALL_PATH
- Remove Sensitive Files: SSH private keys are automatically excluded by
.gitignore - Check .gitignore: Verify sensitive files are listed
- Review Changes:
git statusto see what will be committed
- ✅ Scripts (
.shfiles) - ✅ Configuration templates (
config.sh.example,.bash_aliases.example) - ✅ Mount configurations (
wsl.conf,fstab,mount__data.sh) - ✅ Claude Code settings (
dotfiles/.config/ccstatusline/settings.json) - ✅ Other config files in
dotfiles/.config/ - ✅ Directory structure (
.gitkeepfiles) - ✅ Documentation (
README.md)
- ❌ Your personal config (
config.sh) - ❌ Your personal aliases (
dotfiles/.bash_aliases) - ❌ All SSH keys and files in
dotfiles/.ssh/(except.gitkeep) - ❌
.envfiles - ❌ Log files (
*.log) - ❌ Backup files (
*.backup.*)
.ssh/: Directory is tracked (via.gitkeep), but ALL files inside are ignored for security.config/: Files can be committed (like Claude Code settings).bash_aliases: Ignored (use.bash_aliases.exampleas template)
# Navigate to the script directory
cd ~/wsl-setup-script
# Initialize git repository (if not already a git repo)
git init
# Add all files (respects .gitignore)
git add .
# Check what will be committed
git status
# Commit
git commit -m "Initial WSL setup scripts"
# Add remote and push
git remote add origin <your-repo-url>
git push -u origin mainCurrently not implemented, but you can check what will be installed:
# View package lists
cat config.sh | grep -A 20 "SYSTEM_PACKAGES"
cat config.sh | grep -A 20 "CHROME_DEPENDENCIES"
# View what files will be copied
ls -la files/
ls -la dotfiles/Create a local-config.sh (not tracked by git):
# local-config.sh
source ./config.sh
# Override settings
TARGET_USER="your-username"
CHROME_INSTALL_PATH="/opt/chrome"Then use it:
source ./local-config.sh && ./scripts/install-packages.shSkip steps by commenting out in setup-wsl.sh:
# Comment out steps you don't need
# run_script "scripts/install-packages.sh"
run_script "scripts/configure-mount.sh"
run_script "scripts/setup-dotfiles.sh"- Windows 10/11 with WSL2
- Debian or Ubuntu distribution in WSL
- Internet connection
- Sudo privileges
Tested on:
- ✅ Debian (latest)
- ✅ Ubuntu 22.04 LTS
- ✅ Ubuntu 20.04 LTS
This setup script is provided as-is for personal use.
To add improvements:
- Test changes thoroughly
- Update documentation
- Ensure idempotent behavior
- Add logging for new operations
For issues or questions:
- Check
setup.logfor errors - Review troubleshooting section
- Verify
config.shsettings - Test individual scripts
- Initial release
- Modular script architecture
- Automated package installation
- Mount configuration
- Dotfiles management
- Comprehensive documentation
Created for automating WSL development environment setup with support for:
- Docker containerization
- Node.js/Bun JavaScript runtimes
- Chrome for Testing (Puppeteer)
- Claude Code AI assistant
- Tailscale networking