Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save BeKnowDo/7fbabcbf498134b0766bed903e862c05 to your computer and use it in GitHub Desktop.

Select an option

Save BeKnowDo/7fbabcbf498134b0766bed903e862c05 to your computer and use it in GitHub Desktop.
# Ubuntu 26.04 LTS Developer Installation and Configuration Guide
Last updated: August 19, 2026
Target system: Ubuntu Desktop 26.04 LTS (Resolute Raccoon), standard GNOME desktop, x86-64/amd64 workstation.
This guide is the Ubuntu-native conversion of the Fedora developer workstation walkthrough. It keeps the same general application stack and workflow while replacing Fedora-specific package management, RPM Fusion, SELinux, firewalld, RPM packages, and Nginx conventions with the appropriate Ubuntu equivalents.
Ubuntu 26.04 LTS was released on April 23, 2026 and is supported with standard security and critical maintenance updates through April 2031.
Hardware profile retained from the original workstation guide:
- CPU: AMD Ryzen 9 7900X
- Memory: 128 GiB RAM
- GPU: NVIDIA GeForce RTX 4060
- Display: ultrawide 3440x1440, high refresh rate
- Desktop: GNOME on Wayland
- Terminal: Terminator
- Storage: multi-drive NVMe/SATA desktop
- Network: Realtek 2.5 GbE plus Wi-Fi
> Important: This guide targets standard Ubuntu Desktop 26.04 LTS, not Ubuntu Cinnamon, Kubuntu, Linux Mint, Pop!_OS, or another Ubuntu derivative. Most command-line steps will still work on derivatives, but desktop settings and third-party vendor support can differ.
---
## 1. Application inventory
This guide covers the following applications and tools.
### Shell and developer base
- Terminator terminal
- Zsh
- Oh My Zsh
- Git and Git LFS
- nvm
- Node.js LTS
- AWS CLI v2
- AppImage support with FUSE
- Flatpak and Flathub
### Browser
- Google Chrome Stable
### IDEs and developer apps
- Visual Studio Code
- Cursor IDE
- Google Antigravity IDE
- Postman
### Containers
- Docker Engine
- Docker CLI
- Docker Buildx
- Docker Compose plugin
- Docker Desktop
- NVIDIA Container Toolkit for GPU containers
### NVIDIA and graphics
- Ubuntu restricted driver repository
- NVIDIA proprietary/open kernel driver selected through `ubuntu-drivers`
- NVIDIA settings UI
- Vulkan tools
- OpenGL tools
### AI and local models
- LM Studio AppImage
- LM Studio applications-menu launcher
### Communication
- Slack
### Gaming
- Steam
- Proton and Steam Play
- GameMode
- MangoHud
- Gamescope
### Hardware and utilities
- Brother HL-L2405W printer setup
- CUPS
- Avahi printer discovery
- Cameractrls
- guvcview
- OBS Studio
- Mission Center
- nvtop
- btop
---
## 2. Install Ubuntu Desktop 26.04 LTS
Download Ubuntu Desktop 26.04 LTS from the official Ubuntu download page:
```text
https://ubuntu.com/download/desktop
```
Ubuntu 26.04 LTS is codenamed:
```text
Resolute Raccoon
```
Use one of these methods to create the USB installer:
- Ubuntu's recommended USB-writing workflow
- Rufus on Windows
- balenaEtcher
- Fedora Media Writer if you are creating the installer from your existing Fedora machine
Suggested install choices:
- Install type: fresh install
- Desktop: standard Ubuntu Desktop
- Architecture: amd64/x86-64
- Enable downloading updates during installation
- Enable third-party software/drivers when the installer offers it
- Use the default guided disk layout unless you specifically need custom partitioning
- Secure Boot: it can remain enabled; Ubuntu supports signed NVIDIA driver packages
- Hostname: something memorable, for example `cesar-ubuntu`
Ubuntu's default desktop filesystem layout normally uses ext4. There is no need to force Btrfs unless you specifically want Btrfs features and are comfortable creating a custom partition layout.
Before installing on a multi-drive machine, identify the intended OS disk carefully from the existing system:
```bash
lsblk -o NAME,SIZE,MODEL,SERIAL,TYPE,MOUNTPOINTS
```
Do not assume `/dev/nvme0n1` is the install target. NVMe numbering can change.
On a workstation with many internal drives, the safest approach is to verify the OS target by **model, size, and serial number**, not by device name alone.
---
## 3. First boot checklist
Open the default Ubuntu terminal for the first few commands. Terminator will be installed shortly.
Verify the system:
```bash
cat /etc/os-release
lsb_release -a
uname -r
hostnamectl
```
Check the GPU hardware:
```bash
lspci | grep -Ei 'nvidia|vga|3d'
```
Check whether the current desktop session is Wayland or X11:
```bash
echo "$XDG_SESSION_TYPE"
echo "$XDG_CURRENT_DESKTOP"
```
Create working directories:
```bash
mkdir -p "$HOME/Code" "$HOME/Applications" "$HOME/.local/bin"
```
Add `~/.local/bin` to your login path:
```bash
grep -q 'HOME/.local/bin' "$HOME/.profile" 2>/dev/null || \
printf '\nexport PATH="$HOME/.local/bin:$PATH"\n' >> "$HOME/.profile"
```
Update Ubuntu immediately:
```bash
sudo apt update
sudo apt full-upgrade -y
sudo apt autoremove -y
sudo reboot
```
After reboot, verify there are no broken packages:
```bash
sudo dpkg --audit
sudo apt --fix-broken install
```
If both commands complete without reporting an unresolved problem, continue.
### 3.1 Automatically mount additional internal drives
Your desktop has several NVMe and SATA drives. Configure each data partition with a persistent UUID rather than a path such as `/dev/sda1` or `/dev/nvme1n1p1`. Kernel-assigned device names can change after hardware changes, firmware updates, or rebooting.
> Important: These steps mount an existing filesystem. They do not partition or format a drive. Do not run `mkfs`, `fdisk`, `parted`, `wipefs`, or a formatting command on a drive that contains data you want to keep.
#### 3.1.1 Inventory the drives and filesystems
List each disk, partition, filesystem type, label, UUID, model, and current mount point:
```bash
lsblk -e7 -o NAME,SIZE,FSTYPE,LABEL,UUID,MODEL,MOUNTPOINTS
```
Show additional filesystem identifiers:
```bash
sudo blkid
```
Show real mounted filesystems:
```bash
findmnt --real
```
Select the **partition** that contains the filesystem, not merely the parent disk. For example, use `/dev/nvme0n1p1` or `/dev/sda1`, not `/dev/nvme0n1` or `/dev/sda`.
If GNOME Files temporarily mounted the partition below `/media/$USER/...`, inspect it:
```bash
findmnt -S /dev/DEVICE_PARTITION
```
Unmount it before creating the permanent mount:
```bash
udisksctl unmount -b /dev/DEVICE_PARTITION
```
Replace `/dev/DEVICE_PARTITION` with the real partition path.
#### 3.1.2 Create permanent mount points
Use descriptive paths. For example:
```bash
sudo mkdir -p /mnt/projects
sudo mkdir -p /mnt/models
sudo mkdir -p /mnt/archive
sudo mkdir -p /mnt/games
```
Only create the mount points you actually need.
#### 3.1.3 Record the UUID and filesystem type
For each partition, run:
```bash
sudo blkid -s UUID -s TYPE -o full /dev/DEVICE_PARTITION
```
Example:
```text
/dev/nvme0n1p1: UUID="11111111-2222-3333-4444-555555555555" TYPE="ext4"
```
Copy the UUID exactly and note the filesystem type, such as:
- `ext4`
- `xfs`
- `btrfs`
- `ntfs`
- `exfat`
If you have XFS filesystems, install the XFS utilities:
```bash
sudo apt install -y xfsprogs
```
For NTFS tools:
```bash
sudo apt install -y ntfs-3g
```
For exFAT tools:
```bash
sudo apt install -y exfatprogs
```
#### 3.1.4 Back up and edit `/etc/fstab`
Create a timestamped backup:
```bash
sudo cp -a /etc/fstab "/etc/fstab.backup.$(date +%Y%m%d-%H%M%S)"
sudoedit /etc/fstab
```
Add one line per filesystem.
Example for ext4:
```fstab
UUID=11111111-2222-3333-4444-555555555555 /mnt/projects ext4 defaults,nofail,noatime,x-systemd.device-timeout=10s 0 2
```
Common examples:
```fstab
# ext4
UUID=REPLACE_WITH_UUID /mnt/projects ext4 defaults,nofail,noatime,x-systemd.device-timeout=10s 0 2
# XFS
UUID=REPLACE_WITH_UUID /mnt/models xfs defaults,nofail,noatime,x-systemd.device-timeout=10s 0 0
# Btrfs data filesystem
UUID=REPLACE_WITH_UUID /mnt/archive btrfs defaults,nofail,noatime,x-systemd.device-timeout=10s 0 0
```
The important options are:
- `nofail`: continue booting if the drive is unavailable
- `noatime`: avoid writing an access timestamp every time a file is read
- `x-systemd.device-timeout=10s`: avoid an excessive boot delay if a device is unavailable
For an internal NTFS or exFAT data partition, first obtain your numeric user and group IDs:
```bash
id -u
id -g
```
They are often `1000` for the first desktop user, but verify rather than assuming.
Examples:
```fstab
# NTFS using the in-kernel ntfs3 driver
UUID=REPLACE_WITH_UUID /mnt/shared ntfs3 defaults,nofail,uid=1000,gid=1000,umask=0022,x-systemd.device-timeout=10s 0 0
# exFAT
UUID=REPLACE_WITH_UUID /mnt/shared exfat defaults,nofail,uid=1000,gid=1000,umask=0022,x-systemd.device-timeout=10s 0 0
```
Do not put quotation marks around UUIDs or mount points in `/etc/fstab`.
#### 3.1.5 Validate the configuration before rebooting
Reload systemd's generated mount units:
```bash
sudo systemctl daemon-reload
```
Verify `/etc/fstab`:
```bash
sudo findmnt --verify --verbose
```
Mount all newly configured filesystems:
```bash
sudo mount -a
```
Confirm each expected mount:
```bash
findmnt /mnt/projects
df -hT /mnt/projects
```
Repeat for the other mount points you configured.
If `sudo mount -a` reports an error, fix `/etc/fstab` **before rebooting**.
To restore the most recent backup if necessary:
```bash
ls -1t /etc/fstab.backup.* | head
```
Then restore the correct backup:
```bash
sudo cp -a /etc/fstab.backup.YYYYMMDD-HHMMSS /etc/fstab
```
#### 3.1.6 Set ownership for Linux filesystems
For a newly mounted ext4, XFS, or Btrfs data filesystem that should belong to your user:
```bash
sudo chown "$USER:$USER" /mnt/projects
sudo chmod 755 /mnt/projects
```
This changes only the root directory of the mounted filesystem.
Avoid:
```bash
sudo chown -R ...
```
on an existing data drive unless you intentionally want to rewrite ownership for every file.
#### 3.1.7 Optional home-directory shortcuts
Create symbolic links:
```bash
ln -s /mnt/projects "$HOME/projects-drive"
ln -s /mnt/models "$HOME/models-drive"
ln -s /mnt/archive "$HOME/archive-drive"
ln -s /mnt/games "$HOME/games-drive"
```
Only create a link if the destination name does not already exist.
Verify after reboot:
```bash
findmnt --real
ls -ld /mnt/projects "$HOME/projects-drive"
```
---
## 4. Install Terminator
Install Terminator:
```bash
sudo apt update
sudo apt install -y terminator
```
Launch it:
```bash
terminator
```
Ubuntu uses the `x-terminal-emulator` alternatives system for some generic terminal launches. To choose Terminator:
```bash
sudo update-alternatives --config x-terminal-emulator
```
Select the Terminator entry.
GNOME applications are not required to honor this alternative, so the practical approach is also to pin Terminator to the dock and use it as your normal terminal.
Most commands in the rest of this guide assume you are using Terminator.
---
## 5. Enable Ubuntu software repository components
Ubuntu does not use RPM Fusion. The equivalent software you need is already available through Ubuntu's standard repository components or through vendor-provided APT repositories.
Install repository-management tools:
```bash
sudo apt install -y software-properties-common
```
Enable the standard components needed by this guide:
```bash
sudo add-apt-repository -y universe
sudo add-apt-repository -y multiverse
sudo add-apt-repository -y restricted
sudo apt update
```
Verify enabled Ubuntu sources:
```bash
grep -R --no-filename -E '^(Components:|deb )' \
/etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null
```
On modern Ubuntu releases, the main Ubuntu repository configuration commonly lives in:
```text
/etc/apt/sources.list.d/ubuntu.sources
```
---
## 6. Install base developer packages
Install the base packages used throughout this guide:
```bash
sudo apt update
sudo apt install -y \
zsh git git-lfs curl wget unzip tar gzip ca-certificates gnupg \
software-properties-common apt-transport-https \
build-essential gcc g++ make cmake pkg-config libssl-dev \
python3 python3-pip python3-venv python3-dev pipx \
fuse3 libfuse2t64 \
xdg-utils desktop-file-utils \
inxi fastfetch mesa-utils vulkan-tools \
ripgrep fd-find jq bat eza htop btop tree tmux neovim shellcheck \
pciutils usbutils lsb-release mokutil ubuntu-drivers-common
```
Enable Git LFS:
```bash
git lfs install
```
Ubuntu packages the `fd` command as `fdfind` and frequently packages `bat` as `batcat`.
Create user-level compatibility links:
```bash
mkdir -p "$HOME/.local/bin"
command -v fdfind >/dev/null && \
ln -sfn "$(command -v fdfind)" "$HOME/.local/bin/fd"
command -v batcat >/dev/null && \
ln -sfn "$(command -v batcat)" "$HOME/.local/bin/bat"
```
Verify:
```bash
fd --version
bat --version
eza --version
```
Check AppImage compatibility:
```bash
dpkg -l | grep -E 'fuse3|libfuse2'
```
Ubuntu 26.04 provides `libfuse2t64`, which is useful for AppImages that still require the older FUSE 2 compatibility library.
---
## 7. Configure Git
Set your identity:
```bash
git config --global user.name "Cesar"
git config --global user.email "your-email@example.com"
```
Set defaults:
```bash
git config --global init.defaultBranch main
git config --global pull.rebase false
git config --global core.editor "code --wait"
git config --global fetch.prune true
git config --global rerere.enabled true
```
Verify:
```bash
git --version
git lfs version
git config --global --list
```
---
## 8. Install Zsh and Oh My Zsh
Zsh was installed with the base packages.
Set Zsh as your default shell:
```bash
chsh -s "$(command -v zsh)"
```
Back up an existing Zsh config if present:
```bash
[ -f "$HOME/.zshrc" ] && \
cp "$HOME/.zshrc" "$HOME/.zshrc.backup.$(date +%Y%m%d%H%M%S)"
```
Install Oh My Zsh without starting a nested shell:
```bash
RUNZSH=no CHSH=no sh -c \
"$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
```
Install useful plugins:
```bash
ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
[ -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ] || \
git clone --depth=1 \
https://github.com/zsh-users/zsh-autosuggestions \
"$ZSH_CUSTOM/plugins/zsh-autosuggestions"
[ -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ] || \
git clone --depth=1 \
https://github.com/zsh-users/zsh-syntax-highlighting.git \
"$ZSH_CUSTOM/plugins/zsh-syntax-highlighting"
```
Enable plugins. Keep `zsh-syntax-highlighting` last:
```bash
if grep -q '^plugins=' "$HOME/.zshrc"; then
sed -i \
's/^plugins=(.*)/plugins=(git aws docker npm ubuntu zsh-autosuggestions zsh-syntax-highlighting)/' \
"$HOME/.zshrc"
else
printf '\nplugins=(git aws docker npm ubuntu zsh-autosuggestions zsh-syntax-highlighting)\n' \
>> "$HOME/.zshrc"
fi
```
Add local bin to Zsh:
```bash
grep -q 'HOME/.local/bin' "$HOME/.zshrc" || \
printf '\nexport PATH="$HOME/.local/bin:$PATH"\n' >> "$HOME/.zshrc"
```
Log out and back in, or start Zsh manually:
```bash
exec zsh
```
Verify:
```bash
echo "$SHELL"
zsh --version
```
---
## 9. Install nvm and Node.js LTS
As of this guide update, nvm's upstream install documentation uses version `v0.40.6`.
Install nvm into your Zsh profile:
```bash
curl -o- \
https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh \
| PROFILE="$HOME/.zshrc" bash
```
Open a new Terminator window or source your config:
```bash
source "$HOME/.zshrc"
```
Verify nvm:
```bash
command -v nvm
nvm --version
```
Install Node.js LTS:
```bash
nvm install --lts
nvm alias default "lts/*"
```
Verify:
```bash
node --version
npm --version
nvm current
```
If the installed Node release ships Corepack and you want pnpm/Yarn shims:
```bash
corepack enable
```
If `corepack` is not present in the selected Node release, install your preferred package manager explicitly instead of assuming it is bundled.
Optional: install the current non-LTS Node release:
```bash
nvm install node
```
Useful commands:
```bash
nvm ls
nvm current
nvm install --lts
nvm use --lts
```
---
## 10. Install AWS CLI v2
Install the official AWS CLI v2 x86-64 bundle:
```bash
cd /tmp
rm -rf aws awscliv2.zip
curl -fsSL \
"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" \
-o awscliv2.zip
unzip -q awscliv2.zip
sudo ./aws/install \
--bin-dir /usr/local/bin \
--install-dir /usr/local/aws-cli \
--update
```
Verify:
```bash
aws --version
```
Configure with SSO:
```bash
aws configure sso
```
Or configure classic access keys:
```bash
aws configure
```
Verify credentials:
```bash
aws sts get-caller-identity
```
---
## 11. Install NVIDIA drivers
Ubuntu's recommended approach is to use `ubuntu-drivers`. It uses the same hardware-selection logic as Ubuntu's Additional Drivers interface and is preferable to manually downloading NVIDIA's `.run` installer.
### 11.1 Check Secure Boot
```bash
mokutil --sb-state
```
Secure Boot can remain enabled.
Check available NVIDIA driver packages for the detected hardware:
```bash
sudo ubuntu-drivers list
```
See Ubuntu's recommendation:
```bash
ubuntu-drivers devices
```
### 11.2 Install the recommended NVIDIA driver
Use automatic detection:
```bash
sudo apt update
sudo ubuntu-drivers install
```
Then reboot:
```bash
sudo reboot
```
This approach is preferable to hard-coding a driver branch because Ubuntu can select the current supported branch for your GPU and kernel.
On Ubuntu 26.04, newer NVIDIA branches and open-kernel-module variants may appear in the list. Let `ubuntu-drivers` select the recommended package unless you have a specific compatibility requirement.
### 11.3 Secure Boot and MOK enrollment
Ubuntu attempts to use signed NVIDIA driver modules when Secure Boot is enabled.
If the package installation presents a Machine Owner Key enrollment prompt:
1. Create the one-time enrollment password requested by the installer.
2. Reboot.
3. On the blue MOK management screen, choose `Enroll MOK`.
4. Choose `Continue`.
5. Confirm enrollment.
6. Enter the password you created.
7. Reboot again.
After login, verify Secure Boot:
```bash
mokutil --sb-state
```
If no MOK enrollment screen appears and the NVIDIA modules load normally, no manual MOK work is required.
### 11.4 Verify NVIDIA after reboot
Check the driver:
```bash
nvidia-smi
```
Check loaded kernel modules:
```bash
lsmod | grep '^nvidia'
```
Check the running driver version:
```bash
cat /proc/driver/nvidia/version
```
Check OpenGL:
```bash
glxinfo -B | grep -E 'OpenGL vendor|OpenGL renderer'
```
Check Vulkan:
```bash
vulkaninfo --summary | grep -Ei 'deviceName|driverName' || true
```
Expected result:
- `nvidia-smi` lists the NVIDIA GPU
- `lsmod` lists NVIDIA modules
- OpenGL reports NVIDIA rather than `llvmpipe`
- Vulkan lists the NVIDIA GPU
### 11.5 NVIDIA settings
Install the settings UI if it was not already pulled in:
```bash
sudo apt install -y nvidia-settings
```
Launch it:
```bash
nvidia-settings
```
On Wayland, some display controls are intentionally handled by GNOME rather than by `nvidia-settings`.
### 11.6 Suspend and resume
Ubuntu 26.04 includes updated NVIDIA suspend/resume handling. Do not manually enable NVIDIA sleep services unless troubleshooting demonstrates that they are needed.
If suspend or wake problems occur, collect these first:
```bash
nvidia-smi
systemctl status systemd-suspend.service --no-pager
journalctl -b -1 -k | grep -Ei 'nvidia|suspend|resume|drm' | tail -n 200
```
---
## 12. Install Docker Engine and Docker Compose
Use Docker's official Ubuntu APT repository.
> Firewall note: Docker-published container ports can bypass normal UFW filtering. Do not assume that a UFW deny rule protects a port that Docker has published. For internet-facing systems, review Docker's firewall behavior and use the `DOCKER-USER` chain when appropriate.
### 12.1 Remove conflicting packages
Docker recommends removing packages that can conflict with Docker CE:
```bash
for pkg in \
docker.io \
docker-compose \
docker-compose-v2 \
docker-doc \
docker-buildx \
podman-docker \
containerd \
runc; do
sudo apt remove -y "$pkg" 2>/dev/null || true
done
```
### 12.2 Add Docker's Ubuntu repository
Install prerequisites:
```bash
sudo apt update
sudo apt install -y ca-certificates curl
```
Create the APT keyring directory:
```bash
sudo install -m 0755 -d /etc/apt/keyrings
```
Install Docker's signing key:
```bash
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
```
Add Docker's repository in deb822 format:
```bash
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
```
Refresh APT:
```bash
sudo apt update
```
Verify Docker packages are coming from Docker's repository:
```bash
apt-cache policy docker-ce
```
### 12.3 Install Docker Engine, Buildx, and Compose
```bash
sudo apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
```
Verify service status:
```bash
sudo systemctl status docker --no-pager
```
If needed:
```bash
sudo systemctl enable --now docker
```
Test with sudo first:
```bash
sudo docker run hello-world
```
### 12.4 Let your user run Docker without sudo
Security note: membership in the `docker` group effectively grants root-level control of the machine.
Add your user:
```bash
sudo usermod -aG docker "$USER"
```
Log out and back in.
For a temporary shell refresh:
```bash
newgrp docker
```
Verify:
```bash
groups
docker run hello-world
docker compose version
```
### 12.5 Tiny Compose smoke test
```bash
mkdir -p "$HOME/Code/docker-smoke-test"
cd "$HOME/Code/docker-smoke-test"
cat > compose.yaml <<'YAML'
services:
hello:
image: hello-world
YAML
docker compose up
docker compose down --remove-orphans
cd "$HOME"
rm -rf "$HOME/Code/docker-smoke-test"
```
---
## 13. Install NVIDIA Container Toolkit
Only do this after `nvidia-smi` works correctly on the host and Docker Engine is working.
Install prerequisites:
```bash
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
ca-certificates \
curl \
gnupg2
```
Add NVIDIA's signing key and production repository:
```bash
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
sudo gpg --dearmor \
-o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L \
https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
```
Refresh and install:
```bash
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
```
Configure Docker:
```bash
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
```
Test GPU access in a container:
```bash
docker run --rm --gpus all ubuntu nvidia-smi
```
If your group change has not taken effect yet:
```bash
sudo docker run --rm --gpus all ubuntu nvidia-smi
```
---
## 14. Install Docker Desktop
Docker Desktop officially supports x86-64 Ubuntu 26.04 LTS.
Docker Desktop can coexist with Docker Engine. It uses a separate `desktop-linux` context and stores its data inside its own Linux VM.
### 14.1 Install Docker Desktop requirements
Check CPU virtualization:
```bash
egrep -c '(vmx|svm)' /proc/cpuinfo
```
A nonzero result indicates that CPU virtualization extensions are visible.
Check KVM:
```bash
lsmod | grep kvm
```
On the Ryzen 9 7900X, you should normally see:
```text
kvm_amd
kvm
```
If needed:
```bash
sudo modprobe kvm
sudo modprobe kvm_amd
```
Check the KVM device:
```bash
ls -al /dev/kvm
```
Add your user to the `kvm` group:
```bash
sudo usermod -aG kvm "$USER"
```
Log out and back in after changing group membership.
On standard Ubuntu GNOME, Docker Desktop also expects AppIndicator/KStatusNotifierItem support. If the tray integration is missing, install the Ubuntu AppIndicators extension package:
```bash
sudo apt install -y gnome-shell-ubuntu-extensions
```
Log out and back in if GNOME Shell does not pick it up immediately.
### 14.2 Download and install Docker Desktop DEB
Docker recommends downloading the current DEB package from its Ubuntu Docker Desktop page.
Open the page:
```bash
xdg-open https://docs.docker.com/desktop/setup/install/linux/ubuntu/
```
Download the current file to `~/Downloads`.
If it is named `docker-desktop-amd64.deb`, install it:
```bash
cd "$HOME/Downloads"
sudo apt update
sudo apt install -y ./docker-desktop-amd64.deb
```
If the downloaded filename contains a version, locate it:
```bash
DOCKER_DESKTOP_DEB="$(
find "$HOME/Downloads" -maxdepth 1 -type f \
-iname 'docker-desktop*amd64*.deb' \
| sort | tail -n 1
)"
test -n "$DOCKER_DESKTOP_DEB" || {
echo "Download the Docker Desktop Ubuntu DEB first."
exit 1
}
sudo apt install -y "$DOCKER_DESKTOP_DEB"
```
### 14.3 Launch Docker Desktop
Launch from the Ubuntu applications menu or run:
```bash
systemctl --user start docker-desktop
```
The first launch presents Docker's terms. Docker Desktop will not run until they are accepted.
Enable it at sign-in:
```bash
systemctl --user enable docker-desktop
```
Verify Docker contexts:
```bash
docker context ls
docker context show
```
Switch explicitly to Docker Desktop:
```bash
docker context use desktop-linux
docker run hello-world
```
Switch back to the host Docker Engine:
```bash
docker context use default
```
### 14.4 Terminator aliases for Docker Desktop
Add helpers to `~/.zshrc`:
```bash
cat >> "$HOME/.zshrc" <<'EOF_ZSH'
# Docker Desktop helpers
alias ddesktop-start='systemctl --user start docker-desktop'
alias ddesktop-stop='systemctl --user stop docker-desktop'
alias ddesktop-status='systemctl --user status docker-desktop'
alias ddesktop-use='docker context use desktop-linux'
alias docker-engine-use='docker context use default'
alias docker-context='docker context ls'
EOF_ZSH
source "$HOME/.zshrc"
```
---
## 15. Install Google Chrome
Google provides a 64-bit `.deb` package for Debian and Ubuntu.
### 15.1 Download and install the official DEB
```bash
mkdir -p "$HOME/Downloads"
cd "$HOME/Downloads"
curl -fL \
"https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb" \
-o google-chrome-stable_current_amd64.deb
sudo apt install -y ./google-chrome-stable_current_amd64.deb
```
Verify:
```bash
dpkg -s google-chrome-stable | grep -E 'Status|Version'
google-chrome-stable --version
```
The Google package normally adds Google's APT repository for future updates.
Inspect it:
```bash
grep -R -i 'dl.google.com' \
/etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null || true
```
Launch:
```bash
google-chrome-stable
```
### 15.2 Optional: make Chrome the default browser
```bash
xdg-settings set default-web-browser google-chrome.desktop
xdg-settings get default-web-browser
```
You can also set the default browser through Ubuntu Settings.
### 15.3 Troubleshooting
If the DEB is incomplete:
```bash
rm -f "$HOME/Downloads/google-chrome-stable_current_amd64.deb"
curl -fL \
"https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb" \
-o "$HOME/Downloads/google-chrome-stable_current_amd64.deb"
sudo apt install -y "$HOME/Downloads/google-chrome-stable_current_amd64.deb"
```
If APT reports broken dependencies:
```bash
sudo apt --fix-broken install
sudo apt install -y "$HOME/Downloads/google-chrome-stable_current_amd64.deb"
```
---
## 16. Install Visual Studio Code
Use Microsoft's official APT repository.
Install key tools:
```bash
sudo apt update
sudo apt install -y wget gpg
```
Install Microsoft's signing key:
```bash
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | \
sudo gpg --dearmor -o /usr/share/keyrings/microsoft.gpg
```
Create the deb822 source:
```bash
sudo tee /etc/apt/sources.list.d/vscode.sources > /dev/null <<'EOF'
Types: deb
URIs: https://packages.microsoft.com/repos/code
Suites: stable
Components: main
Architectures: amd64,arm64,armhf
Signed-By: /usr/share/keyrings/microsoft.gpg
EOF
```
Install VS Code:
```bash
sudo apt update
sudo apt install -y code
```
Verify:
```bash
code --version
```
Optional extensions:
```bash
code --install-extension ms-python.python
code --install-extension ms-python.vscode-pylance
code --install-extension dbaeumer.vscode-eslint
code --install-extension esbenp.prettier-vscode
code --install-extension ms-azuretools.vscode-docker
code --install-extension amazonwebservices.aws-toolkit-vscode
code --install-extension github.vscode-github-actions
```
---
## 17. Install Cursor IDE
Cursor provides an APT repository for Debian and Ubuntu.
Install GPG tooling if necessary:
```bash
sudo apt update
sudo apt install -y curl gpg
sudo mkdir -p /etc/apt/keyrings
```
Add Cursor's signing key:
```bash
curl -fsSL https://downloads.cursor.com/keys/anysphere.asc | \
gpg --dearmor | \
sudo tee /etc/apt/keyrings/cursor.gpg > /dev/null
```
Add the repository:
```bash
echo \
"deb [arch=amd64,arm64 signed-by=/etc/apt/keyrings/cursor.gpg] https://downloads.cursor.com/aptrepo stable main" | \
sudo tee /etc/apt/sources.list.d/cursor.list > /dev/null
```
Install:
```bash
sudo apt update
sudo apt install -y cursor
```
Verify:
```bash
command -v cursor
cursor --version 2>/dev/null | head -n 2
```
If the repository method ever fails, use the Linux download from:
```bash
xdg-open https://cursor.com/downloads
```
---
## 18. Install Google Antigravity IDE
Google provides an APT repository for Debian-based distributions.
Create the keyring directory:
```bash
sudo mkdir -p /etc/apt/keyrings
```
Install Google's Antigravity repository signing key:
```bash
curl -fsSL \
https://us-central1-apt.pkg.dev/doc/repo-signing-key.gpg | \
sudo gpg --dearmor --yes \
-o /etc/apt/keyrings/antigravity-repo-key.gpg
```
Add the repository:
```bash
echo \
"deb [signed-by=/etc/apt/keyrings/antigravity-repo-key.gpg] https://us-central1-apt.pkg.dev/projects/antigravity-auto-updater-dev/ antigravity-debian main" | \
sudo tee /etc/apt/sources.list.d/antigravity.list > /dev/null
```
Install:
```bash
sudo apt update
sudo apt install -y antigravity
```
Verify:
```bash
command -v antigravity || true
antigravity --version 2>/dev/null | head -n 2 || true
```
---
## 19. Install Slack
Slack publishes a Debian/Ubuntu `.deb` package.
Open the official Linux download page:
```bash
xdg-open https://slack.com/downloads/linux
```
Download the `.deb` build.
Then install the newest matching Slack package from `~/Downloads`:
```bash
SLACK_DEB="$(
find "$HOME/Downloads" -maxdepth 1 -type f \
-iname 'slack-desktop-*.deb' \
| sort | tail -n 1
)"
test -n "$SLACK_DEB" || {
echo "Download the Slack DEB first."
exit 1
}
sudo apt install -y "$SLACK_DEB"
```
Verify:
```bash
dpkg -l | grep -i slack
command -v slack || true
```
### Flatpak fallback
Install Flatpak if you have not already:
```bash
sudo apt install -y flatpak
```
Add Flathub:
```bash
flatpak remote-add --if-not-exists \
flathub https://dl.flathub.org/repo/flathub.flatpakrepo
```
Install Slack:
```bash
flatpak install -y flathub com.slack.Slack
```
Launch:
```bash
flatpak run com.slack.Slack
```
Use either the native Slack package or Flatpak unless you intentionally want two installations.
---
## 20. Install Postman
Use Postman's official Linux tarball.
```bash
cd /tmp
curl -L \
-o postman-linux-x64.tar.gz \
https://dl.pstmn.io/download/latest/linux64
sudo rm -rf /opt/Postman
sudo tar -xzf postman-linux-x64.tar.gz -C /opt
sudo ln -sfn /opt/Postman/Postman /usr/local/bin/postman
```
Test:
```bash
postman
```
Create an application launcher:
```bash
mkdir -p "$HOME/.local/share/applications"
cat > "$HOME/.local/share/applications/postman.desktop" <<'DESKTOP'
[Desktop Entry]
Name=Postman
Comment=API development environment
Exec=/opt/Postman/Postman
Icon=/opt/Postman/app/resources/app/assets/icon.png
Terminal=false
Type=Application
Categories=Development;Network;
StartupWMClass=Postman
DESKTOP
chmod +x "$HOME/.local/share/applications/postman.desktop"
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
```
Optional Zsh alias:
```bash
cat >> "$HOME/.zshrc" <<'EOF_ZSH'
# Postman
alias postman='/opt/Postman/Postman'
EOF_ZSH
source "$HOME/.zshrc"
```
---
## 21. Install LM Studio with an applications-menu launcher
LM Studio for Linux is distributed as an AppImage.
### 21.1 Install AppImage support
```bash
sudo apt update
sudo apt install -y fuse3 libfuse2t64
```
### 21.2 Download LM Studio
Open the official Linux download page:
```bash
xdg-open "https://lmstudio.ai/download?os=linux"
```
Download the Linux x64 AppImage.
### 21.3 Move it into `~/Applications`
```bash
mkdir -p "$HOME/Applications"
LM_APPIMAGE="$(
find "$HOME/Downloads" -maxdepth 1 -type f \
\( -iname '*LM*Studio*.AppImage' -o -iname '*LMStudio*.AppImage' \) \
| sort | tail -n 1
)"
echo "$LM_APPIMAGE"
test -n "$LM_APPIMAGE" || {
echo "Download the LM Studio AppImage first."
exit 1
}
install -Dm755 \
"$LM_APPIMAGE" \
"$HOME/Applications/LM-Studio.AppImage"
```
Test:
```bash
"$HOME/Applications/LM-Studio.AppImage"
```
### 21.4 Create an Ubuntu applications-menu launcher
```bash
mkdir -p "$HOME/.local/share/applications"
cat > "$HOME/.local/share/applications/lm-studio.desktop" <<DESKTOP
[Desktop Entry]
Name=LM Studio
Comment=Run local LLMs on your computer
Exec=$HOME/Applications/LM-Studio.AppImage
Terminal=false
Type=Application
Categories=Development;Utility;
StartupWMClass=LM Studio
DESKTOP
chmod +x "$HOME/.local/share/applications/lm-studio.desktop"
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
```
Search the Ubuntu applications overview for:
```text
LM Studio
```
If it does not appear immediately, log out and back in.
### 21.5 Optional terminal command
```bash
mkdir -p "$HOME/.local/bin"
ln -sfn \
"$HOME/Applications/LM-Studio.AppImage" \
"$HOME/.local/bin/lmstudio"
grep -q 'export PATH="$HOME/.local/bin:$PATH"' "$HOME/.zshrc" || \
echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.zshrc"
source "$HOME/.zshrc"
```
Test:
```bash
lmstudio
```
---
## 22. AppImage general pattern
For any AppImage:
```bash
sudo apt install -y fuse3 libfuse2t64
mkdir -p "$HOME/Applications"
mv "$HOME/Downloads/MyApp.AppImage" "$HOME/Applications/"
chmod +x "$HOME/Applications/MyApp.AppImage"
"$HOME/Applications/MyApp.AppImage"
```
Create a launcher:
```bash
mkdir -p "$HOME/.local/share/applications"
cat > "$HOME/.local/share/applications/myapp.desktop" <<DESKTOP
[Desktop Entry]
Name=My App
Comment=AppImage application
Exec=$HOME/Applications/MyApp.AppImage
Terminal=false
Type=Application
Categories=Development;Utility;
DESKTOP
chmod +x "$HOME/.local/share/applications/myapp.desktop"
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
```
If the AppImage reports a FUSE 2 compatibility error:
```bash
sudo apt install --reinstall -y libfuse2t64 fuse3
```
If it still fails, try extraction:
```bash
cd "$HOME/Applications"
./MyApp.AppImage --appimage-extract
./squashfs-root/AppRun
```
---
## 23. Install Steam and gaming tools
Ubuntu 26.04 provides Steam through the `steam-installer` package in Multiverse.
### 23.1 Enable 32-bit architecture
Steam and many games still use 32-bit libraries:
```bash
sudo dpkg --add-architecture i386
sudo apt update
```
### 23.2 Install Steam
```bash
sudo apt install -y steam-installer
```
Launch:
```bash
steam
```
Steam will download its runtime components during first launch.
### 23.3 Flatpak fallback
```bash
sudo apt install -y flatpak
flatpak remote-add --if-not-exists \
flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install -y flathub com.valvesoftware.Steam
```
Launch:
```bash
flatpak run com.valvesoftware.Steam
```
Use native Steam or Flatpak Steam, not both, unless you intentionally want separate installations.
### 23.4 Enable Steam Play and Proton
In Steam:
```text
Steam > Settings > Compatibility
```
Enable Steam Play/compatibility support for the games you need.
Steam's wording changes occasionally, but the relevant area remains the Compatibility settings.
### 23.5 Install GameMode, MangoHud, and Gamescope
```bash
sudo apt update
sudo apt install -y gamemode mangohud gamescope
```
Per-game Steam launch option:
```text
gamemoderun %command%
```
With MangoHud:
```text
mangohud gamemoderun %command%
```
Verify GameMode:
```bash
gamemoded -s
```
---
## 24. Install system monitoring tools
### 24.1 Install Flatpak and Flathub
If Flatpak has not been installed yet:
```bash
sudo apt install -y flatpak
flatpak remote-add --if-not-exists \
flathub https://dl.flathub.org/repo/flathub.flatpakrepo
```
### 24.2 Mission Center GUI
Install Mission Center:
```bash
flatpak install -y flathub io.missioncenter.MissionCenter
```
Launch:
```bash
flatpak run io.missioncenter.MissionCenter
```
### 24.3 Terminal monitors
Install:
```bash
sudo apt install -y nvtop btop
```
Use:
```bash
nvtop
btop
```
Recommended pattern:
```text
Mission Center = general GUI system monitor
nvtop = NVIDIA GPU monitoring
btop = CPU, RAM, disks, network, and processes
```
---
## 25. Install camera controls
Your EMEET camera uses the standard Linux UVC stack, so V4L2 tools remain appropriate on Ubuntu.
### 25.1 Install Cameractrls
Make sure Flatpak/Flathub are configured:
```bash
sudo apt install -y flatpak
flatpak remote-add --if-not-exists \
flathub https://dl.flathub.org/repo/flathub.flatpakrepo
```
Install:
```bash
flatpak install -y flathub hu.irl.cameractrls
```
Launch:
```bash
flatpak run hu.irl.cameractrls
```
### 25.2 Install command-line camera tools
```bash
sudo apt install -y v4l-utils
```
List cameras:
```bash
v4l2-ctl --list-devices
```
List controls:
```bash
v4l2-ctl --list-ctrls
```
Inspect a camera:
```bash
v4l2-ctl -d /dev/video0 --all
```
Example controls:
```bash
v4l2-ctl -d /dev/video0 --set-ctrl=brightness=128
v4l2-ctl -d /dev/video0 --set-ctrl=contrast=128
v4l2-ctl -d /dev/video0 --set-ctrl=saturation=128
```
Exact control names and ranges depend on the webcam.
### 25.3 Install guvcview and OBS Studio
```bash
sudo apt install -y guvcview obs-studio
```
Launch:
```bash
guvcview
obs
```
Recommended pattern:
```text
Cameractrls = daily camera control panel
guvcview = quick preview and fallback controls
OBS Studio = recording, streaming, filters, virtual camera
v4l2-ctl = troubleshooting and scripting
```
---
## 26. Set up Brother HL-L2405W printer
Try driverless AirPrint/IPP first.
### 26.1 Install printing and discovery tools
Ubuntu Desktop normally includes CUPS, but install the required packages explicitly:
```bash
sudo apt update
sudo apt install -y \
cups \
cups-client \
cups-filters \
printer-driver-all \
avahi-daemon \
avahi-utils
```
Enable services:
```bash
sudo systemctl enable --now cups
sudo systemctl enable --now avahi-daemon
```
Allow your user to administer printers through the standard `lpadmin` group:
```bash
sudo usermod -aG lpadmin "$USER"
```
Log out and back in before relying on the new group membership.
### 26.2 Connect the printer
For Wi-Fi, connect the Brother HL-L2405W to the same local network as the Ubuntu workstation.
For USB, connect it directly.
### 26.3 Discover the printer
```bash
lpinfo -v | grep -i brother || true
driverless || true
avahi-browse -rt _ipp._tcp
```
### 26.4 Add through Ubuntu Settings
Open:
```text
Settings > System > Printers
```
Depending on the Ubuntu desktop revision, Printers may also appear as its own Settings section.
Prefer a driverless, AirPrint, IPP Everywhere, or similar entry when available.
Suggested queue name:
```text
Brother_HL_L2405W
```
### 26.5 Add with the command line
List devices:
```bash
lpinfo -v
```
If you have an IPP URI:
```bash
sudo lpadmin \
-p Brother_HL_L2405W \
-E \
-v "PASTE_PRINTER_URI_HERE" \
-m everywhere
sudo lpoptions -d Brother_HL_L2405W
```
Example by IP:
```bash
sudo lpadmin \
-p Brother_HL_L2405W \
-E \
-v "ipp://192.168.1.75/ipp/print" \
-m everywhere
sudo lpoptions -d Brother_HL_L2405W
```
Test:
```bash
lpstat -p -d
echo "Brother HL-L2405W Ubuntu test page" | lp -d Brother_HL_L2405W
```
### 26.6 Brother Linux installer fallback
Only use Brother's vendor driver if driverless IPP does not work.
Brother currently provides both a Linux **DEB printer driver** and a **Driver Install Tool** for the HL-L2405W.
Open:
```bash
xdg-open \
"https://support.brother.com/g/b/downloadtop.aspx?c=us&lang=en&prod=hll2405w_us"
```
Choose:
```text
Linux (deb)
```
The Driver Install Tool is generally the simplest vendor fallback because it installs the appropriate LPR/CUPSwrapper components.
After downloading the installer archive:
```bash
cd "$HOME/Downloads"
ls -lh linux-brprinter-installer-*.gz
gunzip linux-brprinter-installer-*.gz
chmod +x linux-brprinter-installer-*
sudo bash linux-brprinter-installer-* HLL2405W
```
Follow Brother's prompts.
If asked for the device connection:
- For USB, choose the USB/local option.
- For Wi-Fi or Ethernet, choose the network option and provide the printer's IP address when requested.
After installation:
```bash
lpstat -t
lpinfo -v | grep -i brother || true
```
---
## 27. Flatpak application-menu refresh
GNOME normally discovers Flatpak launchers automatically.
List installed Flatpaks:
```bash
flatpak list
```
Check exported launchers:
```bash
find \
"$HOME/.local/share/flatpak/exports/share/applications" \
/var/lib/flatpak/exports/share/applications \
-name '*.desktop' 2>/dev/null
```
Refresh desktop databases if needed:
```bash
update-desktop-database \
"$HOME/.local/share/flatpak/exports/share/applications" \
2>/dev/null || true
sudo update-desktop-database \
/var/lib/flatpak/exports/share/applications \
2>/dev/null || true
```
Log out and back in if an application still does not appear.
Direct launch examples:
```bash
flatpak run hu.irl.cameractrls
flatpak run io.missioncenter.MissionCenter
flatpak run com.valvesoftware.Steam
flatpak run com.slack.Slack
```
---
## 28. Repair Ubuntu CA certificates
Use this section if `apt`, `curl`, or another HTTPS client reports certificate-chain errors.
Ubuntu's primary CA bundle is:
```text
/etc/ssl/certs/ca-certificates.crt
```
Check it:
```bash
ls -l /etc/ssl/certs/ca-certificates.crt
test -r /etc/ssl/certs/ca-certificates.crt && echo "CA bundle is readable"
```
Reinstall the CA package:
```bash
sudo apt update
sudo apt install --reinstall -y ca-certificates
```
Regenerate the certificate bundle:
```bash
sudo update-ca-certificates --fresh
```
Verify:
```bash
ls -lh /etc/ssl/certs/ca-certificates.crt
```
Test HTTPS:
```bash
curl -I https://ubuntu.com
curl -I https://download.docker.com
curl -I https://slack.com
```
If `apt update` itself cannot run because of certificate problems, reinstall from the package cache if the package is present:
```bash
ls /var/cache/apt/archives/ca-certificates_*.deb 2>/dev/null
```
Then:
```bash
sudo dpkg -i /var/cache/apt/archives/ca-certificates_*.deb
sudo update-ca-certificates --fresh
```
Do not disable TLS verification as a workaround.
---
## 29. Work around slow or failing Ubuntu mirrors
If `apt update` or an install repeatedly times out, first retry with APT's retry setting:
```bash
sudo apt-get \
-o Acquire::Retries=5 \
update
```
For a package install:
```bash
sudo apt-get \
-o Acquire::Retries=5 \
install -y PACKAGE_NAME
```
Inspect configured Ubuntu mirrors:
```bash
grep -R -E '^(URIs:|deb )' \
/etc/apt/sources.list \
/etc/apt/sources.list.d 2>/dev/null
```
On Ubuntu 26.04, the primary Ubuntu configuration commonly uses:
```text
/etc/apt/sources.list.d/ubuntu.sources
```
Before editing it:
```bash
sudo cp -a \
/etc/apt/sources.list.d/ubuntu.sources \
"/etc/apt/sources.list.d/ubuntu.sources.backup.$(date +%Y%m%d-%H%M%S)"
```
You can also change the mirror through Ubuntu's graphical software-source settings rather than editing the file manually.
After changing a mirror:
```bash
sudo apt clean
sudo rm -rf /var/lib/apt/lists/partial/*
sudo apt update
```
If only a third-party repository is failing, do not break the main Ubuntu repositories trying to fix it. Inspect the specific vendor source:
```bash
ls -1 /etc/apt/sources.list.d/
```
Temporarily disable a problematic third-party `.list` file by renaming it:
```bash
sudo mv \
/etc/apt/sources.list.d/problem.list \
/etc/apt/sources.list.d/problem.list.disabled
sudo apt update
```
For deb822 `.sources` files, rename the file similarly:
```bash
sudo mv \
/etc/apt/sources.list.d/problem.sources \
/etc/apt/sources.list.d/problem.sources.disabled
sudo apt update
```
---
## 30. Final verification script
Run this from a fresh Terminator session:
```bash
cat > /tmp/verify-ubuntu-dev-env.sh <<'VERIFY'
#!/usr/bin/env bash
set -u
section() {
printf '\n== %s ==\n' "$1"
}
section "System"
cat /etc/os-release || true
uname -r || true
hostnamectl | sed -n '1,12p' || true
section "Storage mounts"
lsblk -e7 -o NAME,SIZE,FSTYPE,LABEL,UUID,MODEL,MOUNTPOINTS || true
findmnt --real || true
findmnt --verify --verbose || true
section "Desktop"
echo "XDG_CURRENT_DESKTOP=${XDG_CURRENT_DESKTOP:-unknown}"
echo "XDG_SESSION_TYPE=${XDG_SESSION_TYPE:-unknown}"
echo "DESKTOP_SESSION=${DESKTOP_SESSION:-unknown}"
section "Shell"
echo "SHELL=$SHELL"
zsh --version || true
section "Terminator"
command -v terminator || true
terminator --version 2>/dev/null || true
section "Git"
git --version || true
git lfs version || true
section "AWS CLI"
aws --version || true
section "Node via nvm"
zsh -ic \
'command -v nvm && nvm --version && node --version && npm --version' \
|| true
section "NVIDIA"
cat /proc/driver/nvidia/version 2>/dev/null || true
nvidia-smi || true
lsmod | grep '^nvidia' || true
glxinfo -B 2>/dev/null | \
grep -E 'OpenGL vendor|OpenGL renderer' || true
vulkaninfo --summary 2>/dev/null | \
grep -Ei 'deviceName|driverName' || true
section "Docker Engine"
docker --version || true
docker compose version || true
docker context ls || true
systemctl status docker --no-pager 2>/dev/null | sed -n '1,12p' || true
section "NVIDIA Container Toolkit"
command -v nvidia-ctk || true
dpkg -l 2>/dev/null | grep nvidia-container-toolkit || true
section "Docker Desktop"
systemctl --user status docker-desktop --no-pager 2>/dev/null | \
sed -n '1,12p' || true
section "Google Chrome"
command -v google-chrome-stable || true
google-chrome-stable --version 2>/dev/null || true
dpkg -l 2>/dev/null | grep google-chrome-stable || true
section "VS Code"
code --version 2>/dev/null | head -n 2 || true
section "Cursor"
command -v cursor || true
cursor --version 2>/dev/null | head -n 2 || true
section "Antigravity"
command -v antigravity || true
antigravity --version 2>/dev/null | head -n 2 || true
section "Postman"
command -v postman || true
ls /opt/Postman/Postman 2>/dev/null || true
section "LM Studio"
ls "$HOME/Applications"/*Studio*.AppImage 2>/dev/null || true
ls "$HOME/.local/share/applications"/*lm*studio*.desktop \
2>/dev/null || true
section "Slack"
command -v slack || true
dpkg -l 2>/dev/null | grep -i slack || true
flatpak list 2>/dev/null | grep -i slack || true
section "Steam and gaming"
command -v steam || true
flatpak list 2>/dev/null | grep -i steam || true
command -v gamemoderun || true
command -v mangohud || true
command -v gamescope || true
section "Monitoring"
command -v nvtop || true
command -v btop || true
flatpak list 2>/dev/null | grep -i mission || true
section "Camera"
command -v v4l2-ctl || true
flatpak list 2>/dev/null | grep -i camera || true
command -v guvcview || true
command -v obs || true
section "Printer"
lpstat -t 2>/dev/null || true
section "APT"
sudo apt-get check || true
apt list --upgradable 2>/dev/null | head -n 30 || true
VERIFY
chmod +x /tmp/verify-ubuntu-dev-env.sh
bash /tmp/verify-ubuntu-dev-env.sh
```
---
## 31. Maintenance and updates
Update Ubuntu packages:
```bash
sudo apt update
sudo apt full-upgrade -y
sudo apt autoremove -y
```
Update Flatpaks:
```bash
flatpak update -y
```
Update Snaps if you use any:
```bash
sudo snap refresh
```
Update Oh My Zsh:
```bash
omz update
```
Update Node LTS:
```bash
nvm install --lts
nvm alias default "lts/*"
```
Update AWS CLI v2:
```bash
cd /tmp
rm -rf aws awscliv2.zip
curl -fsSL \
"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" \
-o awscliv2.zip
unzip -q awscliv2.zip
sudo ./aws/install \
--bin-dir /usr/local/bin \
--install-dir /usr/local/aws-cli \
--update
aws --version
```
Update Postman:
```bash
cd /tmp
curl -L \
-o postman-linux-x64.tar.gz \
https://dl.pstmn.io/download/latest/linux64
sudo rm -rf /opt/Postman
sudo tar -xzf postman-linux-x64.tar.gz -C /opt
sudo ln -sfn /opt/Postman/Postman /usr/local/bin/postman
```
Update LM Studio:
1. Download the newest Linux x64 AppImage.
2. Replace the existing AppImage:
```bash
LM_APPIMAGE="$(
find "$HOME/Downloads" -maxdepth 1 -type f \
\( -iname '*LM*Studio*.AppImage' -o -iname '*LMStudio*.AppImage' \) \
| sort | tail -n 1
)"
test -n "$LM_APPIMAGE" || {
echo "Download the new LM Studio AppImage first."
exit 1
}
install -Dm755 \
"$LM_APPIMAGE" \
"$HOME/Applications/LM-Studio.AppImage"
```
Update NVIDIA through Ubuntu's normal package flow:
```bash
sudo apt update
sudo apt full-upgrade -y
```
Check whether Ubuntu now recommends a different supported branch:
```bash
ubuntu-drivers devices
```
Do not switch NVIDIA driver branches merely because a numerically newer package exists. Prefer Ubuntu's recommended branch unless you are fixing a specific problem.
Update Docker Engine:
```bash
sudo apt update
sudo apt install \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
```
Update Docker Desktop by downloading the latest DEB and installing it over the existing package:
```bash
sudo apt install ./docker-desktop-amd64.deb
```
---
## 32. Quick run order for a fresh install
Use this order on a fresh Ubuntu 26.04 LTS workstation:
1. Install Ubuntu Desktop 26.04 LTS and enable third-party drivers/software during installation.
2. Fully update Ubuntu and reboot.
3. Inventory the internal disks and configure UUID-based automatic mounts.
4. Install Terminator.
5. Enable Universe, Multiverse, and Restricted.
6. Install the base developer packages.
7. Configure Git.
8. Install Zsh and Oh My Zsh.
9. Install nvm and Node.js LTS.
10. Install AWS CLI v2.
11. Install the NVIDIA driver with `ubuntu-drivers` and reboot.
12. Verify `nvidia-smi`, OpenGL, and Vulkan.
13. Install Docker Engine and Compose.
14. Install NVIDIA Container Toolkit if you need GPU containers.
15. Install Docker Desktop if you want the GUI.
16. Install Google Chrome.
17. Install VS Code, Cursor, Antigravity, and Postman.
18. Install Slack.
19. Install LM Studio and its launcher.
20. Install Steam, GameMode, MangoHud, and Gamescope.
21. Install Mission Center, nvtop, and btop.
22. Install camera tools.
23. Set up the Brother printer.
24. Run the final verification script.
---
## 33. References
Ubuntu:
- Ubuntu Desktop download: https://ubuntu.com/download/desktop
- Ubuntu 26.04 LTS release notes: https://documentation.ubuntu.com/release-notes/26.04/
- Ubuntu Desktop installation: https://documentation.ubuntu.com/desktop/en/latest/tutorial/install-ubuntu-desktop/
- Ubuntu package management: https://documentation.ubuntu.com/server/how-to/software/package-management/
- Ubuntu NVIDIA driver installation: https://ubuntu.com/desktop/docs/en/latest/how-to/graphics/install-nvidia-drivers/
- Ubuntu Server NVIDIA driver installation: https://ubuntu.com/server/docs/nvidia-drivers-installation/
- Ubuntu package search: https://packages.ubuntu.com/
Developer tools:
- Git: https://git-scm.com/install/linux
- Oh My Zsh: https://ohmyz.sh/
- nvm: https://github.com/nvm-sh/nvm
- AWS CLI v2: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
- Visual Studio Code Linux install: https://code.visualstudio.com/docs/setup/linux
- Cursor: https://cursor.com/docs/get-started/quickstart
- Google Antigravity Linux install: https://antigravity.google/download/linux
- Postman: https://www.postman.com/downloads/
Containers and GPU:
- Docker Engine Ubuntu: https://docs.docker.com/engine/install/ubuntu/
- Docker Desktop Ubuntu: https://docs.docker.com/desktop/setup/install/linux/ubuntu/
- NVIDIA Container Toolkit: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html
- Docker GPU access: https://docs.docker.com/engine/containers/gpu/
Desktop applications:
- Google Chrome Linux: https://support.google.com/chrome/a/answer/9025926
- Slack Linux: https://slack.com/downloads/linux
- LM Studio: https://lmstudio.ai/download?os=linux
- AppImage FUSE troubleshooting: https://docs.appimage.org/user-guide/troubleshooting/fuse.html
- Steam: https://packages.ubuntu.com/resolute/steam-installer
- Mission Center: https://flathub.org/apps/io.missioncenter.MissionCenter
- Cameractrls: https://flathub.org/apps/hu.irl.cameractrls
Printing:
- Brother HL-L2405W support: https://support.brother.com/g/b/downloadtop.aspx?c=us&lang=en&prod=hll2405w_us
- CUPS: https://www.cups.org/doc/admin.html
---
## 34. Install and Configure Nginx on Ubuntu Server 26.04 LTS for a DigitalOcean Droplet
These notes target an Ubuntu Server 26.04 LTS DigitalOcean Droplet.
Ubuntu installs Nginx with APT, manages it with systemd, uses UFW as the common host firewall frontend, uses AppArmor rather than SELinux, and follows the Debian-style Nginx layout:
```text
/etc/nginx/sites-available/
/etc/nginx/sites-enabled/
```
This section covers:
- Updating Ubuntu
- Installing Nginx
- Starting and enabling the service
- Opening Ubuntu's UFW firewall
- Checking DigitalOcean Cloud Firewall rules
- Creating a website directory
- Configuring an Nginx server block
- Testing and reloading Nginx
- Pointing DNS to the Droplet
- Installing HTTPS with Certbot
- Viewing logs
- Setting up a reverse proxy
- AppArmor-aware troubleshooting
- Common failure checks
### 34.1 SSH into the Droplet
Use the IP address from the DigitalOcean dashboard.
For root, if root SSH is enabled:
```bash
ssh root@YOUR_DROPLET_IP
```
Prefer a regular sudo-enabled user for normal administration:
```bash
ssh cesar@YOUR_DROPLET_IP
```
### 34.2 Update Ubuntu
```bash
sudo apt update
sudo apt full-upgrade -y
sudo apt autoremove -y
```
Check whether a reboot is recommended:
```bash
if [ -f /var/run/reboot-required ]; then
cat /var/run/reboot-required
fi
```
If required:
```bash
sudo reboot
```
Reconnect afterward:
```bash
ssh cesar@YOUR_DROPLET_IP
```
### 34.3 Install Nginx
```bash
sudo apt install -y nginx
```
Verify:
```bash
nginx -v
dpkg -s nginx | grep -E 'Status|Version'
```
### 34.4 Enable and start Nginx
Ubuntu normally starts Nginx during package installation.
Ensure it is enabled and running:
```bash
sudo systemctl enable --now nginx
```
Check:
```bash
sudo systemctl status nginx --no-pager
```
Expected:
```text
Active: active (running)
```
### 34.5 Configure UFW for SSH, HTTP, and HTTPS
Install UFW if needed:
```bash
sudo apt install -y ufw
```
Before enabling UFW on a remote server, permit SSH:
```bash
sudo ufw allow OpenSSH
```
List Nginx application profiles:
```bash
sudo ufw app list
```
Allow both HTTP and HTTPS:
```bash
sudo ufw allow 'Nginx Full'
```
If UFW is not already enabled:
```bash
sudo ufw enable
```
Verify:
```bash
sudo ufw status verbose
```
You should see rules allowing OpenSSH and Nginx Full.
> Important: Docker-published ports can bypass normal UFW filtering. If this Droplet also runs Docker, review Docker's firewall behavior separately.
### 34.6 Check the DigitalOcean Cloud Firewall
DigitalOcean Cloud Firewalls are separate from UFW. If both are in use, both layers need to permit the traffic.
Make sure the Cloud Firewall attached to the Droplet allows:
| Type | Protocol | Port | Source |
| --- | --- | --- | --- |
| SSH | TCP | 22 | Your IP when practical |
| HTTP | TCP | 80 | `0.0.0.0/0`, `::/0` |
| HTTPS | TCP | 443 | `0.0.0.0/0`, `::/0` |
Do not remove SSH access before confirming an alternate path into the server.
### 34.7 Test the default Nginx page
From your local machine:
```text
http://YOUR_DROPLET_IP
```
Or:
```bash
curl -I http://YOUR_DROPLET_IP
```
A working response should include something similar to:
```text
HTTP/1.1 200 OK
Server: nginx
```
### 34.8 Create a basic website directory
Replace `example.com` with your domain:
```bash
sudo mkdir -p /var/www/example.com/html
```
Create a test page:
```bash
sudo tee /var/www/example.com/html/index.html > /dev/null <<'HTML'
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>example.com</title>
</head>
<body>
<h1>Nginx is working on Ubuntu 26.04 LTS</h1>
</body>
</html>
HTML
```
For a simple static site, make `www-data` the owner:
```bash
sudo chown -R www-data:www-data /var/www/example.com
```
Set normal web permissions:
```bash
sudo find /var/www/example.com -type d -exec chmod 755 {} \;
sudo find /var/www/example.com -type f -exec chmod 644 {} \;
```
If your deployment process needs your user to own the files instead, use a group-based deployment model rather than repeatedly making everything world-writable.
### 34.9 Ubuntu security model: AppArmor instead of SELinux
The Fedora version required SELinux labeling for custom web roots. Ubuntu does **not** use SELinux labeling by default, so there is no `semanage fcontext` or `restorecon` step here.
Check AppArmor status:
```bash
sudo aa-status
```
For a normal Nginx installation serving `/var/www`, standard Unix file permissions are usually the relevant access control.
If you see an unexpected denial, inspect kernel logs:
```bash
sudo journalctl -k | grep -i apparmor | tail -n 100
```
Do not disable AppArmor globally as a troubleshooting shortcut.
### 34.10 Create an Nginx server block
Ubuntu uses `sites-available` and `sites-enabled`.
Create the configuration:
```bash
sudo nano /etc/nginx/sites-available/example.com
```
Add:
```nginx
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
location / {
try_files $uri $uri/ =404;
}
}
```
Enable the site:
```bash
sudo ln -sfn \
/etc/nginx/sites-available/example.com \
/etc/nginx/sites-enabled/example.com
```
### 34.11 Test and reload Nginx
Test syntax:
```bash
sudo nginx -t
```
If successful:
```bash
sudo systemctl reload nginx
```
Check status:
```bash
sudo systemctl status nginx --no-pager
```
### 34.12 Point your domain to the Droplet
Create DNS records at your DNS provider:
| Type | Name | Value |
| --- | --- | --- |
| A | `@` | `YOUR_DROPLET_IPV4` |
| A | `www` | `YOUR_DROPLET_IPV4` |
| AAAA | `@` | `YOUR_DROPLET_IPV6`, optional |
| AAAA | `www` | `YOUR_DROPLET_IPV6`, optional |
Install DNS tools:
```bash
sudo apt install -y dnsutils
```
Test:
```bash
dig +short example.com
dig +short www.example.com
```
Then:
```bash
curl -I http://example.com
curl -I http://www.example.com
```
### 34.13 Install HTTPS with Certbot
Install Certbot and the Nginx plugin:
```bash
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
```
Request and configure the certificate:
```bash
sudo certbot --nginx \
-d example.com \
-d www.example.com
```
Follow the prompts.
Test:
```bash
curl -I https://example.com
```
Check renewal:
```bash
sudo certbot renew --dry-run
```
Check the timer if your package config uses systemd renewal:
```bash
systemctl list-timers | grep -i certbot || true
```
### 34.14 Useful Nginx commands
Status:
```bash
sudo systemctl status nginx --no-pager
```
Start:
```bash
sudo systemctl start nginx
```
Stop:
```bash
sudo systemctl stop nginx
```
Restart:
```bash
sudo systemctl restart nginx
```
Reload without a full restart:
```bash
sudo systemctl reload nginx
```
Test configuration:
```bash
sudo nginx -t
```
Version:
```bash
nginx -v
```
Full active configuration:
```bash
sudo nginx -T
```
### 34.15 Useful log commands
Default access log:
```bash
sudo tail -f /var/log/nginx/access.log
```
Default error log:
```bash
sudo tail -f /var/log/nginx/error.log
```
Custom site logs:
```bash
sudo tail -f /var/log/nginx/example.com.access.log
sudo tail -f /var/log/nginx/example.com.error.log
```
Systemd journal:
```bash
sudo journalctl -u nginx -f
```
Recent service logs:
```bash
sudo journalctl -u nginx -n 100 --no-pager
```
### 34.16 Basic reverse proxy example
Use this if Nginx should proxy to a local Node.js, Next.js, Strapi, Express, Fastify, Astro, or similar application.
Example application port:
```text
3000
```
Create:
```bash
sudo nano /etc/nginx/sites-available/app.example.com
```
Add:
```nginx
server {
listen 80;
listen [::]:80;
server_name app.example.com;
access_log /var/log/nginx/app.example.com.access.log;
error_log /var/log/nginx/app.example.com.error.log;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
Enable:
```bash
sudo ln -sfn \
/etc/nginx/sites-available/app.example.com \
/etc/nginx/sites-enabled/app.example.com
```
Test and reload:
```bash
sudo nginx -t
sudo systemctl reload nginx
```
Unlike the Fedora SELinux workflow, there is no `setsebool -P httpd_can_network_connect 1` command on Ubuntu.
Confirm the upstream application is listening:
```bash
sudo ss -ltnp | grep ':3000'
```
Test it locally:
```bash
curl -I http://127.0.0.1:3000
```
### 34.17 Remove or disable the default welcome site
Ubuntu enables the default Nginx site through:
```text
/etc/nginx/sites-enabled/default
```
After your real site works, disable it:
```bash
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
```
Keep `/etc/nginx/sites-available/default` if you want the packaged example available for reference.
### 34.18 Quick troubleshooting checklist
#### Nginx is not running
```bash
sudo systemctl status nginx --no-pager
sudo journalctl -u nginx -n 100 --no-pager
```
#### Nginx config has an error
```bash
sudo nginx -t
```
Print the full parsed configuration:
```bash
sudo nginx -T
```
#### UFW is blocking traffic
```bash
sudo ufw status verbose
sudo ufw app list
```
#### Port 80 or 443 is not listening
```bash
sudo ss -tulpn | grep -E ':(80|443)\b'
```
#### DNS is not pointing to the Droplet
```bash
dig +short example.com
dig +short www.example.com
```
#### File permissions may be blocking Nginx
```bash
namei -l /var/www/example.com/html/index.html
sudo -u www-data test -r /var/www/example.com/html/index.html && \
echo "www-data can read the file"
```
#### AppArmor may be involved
```bash
sudo aa-status
sudo journalctl -k | grep -i apparmor | tail -n 100
```
Do not disable AppArmor globally. Fix the actual policy or path problem if an AppArmor denial is genuinely present.
#### Reverse proxy upstream is unavailable
```bash
sudo ss -ltnp | grep ':3000'
curl -v http://127.0.0.1:3000/
```
If the app is in Docker, verify the container and port mapping:
```bash
docker ps
docker compose ps
```
#### DigitalOcean Cloud Firewall is blocking traffic
In DigitalOcean, verify inbound rules for:
- TCP 22 for SSH
- TCP 80 for HTTP
- TCP 443 for HTTPS
Remember that DigitalOcean Cloud Firewall and UFW are independent layers.
### 34.19 Recommended file layout
Static site:
```text
/var/www/example.com/html/index.html
/etc/nginx/sites-available/example.com
/etc/nginx/sites-enabled/example.com
/var/log/nginx/example.com.access.log
/var/log/nginx/example.com.error.log
```
Reverse proxy:
```text
/etc/nginx/sites-available/app.example.com
/etc/nginx/sites-enabled/app.example.com
/var/log/nginx/app.example.com.access.log
/var/log/nginx/app.example.com.error.log
```
### 34.20 Nginx and DigitalOcean references
- Ubuntu Nginx documentation: https://ubuntu.com/server/docs/how-to/web-services/configure-nginx/
- Ubuntu Server documentation: https://ubuntu.com/server/docs/
- UFW documentation: https://help.ubuntu.com/community/UFW
- DigitalOcean Cloud Firewall: https://docs.digitalocean.com/products/networking/firewalls/how-to/configure-rules/
- Certbot: https://certbot.eff.org/
- Nginx documentation: https://nginx.org/en/docs/
- CUPS administration: https://www.cups.org/doc/admin.html
---
## 35. Ubuntu-specific differences from the Fedora walkthrough
For reference, these are the most important platform changes made during this conversion.
| Fedora workflow | Ubuntu 26.04 LTS workflow |
| --- | --- |
| `dnf` | `apt` / `apt-get` |
| RPM packages | DEB packages |
| RPM Fusion | Ubuntu Universe / Multiverse / Restricted |
| `akmod-nvidia` | `ubuntu-drivers install` |
| Manual akmods rebuild | Ubuntu kernel module packages/DKMS as selected by driver packages |
| Fedora MOK/akmods flow | Ubuntu signed modules plus MOK enrollment when prompted |
| `firewalld` | UFW |
| SELinux | AppArmor |
| `/etc/nginx/conf.d/*.conf` as primary site layout | `/etc/nginx/sites-available` + `/etc/nginx/sites-enabled` |
| Nginx worker user `nginx` | Nginx worker user `www-data` |
| `.rpm` Chrome/Slack/Docker Desktop | `.deb` packages |
| RPM Fusion Steam | Ubuntu `steam-installer` from Multiverse |
| `fuse`/`fuse-libs` | `fuse3` + `libfuse2t64` for AppImage compatibility |
| `glx-utils` | `mesa-utils` |
| `kernel-devel` | `linux-headers-$(uname -r)` when specifically needed |
| `rpm -q` | `dpkg -s` / `dpkg -l` / `apt-cache policy` |
The rest of the developer workflow remains broadly the same.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment