Last active
April 18, 2024 15:12
-
-
Save fbouynot/5186b1a83dc896ae00d4a34d91d733d4 to your computer and use it in GitHub Desktop.
My post-installation tasks for Fedora Workstation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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