Skip to content

Instantly share code, notes, and snippets.

@fbouynot
Last active April 18, 2024 15:12
Show Gist options
  • Save fbouynot/5186b1a83dc896ae00d4a34d91d733d4 to your computer and use it in GitHub Desktop.
Save fbouynot/5186b1a83dc896ae00d4a34d91d733d4 to your computer and use it in GitHub Desktop.
My post-installation tasks for Fedora Workstation
#!/usr/bin/env bash
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version. Please see LICENSE.txt at the top level of
# the source code distribution for details.
#
# @package fedora_setup.sh
# @author <[email protected]>
# @link https://gist.github.com/fbouynot/5186b1a83dc896ae00d4a34d91d733d4
# @copyright <[email protected]>
#
# Post-installation tasks for Fedora Workstation
#
# -e: When a command fails, bash exits instead of continuing with the rest of the script
# -u: This will make the script fail, when accessing an unset variable
# -o pipefail: This will ensure that a pipeline command is treated as failed, even if one command in the pipeline fails
set -euo pipefail
# Replace the Internal Field Separator ' \n\t' by '\n\t' so you can loop through names with spaces
IFS=$'\n\t'
# Enable debug mode by running your script as TRACE=1 ./script.sh instead of ./script.sh
if [[ "${TRACE-0}" == "1" ]]; then
set -o xtrace
fi
# Define constants
PROGNAME="${0##*/}"
VERSION='1.1.4'
GREEN="$(tput setaf 2)"
RED="$(tput setaf 1)"
NC="$(tput sgr0)" # No Color
DEFAULT_VERBOSE=0
readonly PROGNAME VERSION GREEN RED NC DEFAULT_VERBOSE
help() {
cat << EOF
Usage: ${PROGNAME} [-Vhv]
Post-install actions for Fedora
Options:
-h --help Print this message.
-v --verbose Verbose output
-V --version Print the version.
EOF
exit 2
}
version() {
cat << EOF
${PROGNAME} version ${VERSION} under GPLv3 licence.
EOF
exit 2
}
# Deal with arguments
while [[ $# -gt 0 ]]
do
key="${1}"
case $key in
-h|--help)
help
;;
-v|--verbose)
verbose=1
;;
-vv)
verbose=2
;;
-V|--version)
version
;;
*)
shift
;;
esac
shift # consume $1
done
# Set defaults if no options specified
verbose="${verbose:-$DEFAULT_VERBOSE}"
# Check root permissions
# shellcheck disable=SC2317
check_root() {
# Check the command is not run as root
if [ "${EUID}" -eq 0 ]
then
echo -e "${RED}E:${NC} please do not run as root" >&2
return 1
fi
return 0
}
# Add required repositories
# shellcheck disable=SC2317
add_repositories() {
# Install dnf plugins to install repository
sudo dnf install -y dnf-plugins-core || return 1
# Install rpmfusion
sudo dnf install -y https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-"$(rpm -E %fedora)".noarch.rpm || return 1
sudo dnf install -y https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-"$(rpm -E %fedora)".noarch.rpm || return 1
# Install Microsoft repository
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc || return 1
sudo bash -c 'cat > /etc/yum.repos.d/vscode.repo << EOF
[code]
name=Visual Studio Code
baseurl=https://packages.microsoft.com/yumrepos/vscode
enabled=1
gpgcheck=1
gpgkey=https://packages.microsoft.com/keys/microsoft.asc
EOF' || return 1
# Install docker repository
sudo dnf config-manager -y --add-repo https://download.docker.com/linux/fedora/docker-ce.repo || return 1
return 0
}
# Upgrade packages
# shellcheck disable=SC2317
update_packages() {
# Upgrade packages
sudo dnf check-update -y || true
sudo dnf upgrade -y || return 1
return 0
}
# Install mesa
# shellcheck disable=SC2317
install_mesa() {
# Remove mesa-va-drivers
sudo dnf remove -y mesa-va-drivers || return 1
# Install vadrivers from rpmfusion
sudo dnf install -y mesa-va-drivers-freeworld mesa-vdpau-drivers-freeworld || return 1
return 0
}
# Install codecs
# shellcheck disable=SC2317
install_codecs() {
sudo dnf groupupdate -y multimedia --setop="install_weak_deps=False" --exclude=PackageKit-gstreamer-plugin --allowerasing || return 1
sudo dnf groupupdate -y sound-and-video || return 1
sudo dnf install -y @multimedia @sound-and-video ffmpeg-libs gstreamer1-plugins-{bad-\*,good-\*,base} gstreamer1-plugin-openh264 gstreamer1-libav lame\* || return 1
return 0
}
# Configure auto-upgrade
# shellcheck disable=SC2317
configure_autoupgrade() {
# Install dnf auto upgrade
sudo dnf install -y dnf-automatic || return 1
sudo systemctl enable --now dnf-automatic-install.timer || return 1
# Auto upgrade firmwares
sudo bash -c 'cat > /etc/systemd/system/fwupd-automatic.service << EOF
[Unit]
Description=Scheduled Firmware Upgrade
[Service]
Type=oneshot
ExecStartPre=/usr/bin/fwupdmgr refresh --force
ExecStart=/usr/bin/fwupdmgr update -y
EOF' || return 1
sudo bash -c 'cat > /etc/systemd/system/fwupd-automatic.timer << EOF
[Unit]
Description=Scheduled Firmware Upgrade.
[Timer]
OnBootSec=15min
OnUnitActiveSec=1d
[Install]
WantedBy=multi-user.target
EOF' || return 1
sudo systemctl enable --now fwupd-automatic.timer || return 1
# Auto upgrade flatpaks
sudo bash -c 'cat > /etc/systemd/user/update-user-flatpaks.service << EOF
[Unit]
Description=Update user Flatpaks
[Service]
Type=oneshot
ExecStart=/usr/bin/flatpak update --assumeyes --noninteractive
[Install]
WantedBy=default.target
EOF' || return 1
sudo bash -c 'cat > /etc/systemd/system/update-system-flatpaks.service << EOF
[Unit]
Description=Update system Flatpaks
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/flatpak update --assumeyes --noninteractive --system
[Install]
WantedBy=multi-user.target
EOF' || return 1
sudo bash -c 'cat > /etc/systemd/user/update-user-flatpaks.timer << EOF
[Unit]
Description=Update user Flatpaks daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
EOF' || return 1
sudo bash -c 'cat > /etc/systemd/system/update-system-flatpaks.timer << EOF
[Unit]
Description=Update system Flatpaks daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
EOF' || return 1
systemctl --user enable --now update-user-flatpaks.timer || return 1
sudo systemctl --system enable --now update-system-flatpaks.timer || return 1
return 0
}
# Install docker
# shellcheck disable=SC2317
install_docker() {
# Install docker
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin || return 1
sudo systemctl enable --now docker || return 1
return 0
}
# Install VSCode
# shellcheck disable=SC2317
install_code() {
# Install VSCode
sudo dnf -y install code || return 1
return 0
}
# Install Gimp
# shellcheck disable=SC2317
install_gimp() {
# Install VSCode
sudo dnf -y install gimp || return 1
return 0
}
# Install EWS connector for Evolution
# shellcheck disable=SC2317
install_evolution-ews() {
# Install EWS connector for Evolution
sudo dnf -y install evolution-ews || return 1
return 0
}
# Install remmina
# shellcheck disable=SC2317
install_remmina() {
# Install remmina
sudo dnf -y install remmina || return 1
return 0
}
# Install Wireshark
# shellcheck disable=SC2317
install_wireshark() {
# Install Wireshark
sudo dnf -y install wireshark || return 1
return 0
}
# Install devops tools
# shellcheck disable=SC2317
install_devops() {
# Install devops_tools
sudo dnf -y install git kubernetes-client || return 1
cat > .bashrc < 'EOF'
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]; then
PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
if [ -d ~/.bashrc.d ]; then
for rc in ~/.bashrc.d/*; do
if [ -f "$rc" ]; then
. "$rc"
fi
done
fi
unset rc
# Aliases
alias k=kubectl
alias kx='kubectl config set-context'
alias dnf='dnf5'
# Allow kubectl autocompletion when using k alias
complete -o default -F __start_kubectl k
# kubectl autocompletion
source <(kubectl completion bash)
EOF || return 1
return 0
}
# Install ShadowPC
# shellcheck disable=SC2317
install_shadowpc() {
# Install ShadowPC
sudo dnf install -y xcb-util xcb-util-keysyms xcb-util-cursor SDL2 libva libva-utils libvdpau libinput mesa-libgbm libXdamage libXrandr libXcomposite nspr cups-libs libXdmcp libXi libbsd libXcursor libXtst atk alsa-lib nss libXScrnSaver at-spi2-atk gdk-pixbuf2 gtk3 gnome-keyring || return 1
wget "https://gitlab.com/aar642/shadow-repackaged/-/jobs/artifacts/main/raw/Shadow_PC-x86_64.AppImage?job=build" -O ShadowPC_Repackaged-x86_64.AppImage || return 1
chmod a+x ShadowPC_Repackaged-x86_64.AppImage || return 1
# launch with ./ShadowPC_Repackaged-x86_64.AppImage and win+shift+M if no mouse
return 0
}
# Tune Network
# shellcheck disable=SC2317
network_tuning() {
# Tune network
sudo bash -c 'cat > /etc/sysctl.d/88-tcp_bbr.conf << EOF
net.core.default_qdisc=fq_codel
net.ipv4.tcp_congestion_control=bbr
EOF' || return 1
sudo sysctl --system || return 1
return 0
}
# Configure DNS Resolver
# shellcheck disable=SC2317
dns_config() {
# Configure DNS Resolver
sudo bash -c 'cat > /etc/systemd/resolved.conf << EOF
[Resolve]
DNS=1.1.1.2#security.cloudflare-dns.com
DNS=1.0.0.2#security.cloudflare-dns.com
DNS=2606:4700:4700::1112#security.cloudflare-dns.com
DNS=2606:4700:4700::1002#security.cloudflare-dns.com
#DNS=45.90.28.0#xxxxxx.dns.nextdns.io
#DNS=2a07:a8c0::#xxxxxx.dns.nextdns.io
#DNS=45.90.30.0#xxxxxx.dns.nextdns.io
#DNS=2a07:a8c1::#xxxxxx.dns.nextdns.io
FallbackDNS=1.1.1.2 1.0.0.2 2606:4700:4700::1112 2606:4700:4700::1002
DNSSEC=allow-downgrade
DNSOverTLS=opportunistic
Cache=yes
EOF' || return 1
sudo systemctl restart systemd-resolved || return 1
return 0
}
# Configure NTS
# shellcheck disable=SC2317
ntp_config() {
# Configure NTS
sudo bash -c 'cat > /etc/chrony.conf << EOF
server time.cloudflare.com iburst nts
server nts.sth1.ntp.se iburst nts
server nts.sth2.ntp.se iburst nts
ntsdumpdir /var/lib/chrony
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
ntsdumpdir /var/lib/chrony
leapsectz right/UTC
logdir /var/log/chrony
EOF' || return 1
sudo systemctl restart chronyd || return 1
return 0
}
# Shell configuration
# shellcheck disable=SC2317
shell_config() {
# Prompt bash
sudo bash -c 'cat > /etc/profile.d/colours.sh << "EOF"
PROMPT_COMMAND='lstatus=$?'
# Print date and space separator
PS1='\D{%F %T} '
# Print green if user, red if root - escaped so it doesn't count for usable line length
PS1+='$(if [ "${EUID}" -ne 0 ]; then echo "\[\e[01;32m\]"; else echo "\[\e[01;31m\]"; fi)'
# Print user
PS1+='\u'
# Reset color - escaped so it doesn't count for usable line length
PS1+='\[\e[00m\]'
# Print @
PS1+='@'
# Green color - escaped so it doesn't count for usable line length
PS1+='\[\e[01;32m\]'
# Print Host
PS1+='\h'
# Reset color - escaped so it doesn't count for usable line length
PS1+='\[\e[00m\]'
# Print :
PS1+=':'
# Blue color - escaped so it doesn't count for usable line length
PS1+='\[\e[01;34m\]'
# Print path
PS1+='\w'
# Brown color - escaped so it doesn't count for usable line length
PS1+='\[\e[01;33m\]'
# Add git branch if any
# Sed first pass get the right line, second pass do the formatting: keep only the branch name, prepend space and [, append ]
PS1+='$(command -v git 1> /dev/null && git branch 2> /dev/null | sed -e "/^[^*]/d" -e "s/* \(.*\)/ [\1]/")'
# Add current kube cluster if any, prepend space and [, append ]
# kubectl is slow so we use awk instead
PS1+='$(kube_ns_cluster=$(command -v kubectl 1> /dev/null && awk "/^current-context:/{print \$2;exit;}" <~/.kube/config 2> /dev/null); echo "${kube_ns_cluster:+ [$kube_ns_cluster]}")'
# Reset color - escaped so it doesn't count for usable line length
PS1+='\[\e[00m\]'
# Get return code; if !0 print it in red prepended with ( appended with ), and keep red color - escaped so it doesn't count for usable line length
PS1+='$(code=${lstatus##0}; echo "${code:+\[\e[01;31m\] (${code})}")'
# Print $ if user, # if root, prepend with space
PS1+='$(if [ "${EUID}" -ne 0 ]; then echo " $"; else echo " #"; fi) '
# Reset color - escaped so it doesn't count for usable line length
PS1+='\[\e[00m\]'
EOF' || return 1
sudo bash -c 'cat >> /etc/nanorc << EOF
include "/usr/share/nano/sh.nanorc"
EOF' || return 1
return 0
}
# Gnome configuration
# shellcheck disable=SC2317
gnome_config() {
# Disable Gnome update
gsettings set org.gnome.software allow-updates false || return 1
# Disable touchpad if mouse is connected
gsettings set org.gnome.desktop.peripherals.touchpad send-events disabled-on-external-mouse || return 1
# Disable touchpad while typing
gsettings set org.gnome.desktop.peripherals.touchpad disable-while-typing true || return 1
# Add shortcut to open terminal (ctrl+alt+T)
gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings "['/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/']" || return 1
gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/ name 'Open Terminal' || return 1
gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/ command 'gnome-terminal' || return 1
gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/ binding '<Primary><Alt>T' || return 1
# Set dark theme preference
gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' || return 1
# Disable hot-corner functionality
gsettings set org.gnome.desktop.interface enable-hot-corners false || return 1
return 0
}
# Call the functions and print pretty output
# arg1: message
# arg2: command
step() {
printf "%-50s" "${1}" 1>&4 2>&5
"${2}" || (printf "%s\n" "${RED}FAIL${NC}" >&5 && exit 4)
printf "%s\n" "${GREEN}OK${NC}" 1>&4 2>&5
return 0
}
# Change directory to base script directory
cd "$(dirname "$0")"
# Main function where we can write code
main() {
# Set verbosity
# Save address of stdout to 4
exec 4>&1
# Save address of stderr to 5
exec 5>&2
case "${verbose}" in
1|--destination)
# Remove messages that would be sent to stdout, keep stderr one
exec 1>/dev/null
;;
2|--folder)
# Print both stdout and stderr messages
;;
*)
# Remove both stdout and stderr messages
exec 1> /dev/null 2>/dev/null
;;
esac
# Check for root permissions
step "Check permissions" "check_root"
# Add repositories
step "Add repositories" "add_repositories"
# Upgrade packages
step "Upgrade packages" "update_packages"
# Install mesa
step "Install mesa" "install_mesa"
# Install codecs
step "Install codecs" "install_codecs"
# Configure autoupgrade
step "Configure autoupgrade" "configure_autoupgrade"
# Install docker
step "Install docker" "install_docker"
# Install VSCode
step "Install VSCode" "install_code"
# Install Gimp
step "Install gimp" "install_gimp"
# Install EWS connector for Evolution
step "Install EWS connector for Evolution" "install_evolution-ews"
# Install remmina
step "Install remmina" "install_remmina"
# Install Wireshark
step "Install Wireshark" "install_wireshark"
# Install devops_tools
step "Install devops tools" "install_devops"
# Install shadowpc
step "Install shadowpc" "install_shadowpc"
# Tune network
step "Tune network" "network_tuning"
# DNS resolver configuration
step "DNS resolver configuration" "dns_config"
# NTP configuration
step "NTP configuration" "ntp_config"
# Shell configuration
step "Shell configuration" "shell_config"
# Gnome configuration
step "Gnome configuration" "gnome_config"
exit 0
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment