Skip to main content

Quick Start

For the fastest development setup:
  1. Clone the repository with submodules:
    git clone https://github.com/mullvad/mullvadvpn-app.git
    cd mullvadvpn-app
    git submodule update --init
    git submodule update --init wireguard-go-rs/libwg/wireguard-go
    
  2. Install Rust and setup for your platform:
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    ./scripts/setup-rust linux  # or macos, windows, android, ios
    
  3. Install Node.js/npm via Volta and build dependencies:
    # Install volta first, then:
    cd desktop
    npm install -w mullvad-vpn
    
  4. Start developing!

Detailed Setup by Platform

Linux Development

Ubuntu/Debian

# System dependencies
sudo apt update
sudo apt install gcc libdbus-1-dev protobuf-compiler libprotobuf-dev rpm curl

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

# Install Volta for Node.js
curl https://get.volta.sh | bash
source ~/.bashrc

# Install Go
wget https://go.dev/dl/go1.21.0.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin

# Clone and setup
git clone https://github.com/mullvad/mullvadvpn-app.git
cd mullvadvpn-app
git submodule update --init
git submodule update --init wireguard-go-rs/libwg/wireguard-go
./scripts/setup-rust linux

# Install Node dependencies
cd desktop
npm install -w mullvad-vpn
cd ..

Fedora/RHEL

# System dependencies
sudo dnf install gcc dbus-devel protobuf protobuf-devel rpm-build curl

# Follow same steps as Ubuntu/Debian for Rust, Volta, Go, and repository setup

Nix Devshell

The recommended approach on Linux:
# Install Nix
sh <(curl -L https://nixos.org/nix/install) --daemon

# Enable flakes (add to ~/.config/nix/nix.conf or /etc/nix/nix.conf)
echo "experimental-features = nix-command flakes" | sudo tee -a /etc/nix/nix.conf

# Enter devshell
cd mullvadvpn-app
nix develop

# Optional: Use direnv for automatic environment activation
sudo apt install direnv  # or dnf install direnv
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
source ~/.bashrc
direnv allow .

macOS Development

# Install Homebrew if not already installed
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Install required tools
brew install bash volta [email protected] protobuf

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

# Volta setup
volta setup

# Clone repository
git clone https://github.com/mullvad/mullvadvpn-app.git
cd mullvadvpn-app
git submodule update --init
git submodule update --init wireguard-go-rs/libwg/wireguard-go

# Setup Rust targets
./scripts/setup-rust macos

# Install Node dependencies
cd desktop
npm install -w mullvad-vpn
cd ..
Important: The default macOS bash (3.2.5) is too old. Make sure to use bash 4.0+ installed via Homebrew.

iOS Development Setup

Additional iOS requirements:
# Install iOS-specific Rust targets
./scripts/setup-rust ios

# Checkout iOS submodule
git submodule update --init --recursive ios/wireguard-apple

# Configure Xcode project
cd ios
for file in ./Configurations/*.template ; do cp $file ${file//.template/} ; done
Edit the .xcconfig files to add your Apple Developer Team ID and provisioning profile names.

Windows Development

Prerequisites Installation

  1. Install Visual Studio 2022
  2. Install Git for Windows
    • Download from git-scm.com
    • This provides Git Bash and Unix utilities
  3. Install Rust
    # In PowerShell
    Invoke-WebRequest -Uri https://win.rustup.rs/x86_64 -OutFile rustup-init.exe
    .\rustup-init.exe
    
  4. Install Zig
  5. Install Volta
  6. Install Go
    • Download installer from golang.org
    • Run installer
  7. Install Protobuf

Setup in Git Bash

# Clone repository
git clone https://github.com/mullvad/mullvadvpn-app.git
cd mullvadvpn-app
git submodule update --init
git submodule update --init wireguard-go-rs/libwg/wireguard-go

# Setup Rust targets
./scripts/setup-rust windows
rustup target add i686-pc-windows-msvc

# Setup Visual Studio environment
. ./scripts/vcvars.sh

# Verify msbuild is available
which msbuild

# Install Node dependencies
cd desktop
npm install -w mullvad-vpn
cd ..

Android Development

This is the easiest and most reliable method:
# Install podman (or docker)
sudo apt install podman

# Build using container
cd mullvadvpn-app
./building/containerized-build.sh android --dev-build

Manual Setup on Linux

# Install JDK
sudo apt install zip openjdk-17-jdk

# Setup Android SDK
mkdir -p ~/android
export ANDROID_HOME=~/android
cd $ANDROID_HOME

wget https://dl.google.com/android/repository/commandlinetools-linux-13114758_latest.zip
mkdir -p cmdline-tools
unzip commandlinetools-linux-13114758_latest.zip -d cmdline-tools-latest
mv cmdline-tools-latest/cmdline-tools cmdline-tools/latest
rm -d cmdline-tools-latest

./cmdline-tools/latest/bin/sdkmanager "platforms;android-36" \
  "build-tools;36.0.0" "platform-tools" "ndk;27.3.13750724"

# Configure Rust for Android
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/27.3.13750724"
export NDK_TOOLCHAIN_DIR="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin"

# Add to ~/.bashrc
cat >> ~/.bashrc << 'EOF'
export ANDROID_HOME="$HOME/android"
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/27.3.13750724"
export NDK_TOOLCHAIN_DIR="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin"
export AR_aarch64_linux_android="$NDK_TOOLCHAIN_DIR/llvm-ar"
export CC_aarch64_linux_android="$NDK_TOOLCHAIN_DIR/aarch64-linux-android26-clang"
export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$NDK_TOOLCHAIN_DIR/aarch64-linux-android26-clang"
# Add similar exports for armv7, x86_64, i686
EOF

source ~/.bashrc

# Install Android Rust targets
cd mullvadvpn-app
./scripts/setup-rust android
git submodule update --init android/rust-android-gradle-plugin

Development Workflow

Running the Daemon

Linux/macOS:
cargo build
sudo MULLVAD_RESOURCE_DIR="./dist-assets" ./target/debug/mullvad-daemon -vv
Windows:
# Build Windows-specific modules first
./build-windows-modules.sh
cp dist-assets/binaries/x86_64-pc-windows-msvc/wintun.dll target/debug/

# Run as SYSTEM user using PsExec
psexec64 -i -s bash.exe
MULLVAD_RESOURCE_DIR="./dist-assets" ./target/debug/mullvad-daemon -vv
macOS specific:
source env.sh  # Set macOS environment variables first

Running the Desktop GUI

With the daemon running, start the Electron app:
cd desktop
npm run -w mullvad-vpn develop
The GUI will automatically reload when you change JavaScript/TypeScript files.

Running the CLI

cargo build -p mullvad-cli
sudo ./target/debug/mullvad status

Common Development Commands

Rust:
cargo build                    # Build default workspace members
cargo build --workspace       # Build all crates
cargo test                    # Run tests
cargo clippy                  # Run linter
cargo fmt                     # Format code
Desktop/Electron:
cd desktop
npm run -w mullvad-vpn develop     # Development mode with hot reload
npm run -w mullvad-vpn lint         # Lint code
npm test                            # Run tests
npm run -w mullvad-vpn build-proto  # Build protobuf files
Android:
cd android
./build.sh --dev-build             # Debug build
./gradlew assembleOssProdDebug     # Gradle build
./gradlew test                      # Run tests

Environment Variables

Development-Specific Variables

# Use custom API endpoint
export MULLVAD_API_HOST="api.mullvad.net"
export MULLVAD_API_ADDR="10.10.1.2:443"
export MULLVAD_API_DISABLE_TLS=1

# Desktop app development
export MULLVAD_PATH="/path/to/mullvad-problem-report"
export MULLVAD_DISABLE_UPDATE_NOTIFICATION=1

# Override directories
export MULLVAD_SETTINGS_DIR="/tmp/mullvad-settings"
export MULLVAD_LOG_DIR="/tmp/mullvad-logs"
export MULLVAD_CACHE_DIR="/tmp/mullvad-cache"
See the full list of environment variables in the README.

Editor/IDE Setup

VS Code

Recommended extensions:
  • rust-analyzer
  • ESLint
  • Prettier
  • TypeScript and JavaScript Language Features

IntelliJ/Android Studio

For Android development, open the android/ directory as a project.

Xcode

For iOS development, open ios/MullvadVPN.xcodeproj.

Git Workflow

Post-Checkout Hook

Automatically update Rust toolchain when version changes:
./scripts/setup-rust install-hook

Submodule Updates

When pulling changes that update submodules:
git pull
git submodule update --init

Commit Signing

All merge commits to main must be GPG signed. Individual commits in feature branches don’t require signing unless they modify security-critical files.

Troubleshooting

”command not found” errors

Ensure all tools are in your PATH:
which rustc cargo go node npm protoc

Rust toolchain issues

rustup update
./scripts/setup-rust <platform>

Node/npm version issues

volta install [email protected]
volta install [email protected]

Permission denied when running daemon

The daemon must run as root/SYSTEM:
  • Linux/macOS: Use sudo
  • Windows: Use PsExec to get SYSTEM shell

Submodule not found

git submodule update --init --recursive

Build fails with “protoc: not found”

Install protobuf compiler and ensure it’s in PATH:
# Linux
sudo apt install protobuf-compiler

# macOS
brew install protobuf

# Verify
protoc --version

Android build fails on ARM64 Linux

Follow the 2-stage build process described in the Building guide - build proto files on x64 first.

macOS: bash version too old

brew install bash
which bash  # Should show /opt/homebrew/bin/bash or similar
bash --version  # Should be 4.0+

Next Steps

Build docs developers (and LLMs) love