This guide provides a step-by-step process for setting up a comprehensive development environment on Ubuntu, tailored for beginner developers. It covers everything from installing the operating system to configuring essential tools, programming languages, IDEs, and utilities, ensuring a robust setup for software development.
✅ Suitable for Ubuntu 24.04 LTS and 26.04 LTS 💡 Designed for software engineers, system programmers, embedded developers, and hobbyists starting with Linux development.
- Flashing Ubuntu ISO to USB (on macOS)
- System Update
- Essential Tools Installation
- Installing Zsh and Oh My Zsh
- Modern CLI Utilities
- Git and Version Control Tools
- Generating SSH Keys
- C/C++ Development Tools
- Rust Installation and Ecosystem
- Embedded Rust Development
- STM32 Development Tools (C/C++ Toolchain)
- Python Setup
- Go Installation
- Node.js Setup
- PostgreSQL Server Setup
- pgAdmin Installation
- Neovim Configuration
- WezTerm Installation
- Installing IDEs
- API Testing Tools
- Wireshark Installation
- Docker and Docker Compose
- KVM + QEMU + libvirt Installation (Recommended)
- QEMU Installation
- VirtualBox Installation
- Rust GUI/Web Frameworks: Leptos and Tauri
- SSH Server Configuration
- nftables Firewall Configuration
- System Maintenance and Automatic Updates
diskutil list
diskutil unmountDisk /dev/diskX
sudo dd if=~/Downloads/ubuntu-24.04.2-desktop-amd64.iso of=/dev/rdiskX bs=4m status=progress
diskutil eject /dev/diskXNote: Replace
diskXwith the correct disk identifier for your USB drive, found usingdiskutil list. Using the raw device (/dev/rdiskX) is significantly faster than/dev/diskX. Be cautious, asddcan overwrite data if the wrong device is specified. GUI alternatives: balenaEtcher or the official Raspberry Pi Imager.
sudo apt update && sudo apt full-upgrade -yExplanation: Updates the package lists and upgrades all installed packages.
full-upgradealso handles changed dependencies (e.g., kernel updates), which plainupgrademay hold back.
sudo apt install -y build-essential curl wget git unzip zip jq
sudo apt install -y htop btop net-tools fastfetch
sudo apt install -y nmap tcpdump mtr-tiny traceroute
sudo apt install -y gnome-disk-utility udisks2
sudo apt install -y printer-driver-all cups cups-pdf sane xsane # Optional: printing/scanningComment: Installs core build tools (
build-essential), download/archive utilities, system monitors (htop,btop), and network diagnostics (nmap,tcpdump,mtr).btopandfastfetchare the actively maintained successors ofbpytopand the discontinuedneofetch. Printing/scanning packages are only needed on desktop machines with printers.
sudo apt install -y zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
chsh -s $(which zsh) # OptionalNote: Zsh is a powerful shell alternative to Bash. Oh My Zsh enhances it with plugins and themes. Setting Zsh as the default shell (
chsh) is optional but recommended for a better experience.
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlightingExplanation:
zsh-autosuggestionsprovides real-time command suggestions based on your history;zsh-syntax-highlightingcolorizes commands as you type, catching typos before you press Enter.
git clone --depth=1 https://github.com/romkatv/powerlevel10k ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/themes/powerlevel10kComment: Powerlevel10k is a highly customizable and fast Zsh theme. Run
p10k configureafter installation to customize its appearance. It requires a Nerd Font (see the Neovim section for font installation).
plugins=(git zsh-autosuggestions zsh-syntax-highlighting)
ZSH_THEME="powerlevel10k/powerlevel10k"sudo apt install -y ripgrep fd-find bat fzf zoxide tmux
cargo install eza # After installing Rust (see below), or: sudo apt install -y eza (Ubuntu 24.10+)Explanation: Modern replacements for classic Unix tools, widely adopted in current development workflows:
ripgrep(rg) – dramatically fastergrepthat respects.gitignore.fd-find(fdfind) – intuitive, fast alternative tofind.bat(batcat) –catwith syntax highlighting and Git integration.fzf– fuzzy finder for files, history, and processes (Ctrl+Ron steroids).zoxide– smartercdthat learns your habits (addeval "$(zoxide init zsh)"to~/.zshrc).eza– modernlsreplacement with colors, icons, and Git status.tmux– terminal multiplexer for persistent sessions.
Note: On Ubuntu, the binaries are named
fdfindandbatcatdue to naming conflicts. Add aliases to~/.zshrc:alias fd=fdfind bat=batcat.
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
git config --global core.editor nvim
git config --global init.defaultBranch main
git config --global pull.rebase trueNote: Configures Git with your identity, sets Neovim as the default editor, uses
mainas the default branch, and prefers rebase ongit pullfor a linear history.
curl https://raw.githubusercontent.com/github/gitignore/main/Global/Linux.gitignore >> ~/.gitignore
git config --global core.excludesfile ~/.gitignoresudo apt install -y tig git-delta
# lazygit — popular TUI for Git
LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | jq -r '.tag_name | ltrimstr("v")')
curl -Lo /tmp/lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz"
sudo tar -C /usr/local/bin -xzf /tmp/lazygit.tar.gz lazygit
# GitKraken — GUI client (optional)
wget https://release.gitkraken.com/linux/gitkraken-amd64.deb
sudo apt install -y ./gitkraken-amd64.debComment:
tigis a text-based Git browser,lazygitis a full-featured Git TUI, andgit-deltaprovides beautiful side-by-side diffs (addpager = deltaunder[core]in~/.gitconfig). GitKraken is an optional GUI client.gh(GitHub CLI) can be installed withsudo apt install -y gh.
ssh-keygen -t ed25519 -C "your_email@example.com"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub # Copy this to GitHub/GitLab → Settings → SSH KeysComment: Generates an ED25519 SSH key pair for secure authentication (used by GitHub, GitLab, and remote servers) and adds it to the SSH agent. Do this early — you will need it to clone private repositories.
sudo apt install -y gcc g++ gdb make cmake ninja-build pkg-config
sudo apt install -y clang clangd clang-format clang-tidy lldb
sudo apt install -y valgrind cppcheck ccache
sudo apt install -y libboost-all-dev # OptionalExplanation: Installs both major toolchains (
gcc/g++andclang), debuggers (gdb,lldb), build systems (make,cmake,ninja-build), theclangdlanguage server (used by VS Code/Neovim for code intelligence), code analysis tools (clang-tidy,valgrind,cppcheck), andccachefor faster rebuilds.libboost-all-devis optional for projects requiring the Boost library.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
. "$HOME/.cargo/env"
rustup component add rust-analyzer rust-src llvm-tools
rustc --version && cargo --versionComment: Installs Rust via
rustup, the official toolchain manager.rustfmt(formatter) andclippy(linter) are included by default with the standard profile — they are rustup components, not crates, so never install them viacargo install. Additionally:
rust-analyzer– the official language server for IDE/editor integration.rust-src– standard library sources, required forrust-analyzerandbuild-std(embedded/no_std work).llvm-tools– needed bycargo-binutilsand coverage tools.Useful toolchain commands:
rustup update(update all toolchains),rustup show(list installed toolchains/targets),rustup toolchain install nightly(add nightly for experiments).
curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bashExplanation:
cargo binstalldownloads prebuilt binaries instead of compiling every tool from source, turning multi-minutecargo installruns into seconds. All tools below can be installed with eithercargo installor the much fastercargo binstall.
cargo binstall -y cargo-nextest cargo-edit cargo-expand bacon
cargo binstall -y cargo-audit cargo-deny cargo-machete
cargo binstall -y cargo-llvm-cov cargo-generateExplanation:
cargo-nextest– next-generation test runner, significantly faster thancargo testwith better output.cargo-edit– providescargo upgradefor bumping dependency versions (cargo add/cargo removeare built into cargo since 1.62).cargo-expand– expands macros and shows the generated Rust code.bacon– background code checker that re-runscheck/clippy/teston file save (the actively maintained successor tocargo-watch, which is deprecated).cargo-audit– scansCargo.lockfor crates with known security vulnerabilities.cargo-deny– enforces license, source, and advisory policies across the dependency tree.cargo-machete– finds unused dependencies inCargo.toml.cargo-llvm-cov– source-based code coverage.cargo-generate– scaffolds new projects from templates (essential for embedded quickstarts).
sudo apt install -y mold clang
cargo binstall -y sccacheAdd to ~/.cargo/config.toml:
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
[build]
rustc-wrapper = "sccache"Comment:
moldis a drop-in linker that is many times faster than the defaultld, noticeably speeding up incremental builds of large projects.sccachecaches compilation artifacts across projects.
sudo apt install -y gdb lldbNote:
rust-gdbandrust-lldb(installed with the toolchain) wrap the system debuggers with Rust pretty-printers. In VS Code, install the CodeLLDB extension for a first-class Rust debugging experience; in Neovim, usenvim-dapwithcodelldb. For CLI-first debugging,gdb -tuiorlldbwork directly ontarget/debug/binaries.
# Cortex-M targets — pick the ones matching your chips:
rustup target add thumbv6m-none-eabi # Cortex-M0/M0+ (e.g., STM32F0, RP2040)
rustup target add thumbv7m-none-eabi # Cortex-M3 (e.g., STM32F1)
rustup target add thumbv7em-none-eabi # Cortex-M4/M7 without FPU
rustup target add thumbv7em-none-eabihf # Cortex-M4F/M7F with FPU (STM32F4/F7/H7)
rustup target add thumbv8m.main-none-eabihf # Cortex-M33 (e.g., STM32L5/U5, nRF9160)
rustup target add riscv32imac-unknown-none-elf # RISC-V MCUs (e.g., ESP32-C6, GD32V)Comment: For STM32F4xx use
thumbv7em-none-eabihf. Modern embedded Rust is built around the async Embassy framework and thestm32f4xx-hal/embedded-halecosystem — both work with the targets above.
# Modern flashing and debugging toolset (includes cargo-flash and cargo-embed)
cargo binstall -y probe-rs-tools
# Convenient wrappers around llvm binutils (cargo size, cargo objdump, etc.)
cargo binstall -y cargo-binutils
# Stack overflow protection for embedded programs
cargo binstall -y flip-linkExplanation:
probe-rs-tools– flashing, debugging, and erasing microcontrollers using a wide range of debug probes (ST-Link, J-Link, CMSIS-DAP). It ships theprobe-rs,cargo-flash, andcargo-embedbinaries in one package — do not installcargo-flash/cargo-embedseparately, and it replaces OpenOCD in most Rust workflows.cargo-binutils– providescargo size,cargo objdump,cargo nmfor analyzing firmware binaries (requires thellvm-toolsrustup component installed above).flip-link– zero-cost stack overflow protection by placing the stack at the end of RAM.
sudo curl -L https://probe.rs/files/69-probe-rs.rules -o /etc/udev/rules.d/69-probe-rs.rules
sudo udevadm control --reload
sudo udevadm trigger
sudo usermod -aG dialout $USER # For USB-serial adapters; re-login to applyNote: Without the udev rules,
probe-rscan only access debug probes as root. Thedialoutgroup grants access to/dev/ttyUSB*//dev/ttyACM*serial ports.
# Classic bare-metal template
cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
# Or start an async Embassy project from its examples:
# https://github.com/embassy-rs/embassy/tree/main/examples| Command | Description |
|---|---|
probe-rs list |
List all connected debug probes (shows VID:PID and serial number) |
probe-rs chip list | grep -i stm32f7 |
Find the exact chip name for --chip |
probe-rs run --chip <CHIP> target/thumbv7em-none-eabihf/debug/myapp |
Flash and run the firmware (with RTT/defmt log output) |
probe-rs attach --chip <CHIP> target/.../myapp |
Attach to a running target without reflashing |
probe-rs erase --chip <CHIP> |
Erase the entire flash of the target chip |
probe-rs download --chip <CHIP> target/.../myapp |
Flash without running |
probe-rs gdb --chip <CHIP> |
Start a GDB server for the target |
Typical workflow for STM32F746:
# Build your program
cargo build --release
# Flash and run with probe-rs (adjust chip name if needed)
probe-rs run --chip STM32F746NGHx target/thumbv7em-none-eabihf/release/myappSelecting a specific ST‑Link when multiple are connected:
- List all probes and note the serial number:
Example output:
probe-rs list
[0]: STLink V3 (VID: 0483, PID: 374e, Serial: 00123456789, StLink) [1]: STLink V2 (VID: 0483, PID: 3748, Serial: 00234567890, StLink) - Use the
--probeoption with VID:PID:Serial:probe-rs run --chip STM32F746NGHx --probe 0483:3748:00234567890 target/.../myapp
- Or configure a default runner in
.cargo/config.toml:After that,[target.'cfg(all(target_arch = "arm", target_os = "none"))'] runner = "probe-rs run --chip STM32F746NGHx --probe 0483:3748:00234567890"
cargo runwill automatically flash and run on that probe.
Note:
- defmt + RTT is the standard logging stack for embedded Rust: add
defmtanddefmt-rttto your firmware, andprobe-rs run/cargo embedwill decode and print the logs on the host.cargo embed(part ofprobe-rs-tools) provides an interactive session with RTT console and an optional GDB server — configure it viaEmbed.toml.- For step debugging in VS Code, install the official
probe-rs.probe-rs-debuggerextension (uses the Debug Adapter Protocol, no GDB needed).- For GDB-based debugging:
probe-rs gdb --chip STM32F746NGHxin one terminal, thengdb-multiarch target/.../myapp -ex "target remote :1337"in another.
For C/C++ firmware (STM32Cube/HAL projects) or as a complement to the Rust workflow above:
sudo apt update
sudo apt install -y gcc-arm-none-eabi gdb-multiarch binutils-arm-none-eabi
sudo apt install -y openocd stlink-tools
sudo apt install -y qemu-system-arm # Optional: Cortex-M emulationComment:
gcc-arm-none-eabiis the bare-metal ARM cross-compiler;gdb-multiarchreplaces the removedgdb-arm-none-eabipackage and debugs any architecture.openocdandstlink-tools(st-flash,st-info) are the classic flashing/debugging stack, still needed for non-Rust projects. For a vendor GUI, STMicroelectronics provides STM32CubeIDE and STM32CubeProgrammer as Linux downloads.
sudo apt install -y python3 python3-venv python3-dev python3-pip pipx
pipx ensurepathImportant: Since Ubuntu 23.04+, the system Python is externally managed (PEP 668) —
pip installoutside a virtual environment fails by design. Install CLI tools withpipxand project dependencies inside virtual environments.
curl -LsSf https://astral.sh/uv/install.sh | shExplanation: uv is an extremely fast package and project manager that has become the de facto standard. It replaces
pip,virtualenv,pip-tools,pipx, andpyenvin one tool:uv python install 3.13 # Install a Python version (pyenv replacement) uv init myproject && cd myproject uv add requests # Add a dependency uv run main.py # Run inside the project venv automatically uv tool install ruff # Install a CLI tool globally (pipx replacement)
uv tool install ruff # Linter + formatter (replaces flake8, black, isort)
uv tool install mypy # Static type checking
uv tool install pytest # Test runner (or add per-project: uv add --dev pytest)Comment:
ruffis a Rust-based linter/formatter that replacesflake8,black, andisortwith a single, dramatically faster tool (ruff check,ruff format).
curl -fsSL https://pyenv.run | bash
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
exec $SHELL
pyenv install 3.13
pyenv global 3.13Note:
pyenvcompiles Python versions from source and is still widely used, butuv python installcovers the same need with prebuilt binaries. Pick one, not both.
# Check the latest version at https://go.dev/dl/
GO_VERSION=1.26.0
curl -LO "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go${GO_VERSION}.linux-amd64.tar.gz"
echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' >> ~/.zshrc
exec $SHELL
go versionNote: The official tarball from go.dev is always current, while
apt install golanglags several releases behind. Useful extras:go install golang.org/x/tools/gopls@latest(language server) andgo install github.com/go-delve/delve/cmd/dlv@latest(debugger).
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash
exec $SHELL
nvm install --lts # Installs the current LTS (Node.js 24)
node --versionExplanation: Node Version Manager (NVM) installs Node.js per-user and lets you switch versions per project (
.nvmrc). Node.js 18 and 20 are end-of-life; Node.js 24 is the current Active LTS.
corepack enable
corepack prepare yarn@stable --activate
corepack prepare pnpm@latest --activateComment:
corepackships with Node.js and managesyarnandpnpmversions per project — the old Debian Yarn repository (dl.yarnpkg.com+apt-key) is deprecated and should not be used.
sudo apt update
sudo apt install -y postgresql postgresql-contrib
sudo systemctl enable --now postgresqlNote: Installs and starts PostgreSQL, a powerful relational database system. For the newest major versions, use the official PGDG apt repository.
sudo -u postgres psql -c "CREATE USER myuser WITH PASSWORD 'mypassword';"
sudo -u postgres psql -c "CREATE DATABASE mydb OWNER myuser;"curl -fsS https://www.pgadmin.org/static/packages_pgadmin_org.pub | sudo gpg --dearmor -o /usr/share/keyrings/packages-pgadmin-org.gpg
echo "deb [signed-by=/usr/share/keyrings/packages-pgadmin-org.gpg] https://ftp.postgresql.org/pub/pgadmin/pgadmin4/apt/$(lsb_release -cs) pgadmin4 main" | sudo tee /etc/apt/sources.list.d/pgadmin4.list
sudo apt update
sudo apt install -y pgadmin4-desktopExplanation: Installs pgAdmin 4 desktop application for managing PostgreSQL databases. Use
pgadmin4-webinstead if you prefer the browser-based mode.
mkdir -p ~/.local/share/fonts
curl -Lo /tmp/FiraCode.zip https://github.com/ryanoasis/nerd-fonts/releases/latest/download/FiraCode.zip
unzip -o /tmp/FiraCode.zip -d ~/.local/share/fonts/FiraCode
fc-cache -fvComment: Nerd Fonts provide icons and glyphs required by Powerlevel10k, Neovim statuslines, and
eza. Other popular choices:JetBrainsMono.zip,Hack.zip— same URL pattern.
sudo snap install nvim --classic
nvim --versionNote: The
aptpackage is several major versions behind, which breaks modern plugin ecosystems. The snap (or the official tarball from GitHub releases) tracks the current stable release.
The modern plugin ecosystem is built around the lazy.nvim plugin manager (vim-plug is legacy). The recommended starting points:
- 👉 kickstart.nvim — a single, heavily commented
init.luathat teaches you the config as you read it (LSP, treesitter, fuzzy finding included). - 👉 LazyVim — a full pre-configured distribution if you want an IDE out of the box.
- 👉 How to Setup Neovim (2024) by Josean — step-by-step guide building a config from scratch.
# Quick start with kickstart.nvim
git clone https://github.com/nvim-lua/kickstart.nvim.git ~/.config/nvim
nvim # Plugins install automatically on first launchComment: For Rust,
rust-analyzer(installed in the Rust section) is picked up automatically by kickstart's LSP config; addcodelldbvia:Masonfor debugging.
curl -fsSL https://apt.fury.io/wez/gpg.key | sudo gpg --yes --dearmor -o /usr/share/keyrings/wezterm-fury.gpg
echo 'deb [signed-by=/usr/share/keyrings/wezterm-fury.gpg] https://apt.fury.io/wez/ * *' | sudo tee /etc/apt/sources.list.d/wezterm.list
sudo apt update
sudo apt install -y weztermNote: WezTerm is a GPU-accelerated terminal emulator with built-in multiplexing, configured in Lua. The command above uses the official apt repository from the WezTerm author. Popular alternatives: Alacritty and Ghostty.
More configuration tips: 👉 Josean's WezTerm Guide
sudo snap install --classic code
sudo snap install rustrover --classic # Rust IDE (free for non-commercial use)
sudo snap install pycharm-community --classic # Python IDEExplanation: Installs Visual Studio Code, RustRover, and PyCharm Community via snap, which handles updates automatically (unlike pinned tarball downloads). Alternatively, manage all JetBrains IDEs with JetBrains Toolbox — download the latest tarball from the site, extract, and run
jetbrains-toolboxonce; it installs itself.
code --install-extension rust-lang.rust-analyzer # Rust language support
code --install-extension vadimcn.vscode-lldb # CodeLLDB debugger
code --install-extension probe-rs.probe-rs-debugger # Embedded debugging via probe-rs
code --install-extension ms-python.python
code --install-extension charliermarsh.ruff
code --install-extension golang.gosudo snap install postman
sudo apt install -y httpie
cargo binstall -y xh # Optional: fast HTTPie clone in RustComment: Installs Postman (GUI for API testing) and HTTPie (CLI for HTTP requests). Lightweight alternatives worth knowing:
xh(Rust), Bruno (offline, Git-friendly Postman alternative), and Hoppscotch (web-based).
sudo apt install -y wireshark
sudo dpkg-reconfigure wireshark-common # Answer "Yes" to allow non-root capture
sudo usermod -aG wireshark $USER # Re-login to applyNote: Wireshark is a network protocol analyzer. The group configuration lets you capture packets without running the GUI as root.
# Add Docker's official GPG key and repository
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list
# Install Docker Engine, CLI, Buildx, and Compose v2
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo usermod -aG docker $USER # Re-login to apply
# Verify
docker run --rm hello-world
docker compose versionComment: Uses Docker's official repository instead of the outdated Ubuntu
docker.iopackage. Compose v2 is now a plugin invoked asdocker compose(with a space) — the standalonedocker-composebinary is deprecated. Adding your user to thedockergroup allows running commands withoutsudo(note: this is root-equivalent access; use rootless Docker or Podman if that concerns you).
# Verify hardware virtualization support first
sudo apt install -y cpu-checker
kvm-ok
# Install core virtualization packages
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager
# Enable and start libvirt
sudo systemctl enable --now libvirtd
# Add your user to required groups (re-login to apply)
sudo usermod -aG libvirt $USER
sudo usermod -aG kvm $USER
# (Optional) install additional tools
sudo apt install -y virtinst virt-viewerExplanation: KVM (Kernel‑based Virtual Machine) together with QEMU and libvirt provides near‑native performance for virtual machines. This setup is ideal for kernel development, malware analysis in isolated snapshots, infrastructure testing, and running full operating systems inside Linux. It is the recommended virtualization stack on Linux — prefer it over VirtualBox unless you need cross-platform VM portability.
virsh list --allIf no errors are shown, KVM is working correctly.
virt-manager- Open virt-manager
- Click Create new VM
- Choose ISO image
- Allocate RAM / CPU cores
- Create a disk image
- Start the VM and install the guest OS
To give your VMs direct access to the physical network, create a bridge:
sudo nano /etc/netplan/01-netcfg.yamlExample configuration (replace eth0 with your interface name from ip link):
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: no
bridges:
br0:
interfaces: [eth0]
dhcp4: yesApply the changes:
sudo netplan applyNow you can attach VMs to br0 instead of the default NAT network.
Nested virtualization allows you to run VMs inside a VM (useful for labs and testing hypervisors).
For Intel CPUs:
echo "options kvm-intel nested=Y" | sudo tee /etc/modprobe.d/kvm-intel.confFor AMD CPUs:
echo "options kvm-amd nested=1" | sudo tee /etc/modprobe.d/kvm-amd.confReload the KVM modules:
sudo modprobe -r kvm_intel kvm_amd 2>/dev/null
sudo modprobe kvm_intel || sudo modprobe kvm_amdCheck if nested virtualization is active:
cat /sys/module/kvm_intel/parameters/nested 2>/dev/null || cat /sys/module/kvm_amd/parameters/nestedIt should print 1 or Y.
- KVM delivers near‑native performance (much faster than QEMU software emulation).
- Supports GPU passthrough (advanced, requires dedicated GPU and IOMMU).
- Perfect for:
- Malware analysis (isolated snapshots)
- Kernel development (easy crash recovery)
- Testing multi‑node clusters on a single machine
- Running Windows or other Linux distributions side‑by-side
sudo apt update
sudo apt install -y qemu-system-x86 qemu-system-arm qemu-user-staticExplanation: Installs QEMU emulators for x86 and ARM systems.
qemu-system-armalso emulates Cortex-M boards (useful for testing embedded firmware without hardware), andqemu-user-staticenables running/building foreign-architecture binaries and Docker images (e.g.,arm64onx86_64). If you installed the KVM stack above,qemu-system-x86is already present.
sudo apt install -y build-essential dkms linux-headers-$(uname -r)
wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo gpg --dearmor --yes --output /usr/share/keyrings/oracle-virtualbox-2016.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/oracle-virtualbox-2016.gpg] http://download.virtualbox.org/virtualbox/debian $(lsb_release -cs) contrib" | sudo tee /etc/apt/sources.list.d/virtualbox.list
sudo apt update
sudo apt install -y virtualbox-7.2
# Extension pack — version must match the installed VirtualBox version
VBOX_VERSION=$(VBoxManage --version | cut -dr -f1)
wget "https://download.virtualbox.org/virtualbox/${VBOX_VERSION}/Oracle_VirtualBox_Extension_Pack-${VBOX_VERSION}.vbox-extpack"
sudo VBoxManage extpack install "Oracle_VirtualBox_Extension_Pack-${VBOX_VERSION}.vbox-extpack"
sudo usermod -aG vboxusers $USER # Re-login to applyExplanation: Installs VirtualBox 7.2 (current stable branch) from Oracle's repository, with the extension pack version derived automatically from the installed build. Note: the extension pack is under Oracle's Personal Use license. Prefer KVM (above) for Linux-only workflows; VirtualBox remains convenient for portable, cross-platform VM setups.
rustup target add wasm32-unknown-unknown
cargo binstall -y cargo-leptos trunk leptosfmtNote: Leptos is a Rust framework for building reactive web applications.
cargo-leptosbuilds full-stack (SSR) projects,trunkserves client-side (CSR) WASM apps, andleptosfmtformats theview!macros. Thewasm32-unknown-unknowntarget is required for all Rust → WebAssembly work.
# System dependencies (Ubuntu 24.04+)
sudo apt install -y libwebkit2gtk-4.1-dev build-essential curl wget file \
libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev
# Tauri CLI (choose one)
cargo binstall -y tauri-cli create-tauri-app
# or per-project via npm: npm install -D @tauri-apps/cli
# Scaffold a new app
cargo create-tauri-appExplanation: Tauri 2 builds lightweight desktop (and mobile) applications with a Rust backend and web frontend. The WebKitGTK system libraries are mandatory on Linux — install them before the first build.
sudo apt install -y openssh-server
sudo systemctl enable --now sshNote: Installs and enables the SSH server for remote access. Recommended hardening in
/etc/ssh/sshd_config:PasswordAuthentication no(after adding your public key to~/.ssh/authorized_keys) andPermitRootLogin no, thensudo systemctl restart ssh.
Warning: For most desktop users, the preinstalled UFW (
sudo ufw enable) is sufficient and simpler. Configure nftables directly only if you want full control. Do not purge theiptablespackage: Docker and libvirt program their rules through theiptables-nftcompatibility layer, and removing it breaks container networking.
# Disable UFW so it does not conflict with your own ruleset
sudo ufw disable
sudo apt update
sudo apt install -y nftables
sudo systemctl enable --now nftables
sudo nano /etc/nftables.conf#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iifname "lo" accept
ct state established,related accept
tcp dport 22 accept
icmp type echo-request accept
icmpv6 type { echo-request, nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert } accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
sudo nft -c -f /etc/nftables.conf # Check syntax first
sudo nft -f /etc/nftables.conf
sudo systemctl restart nftablesExplanation: A modern default-deny inbound firewall: allows SSH, ICMP ping, and established connections, while permitting all outbound traffic (a drop-by-default output chain silently breaks package managers, NTP, and updates — only lock down output on hardened servers). The
-cflag validates the config before applying, so a typo cannot lock you out.
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgradesExplanation: Enables automatic installation of security updates.
sudo apt autoremove -y # Remove packages no longer needed
sudo apt clean # Clear the local package cache
sudo journalctl --vacuum-time=7d # Trim systemd logs older than 7 days
sudo snap set system refresh.retain=2 # Keep only 2 revisions of each snapComment: Run these occasionally to free disk space. Keeping 7 days of journal logs (rather than 1) preserves enough history to debug recent issues.
Happy coding! 🚀