Skip to content

Instantly share code, notes, and snippets.

@luoling8192
Last active November 26, 2024 11:54
Show Gist options
  • Select an option

  • Save luoling8192/883e774ddf3e6da1408d6d955912d1dc to your computer and use it in GitHub Desktop.

Select an option

Save luoling8192/883e774ddf3e6da1408d6d955912d1dc to your computer and use it in GitHub Desktop.
Ubuntu Setup Script
#!/bin/bash
# Define colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Define package groups
MIRROR="https://mirrors.tuna.tsinghua.edu.cn/ubuntu"
KEYRING="/usr/share/keyrings/ubuntu-archive-keyring.gpg"
SYSTEM_PACKAGES="build-essential"
SHELL_PACKAGES="zsh neovim curl wget nala"
UTIL_PACKAGES="neofetch eza"
ZIMRC="$HOME/.zimrc"
ZSHRC="$HOME/.zshrc"
GITHUB_USER="luoling8192"
# Helper function for confirmation
confirm() {
read -p "$(echo -e "${YELLOW}$1 [y/N]${NC} ")" response
case "$response" in
[yY][eE][sS]|[yY])
return 0
;;
*)
return 1
;;
esac
}
# Configure apt sources
configure_apt() {
echo -e "${GREEN}Configuring APT sources...${NC}"
cat << EOF | sudo tee /etc/apt/sources.list.d/ubuntu.sources || echo -e "${RED}Failed to configure APT sources${NC}"
Types: deb
URIs: $MIRROR
Suites: noble noble-updates noble-backports
Components: main restricted universe multiverse
Signed-By: $KEYRING
# Default source code mirror is commented out to improve apt update speed
Types: deb-src
URIs: $MIRROR
Suites: noble noble-updates noble-backports
Components: main restricted universe multiverse
Signed-By: $KEYRING
# Security updates from official source and mirror
Types: deb
URIs: http://security.ubuntu.com/ubuntu/
Suites: noble-security
Components: main restricted universe multiverse
Signed-By: $KEYRING
Types: deb-src
URIs: http://security.ubuntu.com/ubuntu/
Suites: noble-security
Components: main restricted universe multiverse
Signed-By: $KEYRING
# Pre-release software sources (not recommended)
# Types: deb
# URIs: $MIRROR
# Suites: noble-proposed
# Components: main restricted universe multiverse
# Signed-By: $KEYRING
# Types: deb-src
# URIs: $MIRROR
# Suites: noble-proposed
# Components: main restricted universe multiverse
# Signed-By: $KEYRING
EOF
}
# Update system packages
update_system() {
echo -e "${GREEN}Updating system packages...${NC}"
sudo apt update -y && sudo apt upgrade -y || echo -e "${RED}Failed to update system packages${NC}"
echo -e "${GREEN}Installing required packages...${NC}"
sudo apt install -y $SYSTEM_PACKAGES $SHELL_PACKAGES $UTIL_PACKAGES || echo -e "${RED}Failed to install required packages${NC}"
}
# Configure SSH
configure_ssh() {
echo -e "${GREEN}Configuring SSH server...${NC}"
# Enable key auth and keepalive
sudo sed -i 's/#Port 22/Port 22/' /etc/ssh/sshd_config || echo -e "${RED}Failed to configure SSH port${NC}"
sudo sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config || echo -e "${RED}Failed to enable SSH key authentication${NC}"
sudo sed -i 's/#ClientAliveInterval 0/ClientAliveInterval 60/' /etc/ssh/sshd_config || echo -e "${RED}Failed to set client alive interval${NC}"
sudo sed -i 's/#ClientAliveCountMax 3/ClientAliveCountMax 3/' /etc/ssh/sshd_config || echo -e "${RED}Failed to set client alive count${NC}"
setup_ssh_keys
restart_ssh
}
setup_ssh_keys() {
echo -e "${GREEN}Setting up SSH keys...${NC}"
mkdir -p ~/.ssh || echo -e "${RED}Failed to create SSH directory${NC}"
curl -fsSL https://github.com/$GITHUB_USER.keys > ~/.ssh/authorized_keys || echo -e "${RED}Failed to download SSH keys${NC}"
chmod 700 ~/.ssh || echo -e "${RED}Failed to set SSH directory permissions${NC}"
chmod 600 ~/.ssh/authorized_keys || echo -e "${RED}Failed to set SSH key permissions${NC}"
}
restart_ssh() {
echo -e "${GREEN}Restarting SSH service...${NC}"
sudo systemctl restart sshd || echo -e "${RED}Failed to restart SSH service${NC}"
}
# Configure zsh environment
setup_zsh() {
change_default_shell
install_zim
install_zim_plugins
configure_shell_aliases
install_atuin
setup_env_vars
add_command_not_found_handler
}
change_default_shell() {
echo -e "${GREEN}Changing default shell to zsh...${NC}"
sudo chsh -s $(which zsh) || echo -e "${RED}Failed to change default shell${NC}"
echo -e "${GREEN}Cleaning up existing Zim installation...${NC}"
rm -rf ~/.zim || echo -e "${RED}Failed to remove existing Zim installation${NC}"
if confirm "Remove existing zshrc?"; then
rm -f $ZSHRC || echo -e "${RED}Failed to remove existing zshrc${NC}"
fi
}
install_zim() {
reset
echo -e "${GREEN}Installing Zim framework...${NC}"
curl -fsSL https://raw.githubusercontent.com/zimfw/install/master/install.zsh | zsh || echo -e "${RED}Failed to install Zim framework${NC}"
source $ZSHRC
}
install_zim_plugins() {
reset
echo -e "${GREEN}Installing Zim plugins...${NC}"
echo "zmodule Aloxaf/fzf-tab" >> $ZIMRC || echo -e "${RED}Failed to add fzf-tab plugin${NC}"
echo "zmodule romkatv/powerlevel10k --use degit" >> $ZIMRC || echo -e "${RED}Failed to add powerlevel10k plugin${NC}"
zsh -c "zimfw install" || echo -e "${RED}Failed to install Zim plugins${NC}"
source $ZSHRC
echo -e "${GREEN}Configuring Powerlevel10k theme...${NC}"
zsh -c "p10k configure" || echo -e "${RED}Failed to configure Powerlevel10k${NC}"
}
configure_shell_aliases() {
echo -e "${GREEN}Configuring shell aliases...${NC}"
cat << 'EOF' >> $ZSHRC || echo -e "${RED}Failed to configure shell aliases${NC}"
# Aliases
alias vim=nvim
alias ls=eza
alias ll="eza -lah"
alias sudo="sudo "
alias ip="ip -c"
alias reload="source $HOME/.zshrc"
alias zshrc="vim $HOME/.zshrc"
# Git aliases
alias gcl="git clone"
alias ga="git add"
alias gaa="git add -A"
alias gcm="git commit -m"
alias gcma="git commit -m -a"
alias gp="git push"
alias gpl="git pull --rebase"
alias main="git switch main"
EOF
source $ZSHRC
}
install_atuin() {
echo -e "${GREEN}Installing Atuin shell history manager...${NC}"
# Check if atuin is already installed
if command -v atuin >/dev/null 2>&1; then
echo -e "${YELLOW}Atuin is already installed, skipping...${NC}"
return
fi
if confirm "Do you want to install Atuin shell history manager?"; then
bash <(curl -fsSL "https://raw.githubusercontent.com/atuinsh/atuin/main/install.sh") || echo -e "${RED}Failed to install Atuin${NC}"
echo 'eval "$(atuin init zsh)"' >> $ZSHRC || echo -e "${RED}Failed to configure Atuin${NC}"
source $ZSHRC
if confirm "Do you want to import existing shell history?"; then
zsh -c "atuin import auto" || echo -e "${RED}Failed to import shell history${NC}"
fi
if confirm "Do you want to sync shell history with Atuin server?"; then
zsh -c "atuin sync" || echo -e "${RED}Failed to sync shell history${NC}"
fi
fi
}
setup_env_vars() {
echo -e "${GREEN}Setting up environment variables...${NC}"
echo 'export EDITOR="nvim"' >> $ZSHRC || echo -e "${RED}Failed to set editor${NC}"
echo 'export HISTORY_IGNORE="(jetbrains*)"' >> $ZSHRC || echo -e "${RED}Failed to set history ignore${NC}"
source $ZSHRC
}
add_command_not_found_handler() {
echo -e "${GREEN}Adding command not found handler...${NC}"
cat << 'EOF' >> $ZSHRC || echo -e "${RED}Failed to add command not found handler${NC}"
# Handle command not found by removing from history
[ ${BASH_VERSION} ] && PROMPT_COMMAND="mypromptcommand"
[ ${ZSH_VERSION} ] && precmd() { mypromptcommand; }
function mypromptcommand {
local exit_status=$?
if [ ${ZSH_VERSION} ]; then
local number=$(history -1 | awk '{print $1}')
elif [ ${BASH_VERSION} ]; then
local number=$(history 1 | awk '{print $1}')
fi
if [ -n "$number" ]; then
if [ $exit_status -eq 127 ] && ([ -z $HISTLASTENTRY ] || [ $HISTLASTENTRY -lt $number ]); then
local RED='\033[0;31m'
local NC='\033[0m'
if [ ${ZSH_VERSION} ]; then
local HISTORY_IGNORE="${(b)$(fc -ln $number $number)}"
fc -W
fc -p $HISTFILE $HISTSIZE $SAVEHIST
elif [ ${BASH_VERSION} ]; then
local HISTORY_IGNORE=$(history 1 | awk '{print $2}')
history -d $number
fi
echo -e "${RED}Deleted '$HISTORY_IGNORE' from history.${NC}"
else
HISTLASTENTRY=$number
fi
fi
}
EOF
source $ZSHRC
}
# Configure p10k theme
configure_p10k() {
echo -e "${GREEN}Configuring Powerlevel10k theme...${NC}"
sed -i '
/POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=/ {
s/#.*node_version/node_version/
s/#.*go_version/go_version/
s/#.*rust_version/rust_version/
s/#.*dotnet_version/dotnet_version/
s/#.*php_version/php_version/
s/#.*laravel_version/laravel_version/
s/#.*java_version/java_version/
s/#.*terraform_version/terraform_version/
}' ~/.p10k.zsh || echo -e "${RED}Failed to configure Powerlevel10k theme${NC}"
}
# Setup Node environment
setup_node() {
install_nvm
configure_nvm
install_node
setup_package_managers
verify_node
}
install_nvm() {
# Skip if nvm is already installed
if [ -d "$HOME/.nvm" ]; then
echo -e "${GREEN}NVM is already installed, skipping...${NC}"
return
fi
echo -e "${GREEN}Installing Node Version Manager (nvm)...${NC}"
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash || echo -e "${RED}Failed to install NVM${NC}"
}
configure_nvm() {
echo -e "${GREEN}Configuring nvm environment...${NC}"
cat << 'EOF' >> $ZSHRC || echo -e "${RED}Failed to configure NVM environment${NC}"
# NVM configuration
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
EOF
}
install_node() {
# Skip if node is already installed
if command -v node >/dev/null 2>&1; then
echo -e "${GREEN}Node.js is already installed, skipping...${NC}"
return
fi
echo -e "${GREEN}Installing latest LTS version of Node.js...${NC}"
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
zsh -c "nvm install --lts" || echo -e "${RED}Failed to install Node.js${NC}"
zsh -c "nvm use --lts" || echo -e "${RED}Failed to use Node.js LTS version${NC}"
}
setup_package_managers() {
# Skip if pnpm is already installed
if command -v pnpm >/dev/null 2>&1; then
echo -e "${GREEN}Package managers already setup, skipping...${NC}"
return
fi
echo -e "${GREEN}Setting up package managers...${NC}"
zsh -c "corepack enable" || echo -e "${RED}Failed to enable corepack${NC}"
zsh -c "pnpm setup" || echo -e "${RED}Failed to setup pnpm${NC}"
}
verify_node() {
echo -e "${GREEN}Verifying Node.js installation...${NC}"
zsh -c "node --version" || echo -e "${RED}Failed to verify Node.js installation${NC}"
zsh -c "npm --version" || echo -e "${RED}Failed to verify NPM installation${NC}"
zsh -c "pnpm --version" || echo -e "${RED}Failed to verify PNPM installation${NC}"
}
# Setup Go environment
setup_go() {
# Skip if go is already installed
if command -v go >/dev/null 2>&1; then
echo -e "${GREEN}Go is already installed, skipping...${NC}"
return
fi
install_go
configure_go_env
create_go_workspace
verify_go
}
install_go() {
echo -e "${GREEN}Downloading and installing Go...${NC}"
GO_VERSION="1.21.5"
GO_TAR="go${GO_VERSION}.linux-amd64.tar.gz"
wget "https://go.dev/dl/${GO_TAR}" || echo -e "${RED}Failed to download Go${NC}"
sudo rm -rf /usr/local/go || echo -e "${RED}Failed to remove old Go installation${NC}"
sudo tar -C /usr/local -xzf ${GO_TAR} || echo -e "${RED}Failed to extract Go${NC}"
rm ${GO_TAR} || echo -e "${RED}Failed to cleanup Go installer${NC}"
}
configure_go_env() {
echo -e "${GREEN}Configuring Go environment...${NC}"
cat << 'EOF' >> $ZSHRC || echo -e "${RED}Failed to configure Go environment${NC}"
# Go configuration
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
EOF
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
}
create_go_workspace() {
echo -e "${GREEN}Creating Go workspace...${NC}"
mkdir -p $GOPATH/{bin,src,pkg} || echo -e "${RED}Failed to create Go workspace${NC}"
}
verify_go() {
echo -e "${GREEN}Verifying Go installation...${NC}"
zsh -c "go version" || echo -e "${RED}Failed to verify Go installation${NC}"
}
# Execute configuration functions
echo -e "${GREEN}Starting system configuration...${NC}"
if confirm "Configure APT sources?"; then
configure_apt
fi
if confirm "Update system and install packages?"; then
update_system
fi
if confirm "Configure SSH?"; then
configure_ssh
fi
if confirm "Setup ZSH?"; then
setup_zsh
fi
if confirm "Configure Powerlevel10k?"; then
configure_p10k
fi
if confirm "Setup Node.js?"; then
setup_node
fi
if confirm "Setup Go?"; then
setup_go
fi
echo -e "${GREEN}System configuration completed!${NC}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment