Skip to content

Instantly share code, notes, and snippets.

@tuxerrante
Last active December 1, 2025 14:37
Show Gist options
  • Select an option

  • Save tuxerrante/4d4693a44abd56627ecf2c6526313adc to your computer and use it in GitHub Desktop.

Select an option

Save tuxerrante/4d4693a44abd56627ecf2c6526313adc to your computer and use it in GitHub Desktop.
fedora workstation 43 devops setup
#!/bin/bash
set -euo pipefail
# ====================================================================
# Fedora 43 Hyprland + ML4W Development Environment Setup
# https://www.fedoraproject.org/misc#everything
# ====================================================================
# Configuration Version: 2025.11.28
# This script sets up:
# - Hyprland wayland compositor with ML4W dotfiles
# - Modern shell utilities (fzf, bat, eza, zoxide, starship, fd, ripgrep)
# - DevOps tools (Go, Helm, K9s, kubectl, etc.)
# - Neovim Nightly with LazyVim
# - Custom Hyprland keybindings for Windows-like behavior
# ====================================================================
# ====================================================================
# CONFIGURABLE SETTINGS
# ====================================================================
readonly CONFIG_VERSION="2025.11.28"
readonly GO_VERSION="1.25.3"
readonly HELM_VERSION="4.0.1"
# readonly K9S_VERSION="0.50.16"
readonly GOLANGCI_VERSION="latest"
readonly GITLEAKS_VERSION="8.30.0"
readonly KUBECONFORM_VERSION="latest"
readonly KUBECTL_VERSION="stable"
readonly NERDFONT_VERSION="v3.4.0"
readonly KEYBOARD_LAYOUT="${KEYBOARD_LAYOUT:-it}"
# Logging Setup
readonly LOG_FILE="$HOME/fedora_setup_$(date +%Y%m%d_%H%M%S).log"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Redirect all output to both terminal and log file
exec > >(tee -a "$LOG_FILE")
exec 2>&1
# ====================================================================
# LOGGING FUNCTIONS
# ====================================================================
log_info() {
echo -e "\033[0;34m[INFO]\033[0m $*"
}
log_success() {
echo -e "\033[0;32m[OK]\033[0m $*"
}
log_warn() {
echo -e "\033[1;33m[WARN]\033[0m $*"
}
log_error() {
echo -e "\033[0;31m[ERROR]\033[0m $*"
}
# Function to add lines to bashrc idempotently
add_to_bashrc() {
local line="$1"
if ! grep -qxF "$line" ~/.bashrc; then
echo "$line" >>~/.bashrc
fi
}
# Wrapper for non-critical commands - continues on error
run_safe() {
local description="$1"
shift
if "$@" 2>&1 | tee -a "$LOG_FILE"; then
return 0
else
log_warn "$description failed, but continuing..."
return 0
fi
}
# ====================================================================
# 1. SYSTEM PREPARATION
# ====================================================================
prepare_system() {
log_info "Starting system update..."
sudo dnf update -y --refresh || log_warn "System update encountered errors but continuing..."
log_info "Removing unnecessary packages (Bloatware)..."
sudo dnf remove -y \
gnome-weather gnome-maps gnome-photos gnome-calendar \
evolution rhythmbox cheese totem yelp \
'libreoffice-*' || true
sudo dnf autoremove -y || true
log_success "System preparation completed."
}
# ====================================================================
# 2. BASE DEPENDENCIES
# ====================================================================
install_base_deps() {
log_info "Installing base build dependencies..."
sudo dnf install -y --best --skip-broken \
git curl wget make gcc gcc-c++ cmake ninja-build \
openssl-devel pkg-config ca-certificates fontconfig \
nodejs npm python3-pip unzip zip tar gzip \
util-linux-user dnf-plugins-core \
snapd \
fuse || log_warn "Some base dependencies failed to install"
log_success "Base dependencies installed."
}
# ====================================================================
# 3. HYPRLAND & GUI
# ====================================================================
install_hyprland() {
log_info "Enabling Hyprland COPR and installing components..."
sudo dnf copr enable -y solopasha/hyprland || log_warn "Failed to enable solopasha/hyprland copr"
sudo dnf install -y --best --skip-broken \
hyprland hyprlock hypridle hyprpaper hyprpicker \
xdg-desktop-portal-hyprland \
waybar mako dunst \
wofi rofi-wayland \
swaybg swayidle swaylock \
wl-clipboard grim slurp \
kitty alacritty \
hyprland-qtutils
log_info "Configuring Hyprland to autostart at boot..."
cat >~/.config/systemd/user/hyprland.service <<'EOF'
[Unit]
Description=Hyprland session
[Service]
ExecStart=/usr/bin/Hyprland
Restart=no
StandardInput=tty
TTYReset=yes
TTYVHangup=yes
[Install]
WantedBy=default.target
EOF
systemctl --user enable hyprland.service
sudo dnf install -y flatpak
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install -y flathub com.ml4w.dotfilesinstaller
echo "PASTE THIS 'https://raw.githubusercontent.com/mylinuxforwork/dotfiles/main/hyprland-dotfiles-stable.dotinst'"
flatpak run com.ml4w.dotfilesinstaller
log_success "Hyprland installation and autostart configured."
}
# ====================================================================
# 4. SHELL UTILITIES
# ====================================================================
install_shell_utils() {
log_info "Installing modern shell utilities..."
sudo dnf install -y --skip-broken \
fzf bat fd-find ripgrep zoxide \
btop htop ncdu jq yq fastfetch
# Fix for 'fd' command (Fedora names it fdfind)
if ! command -v fd &>/dev/null && command -v fdfind &>/dev/null; then
log_info "Symlinking fdfind to fd..."
sudo ln -sf /usr/bin/fdfind /usr/local/bin/fd
fi
log_success "Shell utilities installed."
ARCH="x64"
echo "Fetching Gitleaks v$GITLEAKS_VERSION for linux ($ARCH)..."
wget -q "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_${ARCH}.tar.gz"
tar -xf "gitleaks_${GITLEAKS_VERSION}_linux_${ARCH}.tar.gz"
rm "gitleaks_${GITLEAKS_VERSION}_linux_${ARCH}.tar.gz"
}
# ====================================================================
# 5. STARSHIP PROMPT
# ====================================================================
install_starship() {
log_info "Installing Starship prompt..."
curl -sS https://starship.rs/install.sh | sh -s -- -y || log_warn "Starship installation failed"
add_to_bashrc 'eval "$(starship init bash)"' || log_warn "Failed to add Starship to bashrc"
mkdir -p ~/.config
cat >~/.config/starship.toml <<'EOF'
format = "$directory$git_branch$git_status $character "
right_format = "$cmd_duration"
[directory]
truncation_length = 3
truncate_to_repo = true
[git_branch]
format = "[$symbol$branch]($style) "
style = "bold blue"
[git_status]
format = "[\\($all_status$ahead_behind\\)]($style) "
style = "bold red"
[character]
success_symbol = "[❯](bold green)"
error_symbol = "[❯](bold red)"
[cmd_duration]
min_time = 500
format = "took [$duration]($style)"
style = "bold yellow"
EOF
log_success "Starship installed and configured."
}
# ====================================================================
# 6. NEOVIM NIGHTLY + LAZYVIM
# ====================================================================
install_neovim() {
log_info "Installing Neovim Nightly AppImage..."
# Fetch the latest release tag
local nvim_tag
nvim_tag=$(curl -s https://api.github.com/repos/neovim/neovim/releases | grep -oP '"tag_name": "\K[^"]+' | head -n 1)
if [[ -z "$nvim_tag" ]]; then
log_warn "Could not fetch Neovim version tag from GitHub. Skipping."
return
fi
log_info "Detected Neovim version: $nvim_tag"
local download_url="https://github.com/neovim/neovim/releases/download/${nvim_tag}/nvim-linux-x86_64.appimage"
local target_path="/usr/local/bin/nvim"
log_info "Downloading AppImage from $download_url..."
if wget -q --show-progress "$download_url" -O /tmp/nvim.appimage; then
chmod u+x /tmp/nvim.appimage
log_info "Moving AppImage to $target_path..."
sudo mv /tmp/nvim.appimage "$target_path"
if command -v nvim &>/dev/null; then
log_success "Neovim ($nvim_tag) installed successfully."
else
log_error "Neovim binary not found after install."
fi
else
log_warn "Failed to download Neovim AppImage. Check network or URL pattern."
fi
# Install LazyVim
log_info "Installing LazyVim starter..."
mv ~/.config/nvim/*.vim /tmp/
git clone https://github.com/LazyVim/starter ~/.config/nvim
rm -rf ~/.config/nvim/.git
log_success "LazyVim starter cloned."
}
# ====================================================================
# 7. VISUAL STUDIO CODE
# ====================================================================
install_vscode() {
log_info "Installing Visual Studio Code..."
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
sudo sh -c 'echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/vscode.repo'
sudo dnf check-update
sudo dnf install -y --best code
log_success "Visual Studio Code installed."
}
# ====================================================================
# 8. ADDITIONAL MISSING PACKAGES
# ====================================================================
install_missing_packages() {
log_info "Installing additional required packages..."
sudo dnf install -y --skip-broken \
networkManager-wifi \
chromium-browser || log_warn "Some additional packages failed to install"
# sudo snap install brave
# echo "brave" > ~/.config/ml4w/settings/browser.sh
log_success "Additional packages installed."
}
# ====================================================================
# 9. DEVOPS TOOLS
# ====================================================================
install_devops() {
log_info "Installing DevOps tools..."
# Container Tools
sudo dnf install -y --skip-broken podman podman-docker docker-compose
# Go Lang
if ! command -v go &>/dev/null; then
log_info "Installing Go $GO_VERSION..."
wget -q "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" -O /tmp/go.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf /tmp/go.tar.gz
add_to_bashrc 'export PATH=$PATH:/usr/local/go/bin'
rm /tmp/go.tar.gz
log_success "Go $GO_VERSION installed."
else
log_info "Go already installed."
fi
# NOTE: The dev version will be in effect!
go install github.com/derailed/k9s@latest
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Helm
if ! command -v helm &>/dev/null; then
log_info "Installing Helm $HELM_VERSION..."
wget -q "https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz" -O /tmp/helm.tar.gz
tar -zxf /tmp/helm.tar.gz -C /tmp
sudo mv /tmp/linux-amd64/helm /usr/local/bin/helm
rm -rf /tmp/helm.tar.gz /tmp/linux-amd64
log_success "Helm $HELM_VERSION installed."
else
log_info "Helm already installed."
fi
log_success "DevOps tools installation completed."
}
# ====================================================================
# 10. FONTS (NERD FONTS)
# ====================================================================
install_fonts() {
log_info "Installing Nerd Fonts (Version: $NERDFONT_VERSION)..."
mkdir -p ~/.local/share/fonts
# Function to download specific font
download_font() {
local font_name="$1"
local zip_name="${font_name}.zip"
local url="https://github.com/ryanoasis/nerd-fonts/releases/download/${NERDFONT_VERSION}/${zip_name}"
if ! fc-list | grep -q "$font_name Nerd Font"; then
log_info "Downloading $font_name..."
if wget -q --show-progress "$url" -O "/tmp/$zip_name"; then
if [ -f "/tmp/$zip_name" ]; then
unzip -o -q "/tmp/$zip_name" -d ~/.local/share/fonts/"$font_name"
rm "/tmp/$zip_name"
log_success "$font_name downloaded and installed."
fi
else
log_warn "Failed to download $font_name from $url"
fi
else
log_info "$font_name already installed."
fi
}
download_font "FiraCode"
download_font "JetBrainsMono"
sudo dnf install -y \
google-noto-emoji-color-fonts \
rofimoji
fc-cache -f
log_success "Fonts installation completed."
}
# ====================================================================
# 11. HYPRLAND CUSTOM KEYBINDINGS
# ====================================================================
setup_hyprland_keybindings() {
log_info "Configuring custom Hyprland keybindings..."
mkdir -p ~/.config/hypr
# Add keybindings file if it doesn't exist
if [ ! -f ~/.config/hypr/hyprland.conf ]; then
log_warn "Main Hyprland config not found at ~/.config/hypr/hyprland.conf"
log_info "Creating custom keybindings file..."
fi
cat >~/.config/hypr/custom-keybinds.conf <<'EOF'
# ====================================================================
# CUSTOM KEYBINDINGS - Windows-like behavior
# ====================================================================
EOF
log_success "Custom Hyprland keybindings created at ~/.config/hypr/custom-keybinds.conf"
log_info "Remember to source this file in your hyprland.conf with: source = ~/.config/hypr/custom-keybinds.conf"
}
# BASHRC
# ====================================================================
update_bashrc() {
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
fi
}
# ====================================================================
# MAIN EXECUTION
# ====================================================================
main() {
log_info "=============================================================="
log_info "Fedora 43 Hyprland & DevOps Environment Setup"
log_info "Configuration Version: $CONFIG_VERSION"
log_info "Log file: $LOG_FILE"
log_info "=============================================================="
prepare_system
install_base_deps
install_missing_packages
install_hyprland
install_shell_utils
install_starship
install_neovim
install_vscode
install_devops
install_fonts
setup_hyprland_keybindings
update_bashrc
log_success "=============================================================="
log_success "Setup Completed Successfully!"
log_success "Log file saved to: $LOG_FILE"
log_success "=============================================================="
log_info "Next steps:"
log_info "1. Source your .bashrc: source ~/.bashrc"
log_info "2. Review and source Hyprland keybindings in your hyprland.conf"
log_info "3. Reboot your system to start Hyprland"
log_success "=============================================================="
}
# Run main function
main "$@"
@tuxerrante
Copy link
Author

✓ set -euo pipefail enabled - Enforces strict error checking for critical operations
✓ Error handling on non-critical DNF installations - Uses || log_warn to continue on package installation failures
✓ --skip-broken flag - Allows DNF to skip missing packages instead of aborting
✓ Helper function run_safe() - Available for wrapping any command that should continue on failure

How it works:

Critical errors still stop the script (e.g., missing git, failed file operations)
Package installation failures are logged as warnings and the script continues
Each function completes and logs its status before moving to the next
The log file captures all warnings for troubleshooting

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment