├── README.md ├── bootstrap.gif ├── bootstrap.sh └── config /README.md: -------------------------------------------------------------------------------- 1 | # Arch Bootstrap 2 | 3 | This script is used to automate the customization/bootstrapping of your Arch installation. This includes installing packages and running custom scripts to set up your environment. 4 | 5 | ![This is an image](bootstrap.gif) 6 | 7 |    8 | 9 | ## Usage 10 | 11 | Simply run the following command on your newly installed Arch environment to start the bootstrapping process. 12 | 13 | ``` 14 | curl -L b00t.me | bash 15 | ``` 16 | 17 | The script by default points to the config file located at the address http://config.b00t.me but can be changed to any local or remote file during installation. 18 | 19 |    20 | 21 | ## Config 22 | 23 | The config file is split up in sections which is represented in the GUI dialogs of the script as seen in the above capture, followed by any custom commands that are called from the menu entries. 24 | 25 | For example: 26 | 27 | ``` 28 | =Utilities 29 | P,openssh,enable-sshd 30 | 31 | =Desktop Environment 32 | P,bspwm sxhkd,,bspwm window manager 33 | A,polybar 34 | 35 | =CMD enable-sshd: sudo systemctl enable sshd 36 | ``` 37 | 38 | ### Syntax 39 | 40 | A section starts with `=Section_name` and contain menu entries formatted in a comma separated line: 41 | 42 | ``` 43 | =Section_name 44 | tag, package name(s), custom command name, description` 45 | ``` 46 | 47 | The syntax for menu entries are as follows: 48 | 49 | ``` 50 | 1. Tag 51 | - P: packages are from official repository 52 | - A: packages are from user repository (AUR) and are installed using the `yay` package manager 53 | 2. Name 54 | - Package name(s) to install, separated by a space 55 | 3. Command name 56 | - Command to run as specified by the `=CMD :` section 57 | 4. Description 58 | - If description is specified, this will replace the default package name in the menu entry 59 | ``` 60 | 61 | Depending on the construction of the meny entry line, only the tag is manditory. Either package name or description needs to specified, and the command name is fully optional. 62 | 63 |    64 | 65 | Custom commands start with `CMD= :` and have to be defined at the end of the config file **after** the menu sections. 66 | 67 | The syntax for commands are: 68 | ``` 69 | =CMD command_name: 70 | 71 | Or for multiple commands: 72 | 73 | =CMD command_name1 74 | command1 75 | command2 76 | ... 77 | 78 | =CMD command_name2 79 | command3 80 | command4 81 | ``` 82 | 83 |    84 | 85 | Please refer to the [config file](config) in this repository for more examples 86 | -------------------------------------------------------------------------------- /bootstrap.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Subbeh/arch_bootstrap/be88714c511a826e3a624c217be1482d4ad6b855/bootstrap.gif -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Arch based bootstrapping script 4 | # 5 | # PURPOSE: Automate the setup of a new Arch installation by installing 6 | # predefined packages and running configuration scripts. 7 | 8 | 9 | ## Environment variables 10 | default_config="http://config.b00t.me" 11 | LOGFILE=install.log 12 | export DEBUG=1 13 | 14 | 15 | ## Main function 16 | main() { 17 | if [ $(id -u) = 0 ] ; then 18 | whiptail \ 19 | --title 'Error' \ 20 | --msgbox "Please avoid running this as root" \ 21 | 10 40 22 | exit 1 23 | fi 24 | 25 | # cache password 26 | sudo -v 27 | 28 | preprocess 29 | sleep 2 30 | setup 31 | 32 | read_config $config 33 | 34 | for choice in $choices ; do 35 | run_job "${job_list[$choice]}" 36 | done 37 | } 38 | 39 | 40 | ## Pre-processing - install build packages and AUR helper 41 | preprocess() { 42 | log running prerequisites 43 | 44 | log refreshing package databases 45 | catch sudo pacman --noconfirm -Syy 46 | 47 | prereq=(dialog curl git base-devel binutils make gcc pkg-config fakeroot rsync) 48 | whiptail --title "Preprocess" \ 49 | --yesno \ 50 | --yes-button "Continue" \ 51 | --no-button "Exit" \ 52 | "The following required packages will be installed:\n\n$(printf ' • %s\n' "${prereq[@]}")" \ 53 | 0 0 3>&1 1>&2 2>&3 3>&1- || exit 54 | 55 | for pkg in ${prereq[@]} ; do 56 | install_pkg $pkg 57 | done 58 | 59 | if [ ! $(pacman -Qq yay 2>/dev/null) ] ; then 60 | install_git yay https://aur.archlinux.org/yay.git 61 | yay -Y --gendb 62 | yay -Syu --devel 63 | fi 64 | } 65 | 66 | 67 | ## Setup configuration 68 | setup() { 69 | while true ; do 70 | config_file=$( 71 | whiptail \ 72 | --title "Config File" \ 73 | --inputbox "\nPlease enter the config file location. This can be a local file or a hosted file (starting with http(s)://): " \ 74 | 0 78 ${1:-$default_config} \ 75 | 3>&1 1>&2 2>&3 3>&1- 76 | ) || exit 77 | 78 | if [[ "${config_file:=$default_config}" =~ ^https?:// ]] ; then 79 | config=$(mktemp) 80 | curl -sSfL "$config_file" > $config && break 81 | elif [ -f "$config_file" ] ; then 82 | config=$config_file 83 | break 84 | fi 85 | whiptail \ 86 | --title 'Error' \ 87 | --msgbox "Unable to access file/url:\n\n$config_file" \ 88 | 10 40 89 | done 90 | } 91 | 92 | 93 | ## Process the configuration file 94 | read_config() { 95 | [ -r "${1:?not set}" ] || { log -e cannot find $1 ; exit 1 ; } 96 | _dlg() { 97 | choices+=$( 98 | dialog --keep-tite \ 99 | --backtitle "Arch Bootstrap Installation Script" \ 100 | --separate-output \ 101 | --checklist \ 102 | "$cat" \ 103 | 0 0 0 \ 104 | "${options[@]}" \ 105 | 2>&1 >/dev/tty)" " || exit 106 | } 107 | 108 | while IFS=, read -r tag name cmd desc ; do 109 | [[ $tag == "=CMD" ]] && break; 110 | if [[ $tag =~ ^= ]] ; then 111 | [[ "$options" ]] && _dlg 112 | options=() 113 | cat=${tag/=/} 114 | continue 115 | fi 116 | 117 | [[ ! $tag =~ ^[PAC] ]] && continue 118 | job_list[$((++id))]=$id,$tag,$cat,$name,$desc,$cmd 119 | 120 | options+=($id "${desc:-$name}" ${checkbox:-off}) 121 | done < $1 122 | 123 | # extract custom scripts 124 | scriptdir=$(mktemp -d) 125 | gawk -F'[: ]' -v sd="$scriptdir/" ' 126 | match($0, /=CMD ([^:]*):(.*)/, a) { print a[2] > sd a[1] } 127 | /^=CMD/ { script=$2 ; next } 128 | /^=/ && script { script="" } 129 | script { print $0 > sd script ; next } 130 | ' $1 131 | 132 | [[ "$options" ]] && _dlg 133 | clear 134 | } 135 | 136 | 137 | ## Run jobs based on tag 138 | run_job() { 139 | IFS=',' read -r id tag cat name desc cmd <<< "$@" 140 | case $tag in 141 | P) install_pkg $name ;; 142 | A) install_pkg -A $name ;; 143 | C) cmd=${cmd:-$name} ;; 144 | esac 145 | 146 | [ "$cmd" ] && run_script $cmd 147 | } 148 | 149 | 150 | ## Run Pacman/AUR helper 151 | install_pkg() { 152 | [ "$1" == "-A" ] && { aur=yay ; shift ; } 153 | for pkg in "$@" ; do 154 | if [ ! $(pacman -Qq $pkg 2>/dev/null) ] ; then 155 | log installing ${aur:+AUR} package "\e[1;96m$pkg\e[0m" 156 | catch ${aur:-sudo pacman} --noconfirm --needed -S "$pkg" 157 | else 158 | log package "\e[1;96m$pkg\e[0m" is already installed 159 | fi 160 | done 161 | } 162 | 163 | 164 | ## Install from git repository 165 | install_git() { 166 | log installing package "\e[1;96m$1\e[0m" 167 | git_dir="$(mktemp -d)" 168 | git clone "$2" $git_dir >/dev/null 2>&1 169 | (cd $git_dir && catch makepkg -csi --noconfirm) 170 | } 171 | 172 | 173 | ## Run custom script 174 | run_script() { 175 | log running script "\e[1;96m$1\e[0m" 176 | [ ! -f "${scriptdir:?not set}/$1" ] && { log -e script \'$1\' is not defined ; return ; } 177 | catch source "${scriptdir:?not set}/$1" 178 | } 179 | 180 | 181 | ## Script cleanup 182 | cleanup() { 183 | sleep 1 184 | rm -rf $err $dbg $scriptdir $git_dir 2>/dev/null 185 | tput rmcup 186 | printf "FINISHED\nlogfile: %s\n" "$LOGFILE" 187 | kill $(jobs -p) 188 | exit 189 | } 190 | 191 | 192 | ## Logging and error handling 193 | log() { 194 | case $1 in 195 | -d) (($DEBUG)) || return ; l=DEBUG ; shift ;; 196 | -e) l=ERROR ; shift ;; 197 | -w) l=WARNING ; shift ;; 198 | *) l=INFO ;; 199 | esac 200 | printf "[$(date --rfc-3339=seconds)] $l: " 201 | echo -e $* 202 | } 203 | 204 | > $LOGFILE 205 | exec > >(tee -a $LOGFILE) 206 | exec 2>&1 207 | 208 | tput smcup 209 | trap 'cleanup' 1 2 EXIT 210 | 211 | export -f log 212 | { err="$(mktemp -u /tmp/err-pipe.XXX)" ; dbg="$(mktemp -u /tmp/dbg-pipe.XXX)"; } && mkfifo $err $dbg 213 | 214 | cat <> $err 2>/dev/null | while IFS= read line ; do log -w $line ; done & 215 | cat <> $dbg 2>/dev/null | while IFS= read line ; do log -d $line ; done & 216 | 217 | catch() { $@ >>$dbg 2>>$err; } 218 | 219 | 220 | ## Run main function 221 | declare -a job_list 222 | declare -a categories 223 | declare -a choices 224 | declare -i id=0 225 | 226 | main $* 227 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | # BOOTSTRAP CONFIG FILE 2 | # 3 | # format: 4 | # = 5 | # , [package-name(s)], [command-name], [description] 6 | # 7 | # - tag: 8 | # - P: package (pacman) 9 | # - A: AUR package (yay) 10 | # - C: custom command (combined with "=CMD" entry) 11 | # - name: package name(s) 12 | # - command-name (optional): name of "=CMD" entry 13 | # - description (optional): description of item 14 | # 15 | # OR 16 | # 17 | # =CMD name: < 18 | # =CMD 19 | # 20 | # <...> 21 | # 22 | # Please note: =CMD sections must be added at the end, after categories 23 | 24 | =System 25 | P,reflector,mirrorlist,mirror-list optimizer 26 | P,base-devel cmake binutils boost pacman-contrib,,build tools 27 | P,linux-lts,,lts kernel 28 | P,linux-zen,,zen kernel 29 | P,intel-ucode 30 | P,openssh libfido2,enable-sshd,openssh 31 | P,net-tools dnsutils inetutils iproute2 macchanger speedtest-cli nethogs nmap whois mtr iperf3 dog,,network tools 32 | P,rebuild-detector 33 | P,tlp,enable-tlp 34 | P,zsh,zsh 35 | P,vim,vim 36 | P,nvim 37 | P,man-db 38 | A,nordvpn-bin,nordvpn 39 | A,mullvad-vpn-bin 40 | P,tailscale,enable-tailscale 41 | P,python-pip 42 | P,jre-openjdk 43 | A,bluez bluez-utils rofi-bluetooth-git,enable-bluetooth,bluetooth tools 44 | P,pulseaudio alsa-utils pulseaudio-alsa pulseaudio-bluetooth pavucontrol,pulseaudio,pulseaudio 45 | P,ntfs-3g,,NTFS support 46 | P,nfs-utils 47 | P,smbclient 48 | A,pure-ftpd 49 | 50 | =Xorg 51 | P,xorg-server xorg-apps xorg-xinit,,xorg display server 52 | P,picom 53 | P,arandr 54 | P,xterm 55 | P,numlockx 56 | P,xbindkeys 57 | P,xclip 58 | P,xdo 59 | P,xlsw-git 60 | P,wmctrl 61 | A,wmutils-git 62 | A,xlsw-git 63 | A,xtitle 64 | A,xsel 65 | 66 | =Desktop Environment 67 | A,bspwm sxhkd bsp-layout,,bspwm window manager 68 | P,dunst libnotify notification-daemon,,notification manager 69 | A,polybar playerctl zscroll-git,,polybar 70 | P,xdg-utils 71 | P,alacritty 72 | P,rxvt-unicode 73 | P,tmux tmuxinator,,tmux 74 | P,nitrogen 75 | A,dmenu2 76 | P,rofi 77 | #A,networkmanager-dmenu 78 | A,betterlockscreen 79 | P,thunar 80 | 81 | =Utilities 82 | P,zip unzip unrar p7zip gzip bzip2 zstd,,archiving/compression tools 83 | P,wget 84 | P,tldr 85 | #P,strace,,debugging tools 86 | P,brightnessctl 87 | A,ranger atool elinks ffmpegthumbnailer highlight mediainfo odt2txt perl-image-exiftool ueberzug epub-thumbnailer-git,,ranger 88 | P,vifm 89 | P,source-highlight 90 | P,fzf 91 | P,fd 92 | A,xh 93 | P,duf 94 | P,pkgfile 95 | P,ripgrep 96 | P,tree 97 | P,bat 98 | P,ncdu 99 | P,dust 100 | P,htop 101 | P,btop 102 | P,feh 103 | P,scrot 104 | P,flameshot 105 | #P,neofetch 106 | #P,pfetch 107 | P,mlocate 108 | P,exa 109 | P,lsof 110 | A,bitwarden-cli-bin 111 | A,sshpass 112 | #P,scrcpy 113 | #P,glances 114 | 115 | =GUI Apps 116 | P,firefox 117 | P,chromium 118 | #A,tor-browser 119 | P,zathura zathura-pdf-mupdf,,zathura 120 | A,spotify spotifywm-git,,spotify 121 | P,vlc 122 | P,mpv 123 | P,galculator 124 | P,obsidian 125 | P,notepadqq 126 | P,cheese 127 | P,qbittorrent 128 | #P,bleachbit 129 | #P,gparted 130 | A,zoom 131 | #A,teams 132 | P,discord 133 | 134 | =Infra 135 | #A,virtualbox virtualbox-ext-oracle virtualbox-host-modules-arch,,virtualbox host utils 136 | #P,virtualbox-guest-utils xf86-video-vmware,enable-virtualbox,virtualbox guest utils 137 | #P,qemu virt-manager virt-viewer dnsmasq vde2 bridge-utils openbsd-netcat libguestfs dmidecode,kvm,kvm 138 | P,docker 139 | P,ansible-core ansible ansible-lint molecule molecule-docker molecule-vagrant,,ansible 140 | P,kubectl helm kubectx k9s stern kubecolor,,k8s utils 141 | P,terraform 142 | #P,vagrant 143 | P,argocd 144 | P,age 145 | A,go-task-bin 146 | P,direnv 147 | P,ipcalc 148 | P,python-pre-commit 149 | P,jq 150 | P,sops 151 | P,go-yq 152 | 153 | =Dotfiles 154 | P,stow git-crypt,dotfiles,pull dotfiles 155 | 156 | =Fonts 157 | P,gucharmap 158 | A,font-manager 159 | #P,noto-fonts 160 | #A,gohufont-powerline 161 | A,jmk-x11-fonts-git 162 | A,nerd-fonts-fira-code 163 | #A,otf-sfmono-patched 164 | #A,scientifica 165 | A,siji-ng 166 | #A,tamzen-font 167 | #A,termsyn-powerline-font-git 168 | #A,ttf-icomoon-feather 169 | #A,ttf-material-design-iconic-font 170 | #A,ttf-typicons 171 | #P,otf-font-awesome 172 | #P,papirus-icon-theme 173 | #C,,load-fonts,load fonts 174 | 175 | =Custom 176 | P,nodejs npm,lifx,lifx controller 177 | A,i8kutils dell-bios-fan-control-git tcl tk acpi,fan-control,i8k fan control 178 | 179 | =Configuration 180 | #C,,enable-macspoof,spoof MAC address 181 | C,,enable-bluetooth_poweron,auto-power bluetooth 182 | C,,enable-ssh-agent,auto-start ssh-agent 183 | C,,enable-paccache,enable paccache timer 184 | C,,enable-fstrim,enable fstrim timer 185 | C,,mount-data,mount data 186 | C,,mount-nas,mount NAS shares 187 | C,,lockscreen,configure lockscreen 188 | C,,kbd-backlight,keyboard backlight timeout 189 | C,,backlight,enable screen backlight control 190 | 191 | =CMD mirrorlist: country=$(curl -Ss ipinfo.io | awk -F'[:,"]' '/country/ { print $5 }') ; sudo reflector -c ${country:-AU} --sort rate --latest 5 --save /etc/pacman.d/mirrorlist 192 | =CMD enable-sshd: sudo systemctl enable --now sshd 193 | =CMD enable-paccache: sudo systemctl enable paccache.timer 194 | =CMD enable-fstrim: sudo systemctl enable fstrim.timer 195 | =CMD enable-virtualbox: sudo systemctl enable --now vboxservice 196 | =CMD enable-bluetooth: sudo systemctl enable --now bluetooth 197 | =CMD enable-bluetooth-poweron: sudo systemctl enable --now bluetooth-poweron 198 | =CMD enable-tlp: sudo systemctl enable --now tlp 199 | =CMD enable-ssh-agent: systemctl --user enable --now ssh-agent 200 | =CMD enable-tailscale: sudo systemctl enable --now tailscaled 201 | =CMD zsh: sudo chsh -s $(which zsh) $USER 202 | =CMD vim: mkdir -p ~/.local/share/vim/{backup,swap,undo,view} ; vim +PlugUpdate +qall 203 | =CMD lifx: sudo npm install -g lifx-client && gpg -d $DOT/secure/.config/lifx/config.gpg --output ${XDG_CONFIG_HOME:?not set}/lifx/config 204 | =CMD pulseaudio: pactl set-card-profile alsa_card.usb-DisplayLink_Dell_Universal_Dock_D6000_1801300418-02 off 205 | =CMD load-fonts: for dir in $(find ~/.local/share/fonts/ -type d) ; do (cd $dir; mkfontdir ; mkfontscale) ; done ; fc-cache -f 206 | =CMD enable-macspoof: sudo systemctl enable --now macspoof@wlan0.service 207 | =CMD mount-data: sudo mkdir /data 2> /dev/null ; sblk -o LABEL | grep -q Data && grep -q "\s/data\s" /etc/fstab || echo "LABEL=Data /data auto auto,nouser,exec,rw,async,atime 0 0" | sudo tee -a /etc/fstab 208 | =CMD mount-nas: sudo systemctl enable mnt-backup.automount mnt-media.automount mnt-workspace.automount 209 | =CMD lockscreen: betterlockscreen -u $HOME/.local/share/wallpapers 210 | =CMD kbd-backlight: echo "5m" | sudo tee /sys/class/leds/dell\:\:kbd_backlight/stop_timeout 211 | =CMD backlight: sudo usermod -aG video $USER 212 | 213 | =CMD dotfiles 214 | git clone --recurse-submodules git@github.com:Subbeh/dotfiles.git ~/.dotfiles 215 | rm ~/.bashrc ~/.bash_profile 2>/dev/null 216 | $HOME/.dotfiles/dot load -g -p 217 | 218 | =CMD fan-control 219 | #grep ^dell-smm-hwmon$ /etc/modules 2> /dev/null || echo dell-smm-hwmon | sudo tee -a /etc/modules 220 | #grep "^options dell-smm-hwmon restricted=0$" /etc/modprobe.d/dell-smm-hwmon.conf 2> /dev/null || echo options dell-smm-hwmon restricted=0 | sudo tee -a /etc/modprobe.d/dell-smm-hwmon.conf 221 | #sudo modprobe -v i8k 222 | sudo systemctl enable --now i8kmon.service 223 | sudo systemctl enable --now dell-bios-fan-control.service 224 | 225 | =CMD nordvpn 226 | sudo groupadd -r nordvpn 227 | sudo usermod -aG nordvpn $USER 228 | sudo systemctl enable --now nordvpnd 229 | nordvpn whitelist add subnet 10.0.0.0/16 230 | nordvpn login 231 | 232 | =CMD kvm 233 | sudo systemctl enable --now libvirtd.service 234 | sudo usermod -aG libvirt $USER 235 | sudo modprobe -r kvm_intel 236 | sudo modprobe kvm_intel nested=1 237 | echo "options kvm-intel nested=1" | sudo tee /etc/modprobe.d/kvm-intel.conf 238 | --------------------------------------------------------------------------------