setup
#!/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" ""; }
function get() {
f="${3:-notesPlain}"
op item get "" --account "" --fields "$f" --format json | jq -rM '.value'
}
function getfile() {
f="${4:-notesPlain}"
op --account "" read "op:////$f"
}
function account() {
domain="${3:-my}.1password.com"
op account add \
--address "$domain" \
--email "" \
--shorthand ""
}
[ "$(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 \
libevent-dev \
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"
$ASME git clone --depth=1 https://github.com/mobile-shell/mosh.git $MYHOME/.local/src/mosh &&
cd $MYHOME/.local/src/mosh &&
git fetch origin && git checkout mosh-1.4.0 &&
./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 fzf"
[[ "$ARCH" == "arm" ]] && PKGARCH="arm64" || PKGARCH="amd64"
$ASME curl -L "https://github.com/junegunn/fzf/releases/download/v0.55.0/fzf-0.55.0-linux_${PKGARCH}.tar.gz" -o $MYHOME/.local/src/fzf.tar.gz
tar xzf $MYHOME/.local/src/fzf.tar.gz -C /usr/bin/ fzf &&
chmod +x /usr/bin/fzf &&
rm $MYHOME/.local/src/fzf.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=
size=
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 </etc/os-release | sed 's/PRETTY_NAME=//;s/"//g;s/GNU.Linux / /') # TAKE THAT RMS ;P
KERNEL=$(uname -r)
PKGS=$(apt list --installed 2>/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=(+)*100/(++)} 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(/ * 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 }')
PPID2=$(grep PPid <"/proc/$PPID1/status" | awk '{ print }')
USERNAME=$(pgrep "$PPID2" | awk '{ print }' | 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
[37;40m [95;40m▄[95;45m██[95;40m██[37;40m [37;40m [37;40m [37;40m [95;40m▄█[95;40m██[95;40m▄[37;40m [37;40m
[90;40m▄▄[37;40m [95;45m▒▓[95;45m█[37;40m [90;40m▄▄[90;40m▀[37;40m [95;40m█[95;45m▓░[37;40m [95;45m░▓[95;40m█[37;40m [90;40m▀[90;40m▄▄[37;40m welcome to [95;40m$HOST[37;40m, $USERNAME
[36;40m▒▒[37;40m [95;45m░▒[95;45m▓[37;40m [36;40m▒▒[37;40m [95;45m▓▓[95;45m░[35;40m▌[90;40m▄[35;40m▐[95;45m░▓[95;45m▓[37;40m [36;40m▒▒ $COLORS
[90;40m▀▀[37;40m [96;46m░[95;45m░▒[37;40m [90;40m▀▀[37;40m [95;45m▓▒[95;45m░[37;40m [90;40m▀[37;40m [96;46m░[95;45m▒▓[37;40m [90;40m▀▀[95;40m distro: $DISTRO
[34;40m░░[37;40m [96;46m░░[95;45m░[37;40m [34;40m░░[34;40m▄▄[34;40m▄▄[37;40m [34;40m▀[37;40m [96;46m░░[95;45m░[37;40m [34;40m░░[37;40m kernel: $KERNEL
[34;40m▒▒[37;40m [96;46m▒░[96;46m░[37;40m [34;40m▒▒[34;40m▓▓[34;40m▓▓[37;40m [96;46m░░[96;46m░░[96;46m▒[37;40m [34;40m▒▒[34;40m public address: $IP
[34;40m▓▓[37;40m [96;46m▒▒[96;46m░[37;40m [34;40m▓▓[34;40m▀▀[34;40m▀▀[37;40m [34;40m▄[37;40m [96;46m▒▒[96;46m▓[37;40m [34;40m▓▓[90;40m uptime: $UPTIME
[34;40m██[37;40m [96;46m▓▒[96;46m▒[37;40m [34;40m██[37;40m [96;46m▓▓[96;46m▓[37;40m [34;40m▓[37;40m [96;40m██[96;40m▓[37;40m [34;40m██ packages: $PKGS [95;40m+ [34;40m bins: $files
[90;40m▄▄[37;40m [96;46m█▓[96;46m▓[37;40m [90;40m▄▄[37;40m [96;40m█[96;46m▓▓[37;40m [90;40m▄[37;40m [96;46m▓█[96;46m█[37;40m [90;40m▄▄ $CPU
[36;40m▒▒[37;40m [96;46m██[96;46m▓[37;40m [36;40m▒▒[37;40m [96;40m██[96;46m▓[37;40m [90;40m▀[37;40m [96;46m██[96;46m█[37;40m [36;40m▒▒ $RAM
[90;40m▀▀[37;40m [96;46m██[96;46m█[37;40m [90;40m▀▀[90;40m▄[37;40m [96;40m█[96;46m██[37;40m [96;46m██[96;46m█[37;40m [90;40m▄[90;40m▀▀ $DISK
[37;40m [96;40m██[96;40m██[96;40m██[96;40m█[37;40m [37;40m [37;40m [96;40m▀[96;46m██[96;46m█[96;40m▀[37;40m [37;40m [37;40m [37;40m
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 "{{&blob}}" &> /dev/null
systemctl reboot