#!/bin/bash # usage: # curl -L https://raw.githubusercontent.com/xero/dotfiles/main/setup > x && chmod +x x && sudo ./x # make sure your edit the ARCH var for your architecture # # setup.sh by xero (http://git.io/.files) # a script to setup a new debian vps with # all my tools and configs, ready to roll # it relies heavily on my 1password vault # so... # ▄▄▄▄ ▓█████ █ █ ▄████ ██▀██▄▓█████ # ▓█████▄▓█░ ▀▓█░ █ ░█▓█ ▒ █▓██ ▒ █▓█▒░ ▓ # ▒██▒ ▄█▒███ ▒█░ █ ░█▓█ ░ █▓██ ░▄█▒███ # ▒██░█▀ ▒▓█ ▄░█▄ █░▄█▒█▀▀▀█▒██▀▀█▄▒▓█ ▄ # ░▓█ ▀█░▒████░░██▒██░██▓ ▒█░██▓ ▒█░▒████▒ # ░▒▓███▀░░ ▒░ ░ ▓░▒ ▒░ ▒▓ ░▒░ ▒▓ ░▒░░ ▒░ ░ # ▒░▒ ░ ░ ░ ░ ▒ ░ ░ ░▒ ░ ▒ ░▒ ░ ▒░ ░ ░ # ░ ░ ░ ░ ░ ░░ ░ ░░ ░ ░ # ░ ░ ░ ░ ░ ░ ░ ░ # this is how i setup my shiz ░ # ░ it might not be great for you ░ # user vars export ME='x0' export X_UID=10806 export PORT=60806 export HOSTNAME='thirteen' export ARCH='x86' # arm, x86 # script vars MYHOME="/home/$ME" ASME="sudo -u $ME" PKGARCH=$ARCH # helper functions function _echo() { printf "\n╓───── %s \n╙────────────────────────────────────── ─ ─ \n" "$1"; } function get() { f="${3:-notesPlain}" op item get "$2" --account "$1" --fields "$f" --format json | jq -rM '.value' } function getfile() { f="${4:-notesPlain}" op --account "$1" read "op://$2/$3/$f" } function account() { domain="${3:-my}.1password.com" op account add \ --address "$domain" \ --email "$2" \ --shorthand "$1" } [ "$(id -u)" -ne 0 ] && { _echo "got root?" >&2 exit 1 } _echo "creating swap" dd if=/dev/zero of=/swapmeet bs=128M count=32 chmod 600 /swapmeet mkswap /swapmeet swapon /swapmeet swapon -s echo "/swapmeet swap swap defaults 0 0" >> /etc/fstab echo "vm.swappiness=0" >> /etc/sysctl.conf sysctl vm.swappiness=0 _echo "installing runtime deps" apt update && apt install -y git gpg bash curl locales gnupg software-properties-common _echo "setting up locales and console" locale-gen "en_US.UTF-8" localectl set-locale en_US.UTF-8 dpkg-reconfigure locales dpkg-reconfigure console-setup systemctl daemon-reload systemctl restart console-setup.service _echo "adding apt sources" # add github curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null # add 1pw curl -sS https://downloads.1password.com/linux/keys/1password.asc | gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/$(dpkg --print-architecture) stable main" | tee /etc/apt/sources.list.d/1password.list > /dev/null mkdir -p /etc/debsig/policies/AC2D62742012EA22/ && curl -sS https://downloads.1password.com/linux/debian/debsig/1password.pol | tee /etc/debsig/policies/AC2D62742012EA22/1password.pol mkdir -p /usr/share/debsig/keyrings/AC2D62742012EA22 && curl -sS https://downloads.1password.com/linux/keys/1password.asc | gpg --dearmor --output /usr/share/debsig/keyrings/AC2D62742012EA22/debsig.gpg # add hashicorp curl -sL https://apt.releases.hashicorp.com/gpg | gpg --dearmor | tee /usr/share/keyrings/hashicorp-archive-keyring.gpg gpg --no-default-keyring \ --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \ --fingerprint echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ https://apt.releases.hashicorp.com $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/hashicorp.list # install all the things \o/ _echo "installing packages" apt update && DEBIAN_FRONTEND=noninteractive apt install -y \ 1password-cli \ apparmor \ apt-utils \ autoconf \ automake \ awscli \ bash \ bash-completion \ bc \ bind9-host \ bsdutils \ build-essential \ ca-certificates \ clamav-base \ cmake \ cmatrix \ coreutils \ curl \ dash \ dbus \ dbus-user-session \ debianutils \ diffutils \ dnsutils \ docker.io \ doxygen \ dpkg \ e2fsprogs \ eslint \ ethtool \ expect \ fail2ban \ findutils \ fzf \ g++ \ gawk \ gcc \ gettext \ gh \ git \ golang \ golang-doc \ golang-src \ gpg \ gpg-agent \ gpgv \ gzip \ htop \ iptables \ iputils-ping \ isc-dhcp-client \ jq \ keychain \ kubernetes-client \ libncurses5-dev \ libprotobuf-dev \ libssl-dev \ libtool \ libtool-bin \ libutempter-dev \ libx11-dev \ libxfixes-dev \ lsb-base \ lua5.4 \ luajit \ luarocks \ man-db \ manpages \ mawk \ ncurses-base \ ncurses-bin \ ncurses-term \ net-tools \ netbase \ ninja-build \ nmap \ ocproxy \ openconnect \ openssh-client \ openssh-server \ openssl \ pciutils \ perl \ perl-base \ pkg-config \ protobuf-compiler \ proxychains4 \ psmisc \ python3 \ python3-boto \ python3-pip \ python3-venv \ ripgrep \ rkhunter \ rsyslog \ secure-delete \ shellcheck \ silversearcher-ag \ socat \ stow \ sudo \ tar \ tcpdump \ terraform \ tmux \ toilet \ traceroute \ tree \ tzdata \ unzip \ util-linux \ uuid-runtime \ vim-tiny \ vpnc \ whiptail \ whois \ xsel \ xvfb \ xz-utils \ zlib1g \ zlib1g-dev \ zsh \ zsh-syntax-highlighting _echo "systemd housekeeping" systemctl stop docker.service systemctl stop containerd.service systemctl enable clamav-freshclam.service _echo "setting up timezone and hostname" timedatectl set-timezone America/New_York hostname "$HOSTNAME" hostnamectl set-hostname "$HOSTNAME" sed -i '/^127\.0\.0\.1\s/s/$/ '"$HOSTNAME"'/' /etc/hosts sed -i '/^127\.0\.0\.1\s/s/$/ '"$HOSTNAME"'/' /etc/cloud/templates/hosts.debian.tmpl _echo "creating local user" adduser --uid "$X_UID" --shell "$(which zsh)" "$ME" _echo "granting root access" echo "${ME} ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/$ME" _echo "setting up 1password" account x0 "x@xero.style" eval "$(op signin --account x0)" _echo "setting up key keychain" get x0 GH_TOKEN | $ASME gh auth login -p ssh --with-token mkdir -p $MYHOME/.ssh if [[ -d /home/admin/.ssh ]]; then cp /home/admin/.ssh/authorized_keys $MYHOME/.ssh/authorized_keys else cp /root/.ssh/authorized_keys $MYHOME/.ssh/authorized_keys fi get x0 id_ed25519_github privateKey > $MYHOME/.ssh/id_ed25519 get x0 id_ed25519_github publicKey > $MYHOME/.ssh/id_ed25519.pub ssh-keyscan -p 22 -H github.com gist.github.com > /root/.ssh/known_hosts $ASME ssh-keyscan -p 22 -H github.com gist.github.com > $MYHOME/.ssh/known_hosts chown -R $ME:$ME /home/$ME/.ssh chmod 700 $MYHOME/.ssh chmod 600 $MYHOME/.ssh/* # i do not want these dirs to be symlinks _echo "creating directory skeletons" $ASME mkdir -p \ $MYHOME/.{config,local} \ $MYHOME/.local/{bin,docs,cache,lib,share,src,state} \ $MYHOME/.local/state/zsh _echo "setting up rust" curl https://sh.rustup.rs -sSf | $ASME CARGO_HOME="$MYHOME/.local/lib/cargo" RUSTUP_HOME="$MYHOME/.local/lib/rustup" sh -s -- -y --default-toolchain stable --profile default && $ASME CARGO_HOME="$MYHOME/.local/lib/cargo" RUSTUP_HOME="$MYHOME/.local/lib/rustup" $MYHOME/.local/lib/cargo/bin/cargo install cargo-quickinstall && $ASME CARGO_HOME="$MYHOME/.local/lib/cargo" RUSTUP_HOME="$MYHOME/.local/lib/rustup" $MYHOME/.local/lib/cargo/bin/cargo quickinstall lolcat stylua _echo "setting up starship" if [[ "$ARCH" == "arm" ]]; then curl -sS https://starship.rs/install.sh | sh else $ASME CARGO_HOME="$MYHOME/.local/lib/cargo" RUSTUP_HOME="$MYHOME/.local/lib/rustup" $MYHOME/.local/lib/cargo/bin/cargo quickinstall starship fi _echo "building neovim" $ASME git clone --depth=1 https://github.com/neovim/neovim.git -b stable $MYHOME/.local/src/neovim && cd $MYHOME/.local/src/neovim && CMAKE_BUILD_TYPE=RelWithDebInfo make && make install _echo "setting up dotfiles" $ASME git clone git@github.com:xero/dotfiles.git $MYHOME/.local/src/dotfiles && cd $MYHOME/.local/src/dotfiles && $ASME stow bin fun git gpg ssh tmux neovim zsh -t $MYHOME # tmux $ASME mkdir $MYHOME/.config/tmux/plugins && $ASME git clone --depth=1 https://github.com/tmux-plugins/tpm $MYHOME/.config/tmux/plugins/tpm && $ASME $MYHOME/.config/tmux/plugins/tpm/scripts/install_plugins.sh && cd $MYHOME/.config/tmux/plugins/tmux-thumbs && expect -c "spawn ./tmux-thumbs-install.sh; send \"\r1\r\"; expect complete" 1> /dev/null # nvim $ASME mkdir $MYHOME/.local/nvim && $ASME git clone --filter=blob:none --single-branch https://github.com/folke/lazy.nvim.git $MYHOME/.local/share/nvim/lazy $ASME nvim --headless "+Lazy! sync" +qa $ASME nvim --headless "+MasonInstallAll" +qa # shellcheck disable=SC2016 echo 'export ZDOTDIR="$HOME"/.config/zsh' >> /etc/zsh/zshenv _echo "creating ~src, ~docs, and ~dotfiles aliases" useradd -g src -d $MYHOME/.local/src src useradd -d $MYHOME/.local/src/dotfiles dotfiles useradd -d $MYHOME/docs docs _echo "building mosh" # OSC52 clipboard support - https://github.com/mobile-shell/mosh/pull/1104 $ASME git clone --depth=1 https://github.com/mgulick/mosh.git -b osc-52-clipboard-types $MYHOME/.local/src/mosh && cd $MYHOME/.local/src/mosh && ./autogen.sh && ./configure && make && make install _echo "building clipmenu" $ASME git clone --recurse-submodules git@github.com:xero/clipmenu.git $MYHOME/.local/src/clipmenu && cd $MYHOME/.local/src/clipmenu/clipnotify && make install && cd .. && make install && $ASME systemctl --user daemon-reload && $ASME systemctl --user restart clipmenud.service &> /dev/null _echo "setting up kubectx" $ASME git clone --depth=1 https://github.com/ahmetb/kubectx.git $MYHOME/.local/src/kubectx && mv $MYHOME/.local/src/kubectx/kubectx $MYHOME/.local/src/kubectx/kubens $MYHOME/.local/bin/ && chmod +x $MYHOME/.local/bin/kubens $MYHOME/.local/bin/kubectx _echo "setting up k9s" [[ "$ARCH" == "arm" ]] && PKGARCH="arm64" || PKGARCH="amd64" $ASME curl -L "https://github.com/derailed/k9s/releases/download/v0.27.4/k9s_Linux_${PKGARCH}.tar.gz" -o $MYHOME/.local/src/k9s.tar.gz && tar xzf $MYHOME/.local/src/k9s.tar.gz -C $MYHOME/.local/bin/ k9s && chmod +x $MYHOME/.local/bin/k9s && rm $MYHOME/.local/src/k9s.tar.gz echo "updating the aws cli to v2" [[ "$ARCH" == "arm" ]] && PKGARCH="aarch64" || PKGARCH="x86_64" curl -L "https://awscli.amazonaws.com/awscli-exe-linux-${PKGARCH}.zip" -o /tmp/awscliv2.zip && cd /tmp && unzip awscliv2.zip && ./aws/install --bin-dir /usr/bin --install-dir /usr/local/aws-cli --update && rm /tmp/awscliv2.zip _echo "setting up node with nave" $ASME mkdir -p $MYHOME/.config/node curl -L https://raw.githubusercontent.com/isaacs/nave/main/nave.sh > $MYHOME/.local/bin/nave && chmod +x $MYHOME/.local/bin/nave && NAVE_DIR="$MYHOME/.local/lib/nodejs" $MYHOME/.local/bin/nave usemain lts && $ASME npm i -g \ neovim \ sofancy _echo "setting up python + pip" $ASME pip3 -V $ASME pip3 install --upgrade pip $ASME pip3 install --no-warn-script-location \ boto3 \ cryptography \ docutils \ emoji-fzf \ greynoise \ https://github.com/PaulSec/API-dnsdumpster.com/archive/master.zip \ json-spec \ mycli \ neovim \ pgcli \ six \ urllib3 \ wcwidth _echo "setting up ascii/ansi art tools" rm -rf /usr/share/figlet/ git clone --depth=1 https://github.com/xero/figlet-fonts.git /usr/share/figlet/ $ASME git clone --depth=1 https://github.com/digitallyserviced/tdfgo.git $MYHOME/.local/src/tdfgo && cd $MYHOME/.local/src/tdfgo && $ASME go build && mv ./tdfgo $MYHOME/.local/bin/tdfgo && chmod +x $MYHOME/.local/bin/tdfgo && mkdir -p $MYHOME/.config/tdfgo && mv ./fonts $MYHOME/.config/tdfgo/fonts _echo "updating motd" rm /etc/motd /etc/update-motd.d/* cat << 'X0' > /etc/update-motd.d/00-banner #!/bin/bash draw() { out= perc=$1 size=$2 inc=$(( perc * size / 100 )) color=36 color2=95 for v in $(seq 0 $(( size - 1 ))); do [ "$v" -le "$inc" ] && out="${out}\e[1;${color}m${FULL}" || out="${out}\e[0;${color2}m${EMPTY}" done printf "$out" } i=1 c=$(printf "\e[0m\e[31m░▒") while [ $i -le 6 ];do c=${c}$(printf "\e[$((i+41))m\e[$((i+30))m█▓▒░") i=$((i+1)) done COLORS=${c}$(printf "\e[37m█\e[0m▒░") FULL=━ EMPTY=┄ HOST=$(hostname) IP=$(curl -s icanhazip.com) #$(hostname -I | cut -d' ' -f1) DISTRO=$(grep PRETTY /dev/null | grep -c 'installed') UPTIME=$(uptime -p | cut -d " " -f2-) [[ ${#UPTIME} -ge 22 ]] && UPTIME=$(echo "$UPTIME" | sed 's/ hours/hrs/;s/ minutes/mins/') c_lvl=$(printf "%.0f" `grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage}'`) CPU=$(printf "\e[0;36m%-4s \e[1;95m%-5s %-25s \n" "cpu" "$c_lvl%" `draw "$c_lvl" 18`) ram_lvl=$(free | awk '/Mem:/ {print int($3/$2 * 100.0)}') RAM=$(printf "\e[0;36m%-4s \e[1;95m%-5s %-25s \n" "ram" "$ram_lvl%" `draw "$ram_lvl" 18`) disk_lvl=$(df -h | grep '/$' | tr -s ' ' | cut -d ' ' -f5 | sed 's/%//') DISK=$(printf "\e[0;36m%-4s \e[1;95m%-5s %-25s \n" "disk" "$disk_lvl%" `draw "$disk_lvl" 18`) PPID1=$(grep PPid <"/proc/$PPID/status" | awk '{ print $2 }') PPID2=$(grep PPid <"/proc/$PPID1/status" | awk '{ print $2 }') USERNAME=$(pgrep "$PPID2" | awk '{ print $6 }' | head -1) [ -z "$USERNAME" ] && USERNAME=$USER files=0 IFS=':' read -r -a PATHS <<<"$PATH" mapfile -t DIRS <<<"$(printf "%s\n" "${PATHS[@]}" | sort -u)" for d in "${DIRS[@]}"; do [ -d "$d" ] && { new=$(find "$d" -maxdepth 1 -type f -executable -print | wc -l); files=$(( files+new )); } done cat << EOF  ▄████    ▄███▄  ▄▄ ▒▓█ ▄▄▀ █▓░ ░▓█ ▀▄▄ welcome to $HOST, $USERNAME ▒▒ ░▒▓ ▒▒ ▓▓░▌▄▐░▓▓ ▒▒ $COLORS ▀▀ ░░▒ ▀▀ ▓▒░ ▀ ░▒▓ ▀▀ distro: $DISTRO ░░ ░░░ ░░▄▄▄▄ ▀ ░░░ ░░ kernel: $KERNEL ▒▒ ▒░░ ▒▒▓▓▓▓ ░░░░▒ ▒▒ public address: $IP ▓▓ ▒▒░ ▓▓▀▀▀▀ ▄ ▒▒▓ ▓▓ uptime: $UPTIME ██ ▓▒▒ ██ ▓▓▓ ▓ ██▓ ██ packages: $PKGS +  bins: $files ▄▄ █▓▓ ▄▄ █▓▓ ▄ ▓██ ▄▄ $CPU ▒▒ ██▓ ▒▒ ██▓ ▀ ███ ▒▒ $RAM ▀▀ ███ ▀▀▄ ███ ███ ▄▀▀ $DISK  ███████   ▀███▀    EOF X0 chmod +x /etc/update-motd.d/00-banner # run ssh on a non-standard port _echo "setting up ssh" echo "Port $PORT" >> /etc/ssh/sshd_config systemctl restart ssh.service systemctl restart sshd _echo "setting up fail2ban" cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local fail2ban-client reload _echo "final user setup stuff" getfile x0 keys runme runme > $MYHOME/runme op signout --account x0 --forget $ASME rm $MYHOME/.profile $MYHOME/.bash* mv $MYHOME/go $MYHOME/.local/lib/ mv $MYHOME/.cache $MYHOME/cache mv $MYHOME/cache/* $MYHOME/cache rm -rf $MYHOME/.npm chmod +x $MYHOME/runme chown -R $ME:$ME /home/$ME _echo "removing default user" userdel -rf admin &> /dev/null && rm /etc/sudoers.d/90-cloud-init-users _echo "setup complete. rebooting the vps. reconnect as yourself via mosh" IP=$(curl -sL icanhazip.com) echo "$HOSTNAME: $ME@$IP:$PORT" echo "mosh location: $(which mosh-server)" # self destruct srm -dvrl "$0" &> /dev/null systemctl reboot