#!/bin/bash -e # # Author: Casey DeLorme # # Description: fully automate installation and config after `arch-chroot`, # providing the user with a fully configured desktop environment and many # bells and whistles for developers. # # Dependencies: requires `base` and `base-devel` be installed with `pacstrap`, # and runs as root. Expects `username`, `password`, and `root_password` to be # supplied. # verify required variables while [ -z "$root_password" ]; do read -p "please enter a root password: " -s root_password && echo ""; done while [ -z "$username" ]; do read -p "please enter your username: " username; done while [ -z "$password" ]; do read -p "please enter your password: " -s password && echo ""; done # print all that transpires henceforth [ -n "$DEBUG" ] && set -x # initial time configuration ln -sf /usr/share/zoneinfo/America/New_York /etc/localtime hwclock -w --utc # setup locale sed -i "/^en_US.UTF-8/d" /etc/locale.gen sed -i "/^ja_JP.UTF-8/d" /etc/locale.gen echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen echo "ja_JP.UTF-8 UTF-8" >> /etc/locale.gen locale-gen echo "LANG=en_US.UTF-8" > /etc/locale.conf # setup hostname echo "${hostname:-arch}" > /etc/hostname echo "127.0.0.1 localhost" > /etc/hosts echo "::1 localhost" >> /etc/hosts echo "127.0.1.1 $(cat /etc/hostname).localdomain $(cat /etc/hostname)" >> /etc/hosts # set default virtualconsole font setfont koi8u_8x16 echo "FONT=koi8u_8x16" > /etc/vconsole.conf # enable multilib sed -i "/\[multilib\]/,/Include/"'s/^#//' /etc/pacman.conf # rebuild gpg keys rm -rf /etc/pacman.d/gnupg pacman-key --init pacman-key --populate archlinux # add sublime text source curl -O https://download.sublimetext.com/sublimehq-pub.gpg && pacman-key --add sublimehq-pub.gpg && pacman-key --lsign-key 8A8F901A && rm sublimehq-pub.gpg [ $(grep -c "sublime-text" /etc/pacman.conf) -eq 0 ] && echo -e "\n[sublime-text]\nServer = https://download.sublimetext.com/arch/stable/x86_64" | tee -a /etc/pacman.conf # Core tools export PACKAGES="linux linux-headers linux-firmware base-devel mkinitcpio sudo bash-completion man-db tmux gvim dkms dmidecode at bc cronie lm_sensors lshw stress" # install core packages so dependencies exist pacman -Syu --noconfirm $PACKAGES # Conditional CPU unicode [ $(grep -c "Intel" /proc/cpuinfo) -gt 0 ] && PACKAGES="${PACKAGES} intel-ucode" [ $(grep -c "AMD" /proc/cpuinfo) -gt 0 ] && PACKAGES="${PACKAGES} amd-ucode" # Conditional battery packages [ -e /sys/class/power_supply/BAT0 ] && PACKAGES="${PACKAGES} xf86-input-synaptics acpid tlp" # Storage PACKAGES="${PACKAGES} btrfs-progs smartmontools usbutils gvfs gvfs-mtp gvfs-afc android-udev parted postgresql transmission-cli python-pip python-setuptools" # Compression PACKAGES="${PACKAGES} cryptsetup lzop unzip p7zip xz unrar unace lrzip arj innoextract" # networking packages PACKAGES="${PACKAGES} nftables iptables dnsmasq rsync dhcpcd inetutils net-tools openssh sshfs ntp wget curl wireless_tools bluez bluez-utils oath-toolkit openconnect openvpn ethtool pptpclient connman wpa_supplicant iwd" # programming packages PACKAGES="${PACKAGES} pkgfile pkgconf bison gcc gcc-libs cmake ccache ncurses xmlstarlet jq git mercurial subversion bzr patchelf xdelta3 packer vagrant libvirt qemu libguestfs virt-install edk2-ovmf" # multimedia dependencies PACKAGES="${PACKAGES} mesa lib32-mesa dbus polkit giflib lib32-giflib mpg123 lib32-mpg123 v4l-utils lib32-v4l-utils lame libwebp libid3tag libvorbis vorbis-tools faac x264 x265 libpng12 lib32-libpng12 pulseaudio libpulse lib32-libpulse openal lib32-openal opencl-icd-loader lib32-opencl-icd-loader libva lib32-libva libva-utils gst-plugins-base-libs lib32-gst-plugins-base-libs graphicsmagick imagemagick joyutils evtest libexif ffmpeg lxsession-gtk3 yt-dlp wine-staging winetricks fcitx5 fcitx5-mozc fcitx5-configtool fcitx5-gtk fcitx5-qt" # GUI theme PACKAGES="${PACKAGES} gnome-themes-extra hicolor-icon-theme arc-gtk-theme gtk-engines gtk-engine-murrine" # GUI dependencies PACKAGES="${PACKAGES} gtk3 lib32-gtk3 pavucontrol pcmanfm-gtk3 ffmpegthumbnailer tumbler xdg-utils xdg-user-dirs" # vulkan packages PACKAGES="${PACKAGES} libva-mesa-driver lib32-libva-mesa-driver lib32-mesa-vdpau vulkan-tools vulkan-icd-loader lib32-vulkan-icd-loader" # Sway dependencies PACKAGES="${PACKAGES} sway swaybg alacritty wofi waybar xorg-xwayland xorg-xlsclients qt5-wayland glfw-x11 grim slurp xdg-desktop-portal-wlr libpipewire02 wl-clipboard brightnessctl playerctl mako libappindicator-gtk3 lib32-libappindicator-gtk3" # fonts PACKAGES="${PACKAGES} fontconfig ttf-bitstream-vera ttf-droid ttf-dejavu ttf-liberation ttf-hanazono ttf-font-awesome" # GUI software PACKAGES="${PACKAGES} xarchiver gparted psensor steam steam-native-runtime gamemode lib32-gamemode discord mpv mpv-mpris openshot gimp krita firefox obs-studio mednafen mame ppsspp lutris sublime-text evince viewnior virt-manager virtualbox virtualbox-host-modules-arch corectrl" # conditional GPU packages if [ $(lspci | grep -i "vga" | grep -ci "amd") -gt 0 ]; then PACKAGES="${PACKAGES} xf86-video-amdgpu vulkan-radeon lib32-vulkan-radeon mesa-vdpau" # update modules to load [ $(grep -c "amd" /etc/mkinitcpio.conf) -eq 0 ] && sed -i 's/MODULES=(\(.*\))/MODULES=(\1 amdgpu radeon)/' /etc/mkinitcpio.conf fi if [ $(lspci | grep -i "vga" | grep -ci "intel") -gt 0 ]; then PACKAGES="${PACKAGES} xf86-video-intel vulkan-intel lib32-vulkan-intel mesa-vdpau" # update modules to load [ $(grep -c "amd" /etc/mkinitcpio.conf) -eq 0 ] && sed -i 's/MODULES=(\(.*\))/MODULES=(\1 i915)/' /etc/mkinitcpio.conf fi if [ $(lspci | grep -i "vga" | grep -ci "nvidia") -gt 0 ]; then PACKAGES="${PACKAGES} nvidia-dkms libglvnd lib32-libglvnd opencl-nvidia lib32-opencl-nvidia xf86-video-nouveau nvidia-utils lib32-nvidia-utils mesa-vdpau nvidia-settings" # update modules to load [ $(grep -c "nvidia" /etc/mkinitcpio.conf) -eq 0 ] && sed -i 's/MODULES=(\(.*\))/MODULES=(\1 nvidia nvidia_modeset nvidia_uvm nvidia_drm)/' /etc/mkinitcpio.conf # automatic mkinitcpio updates in pacman.d echo -e "[Trigger]\nOperation=Install\nOperation=Upgrade\nOperation=Remove\nType=Package\nTarget=nvidia\n\n[Action]\nDepends=mkinitcpio\nWhen=PostTransaction\nExec=/usr/bin/mkinitcpio -P" > /etc/pacman.d/hooks/nvidia.hook fi # install all packages pacman -Syu --noconfirm $PACKAGES # install base configuration files from repository [ -d /srv/arch-desktop/install ] || git clone https://git.caseydelorme.com/cdelorme/arch-desktop /srv/arch-desktop rsync -Pav /srv/arch-desktop/install/ / mkdir -p /etc/skel/.config/pulse mkdir -p /etc/skel/{desktop,downloads,public,public/templates,documents,music,pictures,videos,code} sed "/module-suspend-on-idle/d" /etc/pulse/default.pa > /etc/skel/.config/pulse/default.pa # @note: we may want to avoid disabling this on laptops sed -i "/module-switch-on-port-available/d" /etc/skel/.config/pulse/default.pa rsync -Pav /etc/skel/ "$(getent passwd root | cut -d: -f6)/" sed -i "/ssh-add/d" "$(getent passwd root | cut -d: -f6)/.bashrc" # install protontricks python3 -m pip install protontricks # enable ccache and optimize cores for AUR sed -i 's/!ccache/ccache/' /etc/makepkg.conf sed -i 's/^#MAKEFLAGS.*/MAKEFLAGS="-j$(($(nproc) + 1)) -l$(nproc)"/' /etc/makepkg.conf # create a user to install aur packages export aur_username=$(head /dev/urandom | tr -dc a-z | head -c 13 ; echo '') useradd -r -m -s /bin/bash $aur_username echo "${aur_username} ALL= NOPASSWD: /usr/bin/pacman" > /etc/sudoers.d/${aur_username} # install xcursor-chameleon-skyblue sudo -u $aur_username git clone https://aur.archlinux.org/xcursor-chameleon-skyblue.git /home/${aur_username}/xcursor-chameleon-skyblue (cd /home/${aur_username}/xcursor-chameleon-skyblue && sudo -u ${aur_username} makepkg -rcsi --noconfirm) # install numix-icon-theme sudo -u $aur_username git clone https://aur.archlinux.org/numix-icon-theme-git.git /home/${aur_username}/numix-icon-theme-git (cd /home/${aur_username}/numix-icon-theme-git && sudo -u ${aur_username} makepkg -rcsi --noconfirm) # cmst (for connman UI) # wev # cleanup aur user rm -rf /etc/sudoers.d/${aur_username} userdel -fr $aur_username unset $aur_username # install gifduration if ! which gifduration &> /dev/null; then curl -Lfs https://raw.githubusercontent.com/alimony/gifduration-script/master/gifduration.py > /usr/local/bin/gifduration chmod a+rx /usr/local/bin/gifduration fi # install 64bit flash projector if ! which flashplayer &> /dev/null; then curl -Lfs "https://fpdownload.macromedia.com/pub/flashplayer/updaters/32/flash_player_sa_linux.x86_64.tar.gz" > /tmp/flash.tar.gz tar -xf /tmp/flash.tar.gz -C /usr/local/bin flashplayer fi # create sudo group and add to sudoers groupadd -fr sudo [ ! -f /etc/sudoers.d/sudo ] && echo '%sudo ALL=(ALL) ALL' > /etc/sudoers.d/sudo # update font cache fc-cache -fr # secure ssh by disabling root access and only accepting ssh keys sed -i "/^#\?PermitRootLogin/d" /etc/ssh/sshd_config sed -i "/^#\?PasswordAuthentication/d" /etc/ssh/sshd_config sed -i "/^#\?X11Forwarding/d" /etc/ssh/sshd_config echo "PermitRootLogin no" >> /etc/ssh/sshd_config echo "PasswordAuthentication no" >> /etc/ssh/sshd_config echo "X11Forwarding yes" >> /etc/ssh/sshd_config # set journald size sed -i '/^SystemMaxUse/d' /etc/systemd/journald.conf echo "SystemMaxUse=2G" >> /etc/systemd/journald.conf # set root password printf "${root_password}\n${root_password}\n" | passwd # initialize postgres database su - postgres -c "initdb --locale en_US.UTF-8 -D '/var/lib/postgres/data'" # create configuration to fix transmission errors echo "net.core.rmem_max = 4194304" > /etc/sysctl.d/transmission.conf echo "net.core.wmem_max = 1048576" >> /etc/sysctl.d/transmission.conf # check whether username and password are not empty if [[ -n "$username" && -n "$password" ]]; then # create user if not exists, else (re)-install dot-files if ! id $username &> /dev/null; then useradd -m -s /bin/bash $username echo "${username}:${password}" | chpasswd -c SHA256 else [ $EUID -ne 0 ] && rsync -Pav /etc/skel/ "$(getent passwd $username | cut -d: -f6)/" fi # add user to standard groups usermod -aG users,sudo,adm,input,audio,video,disk,storage,lp,vboxusers $username # generate postgres user and user database systemctl start postgresql su postgres -c "cd && createuser -ds $username" 2> /dev/null && su $username -c "cd && createdb" # load xdg-user-dirs su $username -c "cd && xdg-user-dirs-update" update-desktop-database # generate default (passwordless) ed25519 ssh key if none exists su $username -c "cd; if [ ! -f ~/.ssh/id_ed25519 ]; then ssh-keygen -q -t ed25519 -N '' -f ~/.ssh/id_ed25519 && cd && chmod 600 ~/.ssh/id_ed25519 && chmod 600 ~/.ssh/id_ed25519.pub; fi" # install gvm loading from ~/.bashrc & ~/.bash_profile, and the latest go version su $username -c "if [ ! -d ~/.gvm ]; then GVM_NO_UPDATE_PROFILE=1 bash < <(curl -Ls https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer 2> /dev/null); fi" su $username -c 'grep "gvm" ~/.bashrc &> /dev/null || echo -e "\n# load gvm\n[ -s $HOME/.gvm/scripts/gvm ] && . $HOME/.gvm/scripts/gvm" >> ~/.bashrc' su $username -c 'grep "gvm" ~/.bash_profile &> /dev/null || echo -e "\n# load gvm\n[ -s $HOME/.gvm/scripts/gvm ] && . $HOME/.gvm/scripts/gvm" >> ~/.bash_profile' su $username -c ". ~/.gvm/scripts/gvm && gvm install go1.17.6 -B && gvm use go1.17.6 --default" # configure user-space transmission if [ ! -f "/etc/systemd/system/transmission.service.d/local.conf" ]; then su $username -c "cd && mkdir -p ~/transmission/{done,incomplete}" su $username -c 'cd && tmp=$(mktemp) && jq ".[\"download-dir\"] = \"${HOME}/transmission/done\"" $HOME/.config/transmission-daemon/settings.json | jq ".[\"incomplete-dir\"] = \"${HOME}/transmission/incomplete\"" | jq ".[\"watch-dir\"] = \"$(xdg-user-dir DOWNLOAD)\"" > $tmp && mv $tmp $HOME/.config/transmission-daemon/settings.json' fi fi # symlink shceduled maintenance tasks ln -sf /usr/local/bin/system-updates /etc/cron.daily/system-updates ln -sf /usr/local/bin/disk-maintenance /etc/cron.weekly/disk-maintenance # symlink override vi to vim ln -sf /usr/bin/vim /usr/local/bin/vi # enable services for next reboot which connman &> /dev/null && systemctl enable connman which acpid &> /dev/null && systemctl enable acpid which tlp &> /dev/null && systemctl enable tlp systemctl enable postgresql systemctl enable bluetooth systemctl enable nftables systemctl enable libvirtd systemctl enable dnsmasq systemctl enable cronie systemctl enable ntpd systemctl enable sshd systemctl enable connman # attempt to enable dhcp on active network devices on reboot export active_network_device=$(ip addr | awk '/state UP/ {print $2}' | sed 's/.$//') [ ! -d "/sys/class/net/${active_network_device}/wireless" ] && (systemctl enable dhcpcd@${active_network_device} || echo "failed to enable dhcp service") # (re)build vmlinux image mkinitcpio -p linux # install the bootloader bootctl install # create boot loader entry echo "title arch" > /boot/loader/entries/arch.conf echo "linux vmlinuz-linux" >> /boot/loader/entries/arch.conf [ -f /boot/intel-ucode.img ] && echo "initrd /intel-ucode.img" >> /boot/loader/entries/arch.conf [ -f /boot/amd-ucode.img ] && echo "initrd /amd-ucode.img" >> /boot/loader/entries/arch.conf echo "initrd /initramfs-linux.img" >> /boot/loader/entries/arch.conf export boot_options="options root=PARTUUID=$(blkid -s PARTUUID -o value $(mount | grep ' / '|cut -d' ' -f 1)) rw quiet loglevel=3" [ "$enable_hibernation" = "y" ] && [ -n "$resume_uuid" ] && boot_options="${boot_options} resume=UUID=${resume_uuid}" [[ $(lspci | grep -i " vga" | grep -ci " nvidia") -gt 0 && $(grep -c "nvidia" /boot/loader/entires/arch.conf) -eq 0 ]] && boot_options="${boot_options} nvidia-dkm.modeset=1" echo "$boot_options" >> /boot/loader/entries/arch.conf # set boot loader entry as default sed -i '/^default/d' /boot/loader/loader.conf echo "default arch.conf" >> /boot/loader/loader.conf # check boot loader configuration bootctl status # cleanup pacman cache to minimize image yes | pacman -Scc sync