Setting up a state Windows laptop
TODO: extract the non-Windows development instructions (like zsh, python, nvm, AWS CLI setup) into shared setup documentation
Or: “How I Got npm install to Work on My State-Issued Dell Laptop”
If you’re a developer who’s been handed a Windows machine from your organization and you’re staring at PowerShell wondering how you’re going to get your Node.js projects running, this guide is for you. We’ve all been there—trying to run npm install only to be greeted by cryptic SSL certificate errors thanks to corporate network security tools like Zscaler.
This is a practical, battle-tested guide for setting up a modern Windows development environment using Windows Subsystem for Linux (WSL2), Windows Terminal, and Visual Studio Code. We recommend WSL2 over Git Bash for full Linux-kernel compatibility, better package management, and smoother tool integration. Why WSL2? Because it provides a complete Linux kernel running inside Windows, which means native Linux performance for development tools, better compatibility with the Node.js/Deno ecosystem, and easier package management with apt.
Quick reality check: Developing on Windows used to be painful, but it doesn’t have to be anymore. With the right setup, you’ll have a development environment that rivals macOS and Linux systems—all while keeping your familiar Windows desktop experience.
Prerequisites
Section titled “Prerequisites”Before we dive in, let’s make sure you have everything you need. Don’t worry if some of these sound intimidating — we’ll walk through each step:
- A stable internet connection for downloading packages and updates (this setup involves quite a bit of downloading)
- Windows 11, fully updated (check your version by pressing
Windows + R, typingwinver, and hitting Enter) - Administrator access to enable Windows features (if you’re on a corporate machine, you might need to request this from IT)
- About 30-60 minutes of focused time to complete the setup
- A cup of coffee ☕ (optional but recommended)
State laptop users: If you’re working on a state or corporate-issued machine with network security tools (like Zscaler), don’t panic when things don’t work immediately. We’ve got specific instructions for dealing with those challenges.
1. Windows Terminal: your new command line home
Section titled “1. Windows Terminal: your new command line home”The default Windows Command Prompt and even PowerShell are… well, let’s say they weren’t designed with developers in mind. Windows Terminal, however, is a modern, feature-rich terminal application that Microsoft actually got right. It supports multiple tabs, themes, and profiles—think of it as the terminal experience you’ve been missing on Windows.
Installing Windows Terminal
Section titled “Installing Windows Terminal”The easiest way is through Windows’ built-in package manager. Why use a package manager? Package managers like winget (for Windows) and apt (for Linux) automatically handle software downloads, installations, updates, and dependency management. This means:
- Security: Software comes from verified repositories rather than random websites
- Updates: Straightforward to update all your software with a single command
- Consistency: Standardized installation process across different tools
- Reliability: No need to hunt for the “real” download link among ads and fake buttons
Open PowerShell as Administrator (press Windows + X and select “Windows PowerShell (Admin)” or “Terminal (Admin)”) and run:
winget install -e --id Microsoft.WindowsTerminalCan’t access the Microsoft Store? If you’re on a corporate network that blocks the Microsoft Store, you can download Windows Terminal directly from its GitHub releases page. Look for the .zip file rather than the .msixbundle to bypass store restrictions.
Once installed, you’ll want to make it your default terminal application. We’ll configure it with your new Ubuntu environment in the next steps.
2. Install and configure WSL2: your Linux environment
Section titled “2. Install and configure WSL2: your Linux environment”This is where the magic happens. We’re going to install a full Linux environment that runs seamlessly inside Windows. Think of it as having the best of both worlds—Windows for your familiar desktop experience and Linux for your development tools.
Enable Required Windows Features
Section titled “Enable Required Windows Features”First, we need to tell Windows to enable the subsystem for Linux and virtual machine capabilities. Open Windows PowerShell as Administrator (this is crucial — regular PowerShell won’t work) and run these commands:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestartdism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestartWhat’s happening here? These commands enable two Windows features: the Windows Subsystem for Linux (WSL) and the Virtual Machine Platform that WSL2 needs to run efficiently. The /norestart flag means we’ll restart once after both features are enabled rather than restarting twice.
Restart your computer now. Yes, really. This is one of those times where the restart is actually necessary for the features to work properly.
Install Ubuntu
Section titled “Install Ubuntu”After your computer restarts, open PowerShell as Administrator again and run:
wsl --set-default-version 2wsl --installWhat’s happening here? The first command tells WSL that any new Linux distributions should use WSL2 (the newer, better version). The second command downloads and installs Ubuntu, the default Linux distribution for WSL2.
Initial Ubuntu setup
Section titled “Initial Ubuntu setup”When Ubuntu launches for the first time, it will ask you to create a username and password. This is important:
- Username: Choose a lowercase username with no spaces (it can be different from your Windows username). Write it down — it’s very difficult to change later.
- Password: Create a strong password (it can be different from your Windows password). You’ll need this for sudo commands. Write this down too.
Pro tip: This Ubuntu user will have full administrator rights within the Linux environment, so choose a password you’ll remember but that’s still secure.
3. Understanding dotfiles
Section titled “3. Understanding dotfiles”Before we start installing packages and configuring your environment, let’s take a moment to understand dotfiles—they’re crucial to how Linux (and your development environment) works, and you’ll encounter them throughout this guide.
What Are Dotfiles?
Section titled “What Are Dotfiles?”Dotfiles are configuration files that start with a dot (.) character. In Unix-like systems (including your new Ubuntu environment), files that start with a dot are hidden by default. They’re used to store configuration settings for various programs and your shell environment.
Why are they hidden? Back in the early days of Unix, this was a straightforward way to keep configuration files out of the way during normal file browsing. The convention stuck, and now most Linux/Unix programs store their configuration in dotfiles in your home directory (~/).
Common dotfiles you’ll encounter
Section titled “Common dotfiles you’ll encounter”.bashrc: Configuration for your Bash shell (runs every time you open a terminal).gitignore: Tells Git which files to ignore in your projects.ssh/config: Configuration for SSH connections.vimrc: Configuration for the Vim text editor.profile: General shell configuration that runs once when you log in
How to Work with Dotfiles
Section titled “How to Work with Dotfiles”To see hidden files (including dotfiles) in your terminal:
ls -laTo edit a dotfile, you can use any text editor:
nano ~/.bashrc # Edit with nano (beginner-friendly)vim ~/.bashrc # Edit with vim (more advanced)code ~/.bashrc # Edit with VS Code (after we install it)Important: Some dotfiles get automatically loaded when you start your terminal or log in. After editing .bashrc, for example, you need to either restart your terminal or run source ~/.bashrc to apply the changes.
Why This Matters
Section titled “Why This Matters”Throughout this guide, we’ll be creating and editing several dotfiles to customize your development environment. Understanding how they work will help you troubleshoot issues and personalize your setup. Don’t worry if it seems abstract now—it’ll make more sense as we use them!
4. Essential Linux Packages
Section titled “4. Essential Linux Packages”Now for the fun part—installing all the development tools you’ll need. Think of this as setting up your Linux toolbox with all the essential utilities.
In your WSL (Ubuntu) terminal, run:
# First, update the package lists to get the latest versionssudo apt update
# Install essential development toolssudo apt install -y \ curl wget git build-essential ca-certificates \ software-properties-common apt-transport-https \ gnupg lsb-release unzip zip tree jq htop \ vim nano gh python3-pip python3-venv python3-requests zshWhat did we install? Let’s break down the most important ones:
- curl & wget: Tools for downloading files from the internet
- git: Version control (you probably knew this one)
- build-essential: Compilers and tools needed to build software from source
- gh: GitHub’s official command-line tool
- tree: Displays directory structures in a tree format (surprisingly useful)
- jq: Command-line JSON processor (invaluable for API work)
- htop: A better version of the top command for monitoring system processes
- vim & nano: Text editors (nano is more beginner-friendly)
- python3-pip: Python package installer
- python3-venv: Python virtual environment support
- python3-requests: Python HTTP request library
- zsh: A more powerful shell than bash (we’ll configure this next)
Again, why apt? Like winget on Windows, apt is Ubuntu’s package manager. It ensures you get software from trusted repositories, handles dependencies automatically, and makes updates straightforward. This is much safer and more reliable than downloading random .deb files from websites.
This might take a few minutes to complete, especially on a fresh Ubuntu installation.
Verify it worked:
# Test that essential tools are installedgit --versioncurl --versiongh --versionpython3 --versionzsh --version
# All commands should return version numbers without errors5. Switching to zsh: a better shell experience
Section titled “5. Switching to zsh: a better shell experience”While bash is the default shell on Ubuntu, we’ll switch to zsh (Z shell) for a more powerful and user-friendly experience. Zsh offers better autocompletion, command history, and customization options.
Installing and Configuring Zsh
Section titled “Installing and Configuring Zsh”# Change your default shell to zshchsh -s $(which zsh)
# Log out and back in (or restart your terminal) for the change to take effect# When you first run zsh, it will ask about configuration - choose option 2 to create a basic .zshrcWhy zsh? Zsh provides:
- Better tab completion: More intelligent suggestions for commands and file paths
- Improved history: Better command history search and sharing between sessions
- Powerful customization: Themes, plugins, and extensive configuration options
- Modern features: Directory navigation shortcuts, spell correction, and more
Note: From this point forward, all shell configuration will use .zshrc instead of .bashrc. If you’ve already customized .bashrc, you can copy those settings to your new .zshrc file.
Verify it worked: Close and reopen your terminal. You should see a zsh prompt instead of the bash prompt.
6. The dreaded Zscaler certificate (corporate network users)
Section titled “6. The dreaded Zscaler certificate (corporate network users)”Ah, the infamous SSL certificate error. If you’re on a corporate or state-issued laptop, you’ve probably already encountered this beast:
SSL Error: unable to get local issuer certificateThis error has tormented developers at the Office for years, but don’t despair! The problem is that OIT’s network security tool (Zscaler) intercepts and decrypts all HTTPS traffic to scan it for security threats. While this keeps the network secure, it means that development tools like npm, pip, AWS CLI tools, and Azure CLI tools don’t trust the connection because they don’t recognize Zscaler’s certificate.
The solution: We need to tell your Linux environment to trust the Zscaler root certificate.
Installing the Zscaler Certificate
Section titled “Installing the Zscaler Certificate”-
Get the certificate file: Download the ZScaler CA certificate from Slack to your Downloads folder on Windows.
-
Copy it to the certificate directory:
cd /mnt/c/Users/<your_windows_username>/Downloadssudo cp node_awscli_zscaler_ca.crt /usr/local/share/ca-certificates/zscaler.crt- Update the certificate store:
sudo update-ca-certificates- Verify it worked:
sudo update-ca-certificates --freshYou should see output indicating that certificates were processed, including your Zscaler certificate.
What’s happening here? We’re adding Zscaler’s root certificate to Ubuntu’s trusted certificate store. This tells all your development tools, “Hey, it’s okay to trust connections that have been intercepted and re-encrypted by Zscaler.”
Test it: Try running curl -I https://innovation.nj.gov to see if HTTPS connections work without certificate errors.
Configuring Python/pip for Zscaler
Section titled “Configuring Python/pip for Zscaler”Python and pip also need to be configured to work with the Zscaler certificate. Add these configurations:
# Configure pip to use the system certificate store. Copy everything below and run it in one gomkdir -p ~/.config/pipcat > ~/.config/pip/pip.conf << 'EOF'[global]cert = /etc/ssl/certs/ca-certificates.crttrusted-host = pypi.org pypi.python.org files.pythonhosted.orgEOF# Configure Python requests library". Copy everything below and run it in one gocat >> ~/.zshrc << 'EOF'
# Python SSL configuration for Zscalerexport REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crtexport SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crtexport CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
EOFReload your .zshrc to apply the changes: source ~/.zshrc
Test Python/pip: Try installing a straightforward package to verify SSL connections work:
python3 -c "import requests; print(requests.get('https://ipinfo.io/ip').text)"You should see your public IP address if everything is working correctly.
7. Installing Node.js with NVM and configuring it for Zscaler
Section titled “7. Installing Node.js with NVM and configuring it for Zscaler”For Node.js development, we’ll use NVM (Node Version Manager) to install and manage Node.js versions. This is essential because different projects often require different Node.js versions.
Installing NVM
Section titled “Installing NVM”# Download and install NVMwget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# Reload your shell configuration to make nvm availablesource ~/.zshrc
# Verify NVM installationnvm --versionNote: If nvm command is not found, restart your terminal or run source ~/.zshrc.
Installing Node.js# Install the latest LTS (Long Term Support) version of Node.jsnvm install --lts
# Use the LTS version as defaultnvm use --lts
# Verify the installationnode --versionnpm --versionWhy NVM? Different projects often require different Node.js versions. NVM lets you switch between versions easily.
Configuring Node.js for Zscaler
Section titled “Configuring Node.js for Zscaler”Run the following commands to get Node.js set up to work with Zscaler in WSL:
# Configure Node's SSL certs. Copy everything below and run it in one gocat >> ~/.zshrc << 'EOF'
# Node SSL configuration for Zscalerexport NODE_TLS_REJECT_UNAUTHORIZED=0export NODE_EXTRA_CA_CERTS="/etc/ssl/certs/ca-certificates.crt"export NODE_OPTIONS="--use-openssl-ca"
EOFcorepack enable
yarn config set enableStrictSsl false -HReload your .zshrc to apply the changes: source ~/.zshrc
Test Node.js: Try installing a straightforward package to verify SSL connections work:
node -e "require('https').get('https://ipinfo.io/ip', res => res.on('data', d => process.stdout.write(d)))"You should see your public IP address if everything is working correctly.
8. Setting up your development environment
Section titled “8. Setting up your development environment”Now that you have a working Linux environment, let’s configure it properly for development work. This is where your environment starts to feel like home.
Git configuration
Section titled “Git configuration”First, let’s set up Git with your identity and preferences:
# Set your name and email (use your real name and email attached to GitHub)git config --global user.name "Your Name"git config --global user.email "your.email@example.com"
# Set the default branch name to 'main' (modern standard)git config --global init.defaultBranch main
# Make Git output colorful and easier to readgit config --global color.ui auto
# Set up better diff and merge toolsgit config --global core.editor "code --wait --new-window"git config --global diff.tool vscodegit config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'git config --global merge.tool vscodegit config --global mergetool.vscode.cmd 'code --wait $MERGED'Verify it worked:
# Check your Git configurationgit config --global --list | grep user# Should show your name and email
git config --global init.defaultBranch# Should show 'main'Global gitignore file
Section titled “Global gitignore file”Create a global .gitignore file to automatically ignore common files you never want to commit:
# Create the global gitignore file. Run the next three lines togethercat > ~/.gitignore << 'EOF'.aider*EOF
# Tell Git to use this global gitignore filegit config --global core.excludesfile ~/.gitignoreWhat’s this doing? This creates a global ignore file that applies to all your Git repositories. It includes common files that you never want to accidentally commit—like OS-generated files, editor temporary files, dependency directories, and environment files containing secrets. Add any additional files to this .gitignore file that wouldn’t normally be included in project-specific .gitignore files.
SSH key setup for GitHub
Section titled “SSH key setup for GitHub”While we’ll use GitHub CLI for most operations, having SSH keys set up is still useful:
# Generate a new SSH key (replace with the email linked to your GitHub account)ssh-keygen -t ed25519 -C "your.email@example.com"
# When prompted, press Enter to accept the default file location# Choose a strong passphrase when prompted
# Start the SSH agenteval "$(ssh-agent -s)"
# Add your SSH key to the agentssh-add ~/.ssh/id_ed25519
# Display your public key (you'll need to add this to GitHub)cat ~/.ssh/id_ed25519.pubCopy the output of that last command and add it to your GitHub account under Settings → SSH and GPG keys.
Verify it worked:
# Test SSH connection to GitHub (after adding key to GitHub)ssh -T git@github.com
# Should show: "Hi <yourusername>! You've successfully authenticated..."
# Sign your commitsgit config --global gpg.format sshgit config --global user.signingkey ~/.ssh/id_ed25519.pubShell customization
Section titled “Shell customization”Let’s make your shell more pleasant to use by adding some helpful aliases to your .zshrc file:
# Add useful aliases to your .zshrc . Copy everything below and run it in one gocat >> ~/.zshrc << 'EOF'
# Development aliasesalias myip='curl ipinfo.io/ip'
# Safety aliasesalias rm='rm -i'alias cp='cp -i'alias mv='mv -i'
EOFReload your .zshrc to apply the changes: source ~/.zshrc
What did we do? We added some convenient shortcuts to your shell configuration. These small conveniences add up to a much more pleasant development experience.
Creating your development directory structure
Section titled “Creating your development directory structure”Let’s create a standard directory structure for your development work:
# Create a standard development directory structuremkdir -p ~/Developercd ~/DeveloperWhy ~/Developer? This creates a consistent, easy-to-find location for all your development projects. Having a standard structure makes it easier to navigate between projects and ensures good organization from the start.
Verify it worked:
# Check that the directory was createdls -la ~/Developer# You should see an empty directory9. Python virtual environments: keeping your projects clean
Section titled “9. Python virtual environments: keeping your projects clean”Let’s set up Python virtual environments. Why use virtual environments? When you install Python packages globally (with pip3 install package-name), they can conflict with each other when different projects need different versions of the same package. Virtual environments solve this by creating isolated Python installations for each project.
Creating and using virtual environments
Section titled “Creating and using virtual environments”# Navigate to your projects directory (we created this earlier)cd ~/Developer
# Create a new project directorymkdir my-python-projectcd my-python-project
# Create a virtual environment named 'venv'python3 -m venv .venv
# Activate the virtual environmentsource .venv/bin/activate
# Your prompt should now show (venv) at the beginning# Install packages only for this projectpip install requests beautifulsoup4
# When you're done working, deactivate the environmentdeactivateBest Practices for Virtual Environments
Section titled “Best Practices for Virtual Environments”- Always use virtual environments for Python projects
- Name your environment folder
.venv- it’s the standard convention - Add
.venv/to your.gitignore- never commit virtual environments to version control - Keep a
requirements.txtfile with your project dependencies:
# Generate requirements.txt from your current environmentpip freeze > requirements.txt
# Install from requirements.txt in a new environmentpip install -r requirements.txtGlobal vs. virtual environment packages
Section titled “Global vs. virtual environment packages”Install globally only for system tools:
# These are tools you want available everywherepip3 install --user aider-install # AI assistantpip3 install --user black # Python code formatterInstall in virtual environments for project dependencies:
# Create a virtual environmentpython3 -m venv .venv
# Activate your project's virtual environment firstsource .venv/bin/activate
# Then install project-specific packagespip install -r requirements.txtpip install django flask requestspip freeze > requirements.txtWhy this matters: This approach prevents dependency conflicts, makes your projects reproducible, and keeps your system Python installation clean.
10. Docker CLI: container management without Docker Desktop (optional)
Section titled “10. Docker CLI: container management without Docker Desktop (optional)”For containerized development, we’ll install the Docker CLI without Docker Desktop. This gives you access to Docker commands while keeping your system lightweight.
Installing Docker CLI
Section titled “Installing Docker CLI”# Remove conflicting packagesfor pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
# Install the docker engine. It'll yell at you about Docker Desktop. Just wait 20 seconds and it'll continue installation.curl -fsSL https://get.docker.com | sh
# Install Docker Composesudo apt install -y docker-compose-plugin
# Add your user to the Docker group (replacing with your Ubuntu username)sudo usermod -a -G docker yourusernameWhy Docker CLI without Docker Desktop? This approach:
- Reduces resource usage: No heavy Docker Desktop GUI application, which requires a license
- Maintains compatibility: Full Docker CLI functionality for building and managing containers
- Enables remote Docker: Can connect to remote Docker hosts or services like AWS ECS
Verify it worked:
# Check Docker CLI installationdocker --versiondocker compose version
# These should show version information11. AWS CLI: cloud development essentials
Section titled “11. AWS CLI: cloud development essentials”The AWS CLI is essential for cloud development. Let’s install it and configure it to work with multiple AWS accounts and profiles.
Installing AWS CLI
Section titled “Installing AWS CLI”# Install AWS CLI v2curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"unzip awscliv2.zipsudo ./aws/install
# Clean up installation filesrm -rf awscliv2.zip aws/Verify the installation:
aws --version# Should show AWS CLI version 2.xConfiguring AWS CLI for Multiple ProfilesAWS profiles allow you to manage multiple AWS accounts or environments (dev, staging, prod):
# Configure your default profileaws configure
# Configure additional profilesaws configure --profile developmentaws configure --profile stagingaws configure --profile productionFor each profile, you’ll need to provide:
- Access Key ID: From your AWS IAM user
- Secret Access Key: From your AWS IAM user
- Default region: e.g., us-east-1
- Default output format: json is recommended
Managing AWS Profiles
Section titled “Managing AWS Profiles”# List all configured profilesaws configure list-profiles
# Use a specific profile for a commandaws s3 ls --profile development
# Set a default profile for your sessionexport AWS_PROFILE=development
# View current configurationaws configure listSetting up AWS CLI with Zscaler certificate
Section titled “Setting up AWS CLI with Zscaler certificate”Configure AWS CLI to work with the Zscaler certificate:
# Add AWS certificate configuration to your shellcat >> ~/.zshrc << 'EOF'
# AWS CLI configuration for Zscalerexport AWS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
EOF
# Reload your configurationsource ~/.zshrcVerify AWS CLI works:
# Test basic AWS connectivity (replace with your profile)aws sts get-caller-identity
# Should return your AWS account information (press q to exit)Managing Multiple Accounts: Create a profile for each AWS account you work with:
# Example: different profiles for different purposesaws configure --profile personal-devaws configure --profile work-stagingaws configure --profile work-production12. GitHub authentication: essential for development
Section titled “12. GitHub authentication: essential for development”Before we continue, let’s authenticate with GitHub since you’ll need this for most development work.
Set up GitHub CLI for seamless repository management:
# Start the GitHub authentication processgh auth loginFollow the prompts:
- Choose “GitHub.com” as your server
- Choose “HTTPS” as your preferred protocol
- Choose “Yes” to authenticate Git with GitHub credentials
- Choose “Login with a web browser” for authentication
The CLI will display a one-time code. Open your web browser to the address provided (WSL will not be able to open your browser for you), log into GitHub, and enter the code to complete authentication.
Verify it worked:
gh auth statusWhy is this essential? GitHub CLI provides:
- Seamless authentication for Git operations
- Repository management from the command line
- Pull request and issue management without leaving your terminal
- Integration with other tools that need GitHub access
13. Installing the Aider CLI
Section titled “13. Installing the Aider CLI”If you’re part of the Aider AI assistant pilot program, you can now install it:
python3 -m pip install aider-installVerify the installation:
aider --helpWhat is Aider? Aider is an AI-powered coding assistant that can help you write and edit code directly in your terminal. It’s particularly useful for code refactoring, bug fixes, and implementing new features. Talk to the tech ops team if you’d like to join this pilot.
14. Understanding the file system: where your code lives
Section titled “14. Understanding the file system: where your code lives”One of the most confusing aspects of WSL for newcomers is understanding where files live and how to access them. Let’s clear this up once and for all.
The Two File Systems
Section titled “The Two File Systems”You’re now working with two file systems:
- Your Windows file system:
C:\,D:\, etc. - Your Linux file system:
/home/yourusername/,/etc/,/var/, etc.
Where should you store your code?
Section titled “Where should you store your code?”Short answer: In your Linux home directory (/home/<yourusername>/Developer otherwise known as ~/Developer or $HOME/Developer).
Why? For best performance and full Linux file system compatibility, store and edit your project files in your Linux home directory rather than on Windows drives. Here’s why:
- Performance: Files in the Linux filesystem are much faster to access from Linux tools
- Compatibility: Some Linux tools expect Unix-style file permissions and attributes
- No weird Windows/Linux path translation issues
Path Translation Guide
Section titled “Path Translation Guide”- Linux files: Live under
/home/<yourusername>/(or~/as a shortcut) - Windows drives: Are mounted at
/mnt/c/,/mnt/d/, etc. - From Windows: Your Linux files appear at
\\wsl$\Ubuntu\home\<yourusername>\
Accessing Files Between Systems
Section titled “Accessing Files Between Systems”From Linux, Open Windows Explorer
Section titled “From Linux, Open Windows Explorer”# Open the current Linux directory in Windows File Explorerexplorer.exe .
# Open a specific directoryexplorer.exe ~/DeveloperFrom Windows, Access Linux Files
Section titled “From Windows, Access Linux Files”In File Explorer, navigate to: \\wsl$\Ubuntu\home\<yourusername>\
Pro tip: You can bookmark this location in Windows File Explorer for quick access.
15. VSCode Integration: The Best of Both Worlds
Section titled “15. VSCode Integration: The Best of Both Worlds”Visual Studio Code is the secret sauce that makes Windows development with WSL truly shine. It bridges the gap between your familiar Windows desktop and your powerful Linux development environment.
With the Remote – WSL extension, you get:
- Edit and debug code directly inside your Linux environment
- Run terminal commands and view output seamlessly within VS Code
- Leverage Windows apps (like your web browser) alongside Linux development tools
- Full IntelliSense and extension support that works with your Linux environment
Installing VSCode
Section titled “Installing VSCode”Install VSCode on your Windows system:
# From PowerShell (as Administrator)winget install -e --id Microsoft.VisualStudioCodeAlternatively, you can download it directly from code.visualstudio.com. However, we strongly recommend using package managers like winget and apt because they:
- Simplify updates: One command updates all your software instead of checking each program individually
- Handle dependencies: Automatically install required components
- Provide security: Software comes from verified repositories
- Save time: No hunting through websites for the correct download link
- Ensure consistency: Standardized installation process across your entire system
Setting Up WSL Integration
Section titled “Setting Up WSL Integration”- Open a project in WSL: From your WSL terminal, navigate to any project directory and run:
cd ~/Developercode .
# That's the equivalent of:code ~/Developer-
First-time setup: VSCode will automatically detect WSL and offer to install the “Remote - WSL” extension. Click “Install” when prompted.
-
Verify the connection: Look at the bottom-left corner of VS Code. You should see “WSL: Ubuntu” in green, indicating you’re connected to your Linux environment.
Why This Setup is Magical
Section titled “Why This Setup is Magical”- Files: You’re editing files that live in Linux, but using the familiar VSCode interface
- Terminal: The integrated terminal runs zsh in your Linux environment
- Extensions: Most VS Code extensions work seamlessly in the WSL environment
- Performance: Everything runs at native Linux speed because the code execution happens in Linux
Essential VSCode Extensions for Development
Section titled “Essential VSCode Extensions for Development”Once you have VSCode connected to WSL, consider installing these extensions:
- GitLens: Enhanced Git capabilities
- Prettier: Code formatting
- Thunder Client: API testing (alternative to Postman)
Pro tip: Extensions installed in WSL are separate from extensions in regular Windows VS Code. This is actually a good thing—it keeps your development environment clean and specific to your Linux setup.
16. Configuring Windows Terminal
Section titled “16. Configuring Windows Terminal”Remember Windows Terminal that we installed at the beginning? Now it’s time to configure it properly so it becomes your primary development interface.
Setting Ubuntu as Default
Section titled “Setting Ubuntu as Default”-
Open Windows Terminal settings: Click the dropdown arrow next to the ”+” tab button and select “Settings”
-
Set Ubuntu as default:
- In the left sidebar, click “Startup”
- Under “Default profile”, select “Ubuntu”
- Under “Default terminal application”, select “Windows Terminal”
- Customize your Ubuntu profile:
- In the left sidebar, under “Profiles”, click “Ubuntu”
- Here you can customize:
- Font: We recommend “Cascadia Code” or “Fira Code” for better coding experience
- Color scheme: Try “Campbell Powershell” or “Solarized Dark”
- Starting directory: Set to
~
- Save your settings: Click “Save” at the bottom
Pro tip: You can create custom key bindings, set background images, and even adjust transparency. Windows Terminal is surprisingly customizable once you dig into the settings!
17. Quality of life tools
Section titled “17. Quality of life tools”These aren’t strictly necessary, but they’ll make your Windows development experience much more pleasant:
Essential Windows tools
Section titled “Essential Windows tools”-
PowerToys: A collection of Windows utilities that add functionality Microsoft should have included by default. Particularly useful features:
- PowerToys Run: Launch applications and files quickly (like macOS Spotlight)
- FancyZones: Snap windows into custom layouts
- File Locksmith: See what’s using a locked file
-
ScreenToGif: Lightweight screen recorder perfect for creating quick demos or bug reports. Great for sharing your work with team members.
Oh My Zsh (enhanced shell experience)
Section titled “Oh My Zsh (enhanced shell experience)”For an even better zsh experience, install Oh My Zsh, a popular framework for managing zsh configuration:
# Install Oh My Zshsh -c "$(wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh -O -)"Oh My Zsh provides themes, plugins, and sensible defaults that make zsh even more powerful out of the box. It includes features like:
- Git integration: Shows branch info and status in your prompt
- Command aliases: Hundreds of useful shortcuts
- Auto-completion: Intelligent tab completion for many tools
- Themes: Beautiful, informative prompts
Verify it worked: Your prompt should change to a more colorful, informative display showing your current directory and git status.
Environment variables for development
Section titled “Environment variables for development”Add commonly needed environment variables to your ~/.zshrc:
# Development environment variablesexport EDITOR=codeexport BROWSER=explorer.exeexport NODE_ENV=development
# Add local bin to PATH for global npm packagesexport PATH="$HOME/.local/bin:$PATH"Troubleshooting Common Issues
Section titled “Troubleshooting Common Issues””Windows Subsystem for Linux has no installed distributions”
Section titled “”Windows Subsystem for Linux has no installed distributions””Problem: You get this error when trying to run wsl commands.
Solution:
wsl --install -d UbuntuIf that doesn’t work, try installing Ubuntu manually from the Microsoft Store.
VSCode can’t connect to WSL
Section titled “VSCode can’t connect to WSL”Problem: VSCode shows connection errors or doesn’t detect WSL.
Solutions:
- Restart both VSCode and your WSL terminal
- Uninstall and reinstall the “Remote - WSL” extension
- Run
code --list-extensions --show-versionsin WSL to verify extensions are installed
Permission denied errors
Section titled “Permission denied errors”Problem: Getting permission errors when trying to install packages or access files.
Solutions:
- Use
sudofor system-level operations:sudo apt install packagename - Check file ownership:
ls -la filename - Fix ownership if needed:
sudo chown username:username filename
npm/pip still showing certificate errors
Section titled “npm/pip still showing certificate errors”Problem: Even after installing the Zscaler certificate, you’re still getting SSL errors.
Solutions:
- Verify the certificate is installed:
ls -la /usr/local/share/ca-certificates/ - Re-run the update command:
sudo update-ca-certificates --fresh - Restart your terminal session
- For npm specifically, you might need to set the certificate path explicitly:
npm config set cafile /etc/ssl/certs/ca-certificates.crtSlow file performance
Section titled “Slow file performance”Problem: File operations are slow, especially with large projects.
Solutions:
- Store your projects in the Linux filesystem (
~/Developer) rather than Windows drives (/mnt/c/) - Disable Windows Defender real-time protection for your WSL directories
- Consider using the WSL 2 performance tuning guide