Skip to content

Instantly share code, notes, and snippets.

@lazanet
Last active August 3, 2026 23:25
Show Gist options
  • Select an option

  • Save lazanet/dca0f48efc1b54901d29c3265f29d07f to your computer and use it in GitHub Desktop.

Select an option

Save lazanet/dca0f48efc1b54901d29c3265f29d07f to your computer and use it in GitHub Desktop.
Script that sets up Ubuntu 26.04 to my liking
#!/usr/bin/env -S bash -e
set -o xtrace
set -e
WORK=${WORK-0}
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# GraalVM CE version to install via sdkman (must be a full sdkman identifier).
# Bump this as new releases land: `sdk list java | grep graalce`.
JAVA_VERSION=25.0.2-graalce
function set_gnome_configuration {
# Configure power settings
dconf write /org/gnome/desktop/session/idle-delay "uint32 0"
dconf write /org/gnome/settings-daemon/plugins/power/sleep-inactive-battery-timeout 1800
dconf write /org/gnome/settings-daemon/plugins/power/sleep-inactive-ac-type "'nothing'"
# Disable Gnome animations
gsettings set org.gnome.desktop.interface enable-animations false
# Dock settings
gsettings set org.gnome.shell.extensions.dash-to-dock show-apps-at-top true
dconf write /org/gnome/shell/extensions/dash-to-dock/dash-max-icon-size 24
dconf write /org/gnome/shell/extensions/dash-to-dock/multi-monitor true
dconf write /org/gnome/shell/extensions/dash-to-dock/isolate-workspaces true
dconf write /org/gnome/shell/extensions/dash-to-dock/isolate-monitors false
dconf write /org/gnome/shell/extensions/tiling-assistant/enable-tiling-popup false
# Add Sr1 EN Sr2 keyboard layouts
dconf write /org/gnome/desktop/input-sources/sources "[('xkb', 'rs+latin'), ('xkb', 'us'), ('xkb', 'rs')]"
# Use GB locale (uses metric + Monday is the first day of the week)
# Generate it first; on a fresh 26.04 only C/POSIX exist, so update-locale would reject it
sudo locale-gen en_GB.UTF-8
sudo update-locale LC_NUMERIC=en_GB.UTF-8 LC_TIME=en_GB.UTF-8 LC_MONETARY=en_GB.UTF-8 LC_PAPER=en_GB.UTF-8 LC_NAME=en_GB.UTF-8 LC_ADDRESS=en_GB.UTF-8 LC_TELEPHONE=en_GB.UTF-8 LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=en_GB.UTF-8
# Enable Shift + Alt for switching keyboard layouts
gsettings set org.gnome.desktop.wm.keybindings switch-input-source "['<Alt>Shift_L', 'XF86Keyboard']"
gsettings set org.gnome.desktop.input-sources xkb-options "['grp_led:scroll', 'grp:alt_shift_toggle']"
gsettings set org.gnome.desktop.wm.preferences button-layout ":minimize,maximize,close"
# Change background
sudo wget https://github.com/twinysam/ubuntu-wallpapers/raw/applied/ubuntu/artful/ubuntu_by_arman1992.jpg -O /usr/share/backgrounds/ubuntu_by_arman1992.jpg
gsettings set org.gnome.desktop.background picture-uri "file:///usr/share/backgrounds/ubuntu_by_arman1992.jpg"
gsettings set org.gnome.desktop.background picture-uri-dark "file:///usr/share/backgrounds/ubuntu_by_arman1992.jpg"
# Enable dark theme
gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark'
gsettings set org.gnome.desktop.interface gtk-theme 'Yaru-blue-dark'
# Setup Ptyxis terminal theme (Ptyxis replaces GNOME Terminal as the default on 26.04)
PROFILE=$(dconf read /org/gnome/Ptyxis/default-profile-uuid 2>/dev/null | tr -d "'")
if [ -z "$PROFILE" ]; then
PROFILE=$(uuidgen | tr -d '-')
dconf write /org/gnome/Ptyxis/profile-uuids "['$PROFILE']"
dconf write /org/gnome/Ptyxis/default-profile-uuid "'$PROFILE'"
fi
dconf write /org/gnome/Ptyxis/interface-style "'dark'" # force dark UI
# Install and select a custom palette matching the old GNOME Terminal colors exactly
# (bg #040504, fg #D3CFCD, classic GNOME Terminal ANSI colors)
mkdir -p ~/.local/share/org.gnome.Ptyxis/palettes
ptyxis --import-palette "$SCRIPT_DIR/gnome-terminal-classic.palette" \
|| cp "$SCRIPT_DIR/gnome-terminal-classic.palette" ~/.local/share/org.gnome.Ptyxis/palettes/
dconf write /org/gnome/Ptyxis/Profiles/$PROFILE/palette "'gnome-terminal-classic'"
dconf write /org/gnome/Ptyxis/Profiles/$PROFILE/opacity 0.8 # ~old 20% transparency
# Setup gedit theme
sudo apt -y install gedit
gsettings set org.gnome.gedit.preferences.editor display-line-numbers true
# gedit 48 (GTK4) replaced the single 'scheme' key with per-theme-variant keys
gsettings set org.gnome.gedit.preferences.editor style-scheme-for-dark-theme-variant 'solarized-dark'
gsettings set org.gnome.gedit.preferences.editor style-scheme-for-light-theme-variant 'solarized-light'
dconf write /org/gnome/gedit/preferences/editor/tabs-size "uint32 4"
# Setup gnome-text-editor theme
dconf write /org/gnome/TextEditor/show-line-numbers true
dconf write /org/gnome/TextEditor/style-variant "'follow'"
dconf write /org/gnome/TextEditor/style-scheme "'solarized-dark'"
dconf write /org/gnome/TextEditor/show-map true
dconf write /org/gnome/TextEditor/restore-session true
# Top bar tweaks
gsettings set org.gnome.desktop.interface clock-show-seconds true
gsettings set org.gnome.desktop.interface show-battery-percentage true
dconf write /org/gnome/desktop/sound/allow-volume-above-100-percent true
# Nautilus tweaks
dconf write /org/gnome/nautilus/preferences/show-create-link true
dconf write /org/gnome/nautilus/preferences/show-delete-permanently true
dconf write /org/gnome/nautilus/preferences/date-time-format "'detailed'"
# Configure workspaces
gsettings set org.gnome.mutter dynamic-workspaces false
gsettings set org.gnome.desktop.wm.preferences num-workspaces 2
gsettings set org.gnome.mutter workspaces-only-on-primary false
gsettings set org.gnome.shell.extensions.dash-to-dock isolate-workspaces true
gsettings set org.gnome.shell disable-extension-version-validation true
# Needs a live gnome-shell session; don't abort the script if run headless
gnome-extensions enable tiling-assistant@ubuntu.com || true
}
function gnome_extensions {
sudo apt -y install curl git
pushd $(mktemp -d)
wget -O gnome-shell-extension-installer "https://github.com/brunelli/gnome-shell-extension-installer/raw/master/gnome-shell-extension-installer"
chmod +x gnome-shell-extension-installer
./gnome-shell-extension-installer 1319 # https://extensions.gnome.org/extension/1319/gsconnect/
./gnome-shell-extension-installer 4559 # https://extensions.gnome.org/extension/4559/quick-lang-switch/
popd
# multi-monitors-add-on: clone once, update on re-run
mkdir -p ~/.local/share/gnome-shell/extensions
if [ ! -d ~/multi-monitors-add-on ]; then
git clone https://github.com/lazanet/multi-monitors-add-on.git ~/multi-monitors-add-on
else
git -C ~/multi-monitors-add-on pull --ff-only || true
fi
ln -srfn ~/multi-monitors-add-on/multi-monitors-add-on@spin83 ~/.local/share/gnome-shell/extensions/multi-monitors-add-on@spin83
}
function desnap {
# Ubuntu 26.04 ships Firefox and the App Store as snaps. We want flatpak instead,
# so ensure replacements exist (Firefox is installed in flatpak_packages, which runs
# first), then remove every snap and pin snapd so it can't return. Idempotent: safe
# to re-run after snapd is already gone.
# Flatpak-friendly Software store, plus the firmware-update GUI. fwupd (the daemon
# that actually applies firmware updates) is already a deb; only the "Firmware
# Updater" GUI ships as a snap, so gnome-firmware keeps that capability.
sudo apt -y install --install-suggests gnome-software
sudo apt -y install gnome-software-plugin-flatpak gnome-firmware
sudo apt -y purge gnome-software-plugin-snap || true
# Pin snapd FIRST so it can never come back as a dependency. Writing the pin up
# front means a later failure (e.g. a busy /snap mount making `rm` fail under
# `set -e`) can't abort the run and leave the system UNpinned — where the next
# `apt upgrade` could quietly pull snapd back via ubuntu-desktop's Recommends.
printf 'Package: snapd\nPin: release a=*\nPin-Priority: -10\n' | sudo tee /etc/apt/preferences.d/nosnap.pref
sudo apt-mark hold snapd || true
# Remove the Firefox/Thunderbird transitional stub debs (they exist only to
# install the corresponding snaps).
sudo apt -y purge firefox thunderbird || true
# Remove every installed snap (leaf snaps first, then bases/core/snapd). Bounded:
# if a full pass removes nothing (a snap is genuinely stuck), break instead of
# spinning forever.
while [ -n "$(snap list 2>/dev/null | tail -n +2)" ]; do
before=$(snap list 2>/dev/null | tail -n +2 | wc -l)
for s in $(snap list 2>/dev/null | tail -n +2 | awk '{print $1}'); do
sudo snap remove --purge "$s" || true
done
[ "$(snap list 2>/dev/null | tail -n +2 | wc -l)" -eq "$before" ] && break
done
sudo systemctl stop snapd.service snapd.socket 2>/dev/null || true
sudo apt -y purge snapd || true
sudo apt -y autoremove --purge
# Unmount any leftover snap squashfs mounts before wiping the dirs, and guard the
# rm with `|| true` so a stubborn mount can't abort the script (the pin is already
# safely in place above).
mount | awk '/\/snap|snapd/{print $3}' | sort -r | while read -r m; do sudo umount -l "$m" 2>/dev/null || true; done
rm -rf ~/snap
sudo rm -rf /snap /var/snap /var/lib/snapd /var/cache/snapd /usr/lib/snapd || true
}
function apt_packages {
set -e
sudo apt update
sudo apt clean
sudo apt -y autoremove
# Enable multiverse (Steam lives there) and 32-bit architecture (Steam needs i386)
sudo add-apt-repository -y multiverse
sudo dpkg --add-architecture i386
# Add kisak-mesa repository
# sudo add-apt-repository -y ppa:kisak/kisak-mesa
# Add VSCode
if ! command -v code >/dev/null 2>&1; then
pushd $(mktemp -d)
wget https://update.code.visualstudio.com/latest/linux-deb-x64/stable -O code.deb
sudo apt -y install ./code.deb
popd
fi
sudo apt update && sudo apt -y upgrade
sudo apt -y install libgl1-mesa-dri:i386 mesa-vulkan-drivers mesa-vulkan-drivers:i386
sudo apt -y install curl gpg vlc gnome-snapshot fastfetch gnome-tweaks gnome-shell-extension-manager file-roller build-essential git code cifs-utils rar remmina sqlitebrowser baobab fzf mc ptyxis uuid-runtime
if [ $WORK == "0" ]; then
# Steam via Valve's official deb (sets up repo.steampowered.com + signing key
# on install, so it self-updates; provides the real "Steam" launcher)
if ! dpkg -s steam-launcher >/dev/null 2>&1; then
pushd $(mktemp -d)
wget https://repo.steampowered.com/steam/archive/stable/steam_latest.deb -O steam.deb
sudo apt -y install ./steam.deb
popd
fi
if ! dpkg -s teamviewer >/dev/null 2>&1; then
pushd $(mktemp -d)
wget https://download.teamviewer.com/download/linux/teamviewer_amd64.deb
sudo apt -y install ./teamviewer_amd64.deb
popd
fi
if ! dpkg -s megasync >/dev/null 2>&1; then
pushd $(mktemp -d)
wget https://mega.nz/linux/repo/xUbuntu_26.04/amd64/megasync-xUbuntu_26.04_amd64.deb -O mega.deb
sudo apt -y install ./mega.deb
popd
fi
fi
if ! dpkg -s zoom >/dev/null 2>&1; then
pushd $(mktemp -d)
wget https://zoom.us/client/latest/zoom_amd64.deb
sudo apt -y install ./zoom_amd64.deb
popd
fi
}
function flatpak_packages {
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
# Firefox as a flatpak (snap-free); installed before desnap removes the Firefox snap stub
flatpak install -y flathub org.mozilla.firefox org.onlyoffice.desktopeditors com.jetbrains.IntelliJ-IDEA-Community
if [ $WORK == "0" ]; then
flatpak install -y com.jetbrains.PyCharm-Community com.google.AndroidStudio
fi
export XDG_DATA_DIRS="/var/lib/flatpak/exports/share:$XDG_DATA_DIRS"
xdg-settings set default-web-browser org.mozilla.firefox.desktop || true
}
function set_term_configuration {
if ! grep -qF "init_sys customizations" ~/.bashrc 2>/dev/null; then
cat >> ~/.bashrc <<'EOF'
# init_sys customizations
export PS1="\[\033[01;34m\]\w\[\033[36m\]$(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/')\[\033[00m\]$ "
eval "$(fzf --bash)"
fastfetch
EOF
fi
}
function add_dock_icons {
# Add dock icons
gsettings set org.gnome.shell favorite-apps "['org.mozilla.firefox.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'org.gnome.Ptyxis.desktop', 'code.desktop', 'steam.desktop', 'com.teamviewer.TeamViewer.desktop', 'vlc.desktop', 'org.onlyoffice.desktopeditors.desktop', 'com.jetbrains.IntelliJ-IDEA-Community.desktop', 'com.jetbrains.PyCharm-Community.desktop', 'com.google.AndroidStudio.desktop']"
}
function install_sdkman {
# Install sdkman!
if [ ! -d "$HOME/.sdkman" ]; then
curl -s "https://get.sdkman.io" | bash
fi
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java "$JAVA_VERSION"
sdk install maven
sdk install gradle
}
apt_packages
flatpak_packages
desnap
gnome_extensions
set_gnome_configuration
set_term_configuration
add_dock_icons
install_sdkman
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment