#!/usr/bin/env bash scriptdir=$(dirname $(realpath $0)) tempdir=$(mktemp -d) if [[ $(sudo id -u) -ne 0 ]]; then echo "Please get sudo access first." exit 1 fi # ============================================================ . $scriptdir/configure_user.sh # ============================================================ configure_tuna() { [ $offline -eq 1 ] && return [ $abroad -eq 1 ] && return if confirm_action "要切换 Tuna 源吗?" "N"; then python3 $scriptdir/files/oh-my-tuna.py # 如果 uid 不为 0 则 sudo 再跑一次 if [[ $EUID -ne 0 ]]; then sudo python3 $scriptdir/files/oh-my-tuna.py fi fi } configure_upgrade() { [ $offline -eq 1 ] && return if [ "$(uname)" = "Darwin" ]; then # macOS 系统使用 brew if confirm_action "要运行 brew upgrade 吗?" "N"; then brew update brew upgrade brew cleanup fi else # 其他系统使用 apt if confirm_action "要运行 apt-get upgrade 吗?" "N"; then sudo apt-get update sudo apt-get upgrade -y sudo apt-get autoremove -y fi fi } configure_install_basic() { if [ "$(uname)" = "Darwin" ]; then [ "$1" != "noupdate" ] && brew update brew install tmux htop else [ "$1" != "noupdate" ] && sudo apt-get update sudo apt-get install tmux git curl htop net-tools tar unzip -y fi pip3 install trash-cli --break-system-packages } configure_install_useful() { if [ "$(uname)" = "Darwin" ]; then [ "$1" != "noupdate" ] && brew update brew install hexyl bat tree p7zip brew install mtr else [ "$1" != "noupdate" ] && sudo apt-get update sudo apt-get install hexyl bat tree fd-find fzf -y # 原来有 tcptraceroute 的,用 mtr 替代 sudo apt-get install hping3 mtr -y fi } configure_install_new() { if [ "$(uname)" = "Darwin" ]; then [ "$1" != "noupdate" ] && brew update brew install pigz else [ "$1" != "noupdate" ] && sudo apt-get update sudo apt-get install pigz -y fi pip3 install speedtest-cli --break-system-packages } configure_install_old() { if [ "$(uname)" = "Darwin" ]; then [ "$1" != "noupdate" ] && brew update brew install neofetch cloc else [ "$1" != "noupdate" ] && sudo apt-get update sudo apt-get install neofetch cloc -y fi } configure_install_eza() { if [ "$(uname)" = "Darwin" ]; then brew install eza elif [[ $(uname -m) != "x86_64" && $(uname -m) != "aarch64" ]]; then echo "eza is not supported on $(uname -m)." elif ! command_exists eza; then if [[ "$(lsb_release -is)" == "Ubuntu" && ("$(lsb_release -rs)" == "24.04" || "$(lsb_release -rs)" > "24.04") ]]; then sudo apt-get install eza -y else unzip $scriptdir/files/eza_$(uname -m)-unknown-linux-musl.zip -d $tempdir/eza sudo cp $tempdir/eza/eza /usr/local/bin/ rm $tempdir/eza -r fi fi } configure_install() { if [ "$(uname)" = "Darwin" ]; then # macOS 系统使用 brew if confirm_action "要运行 brew/pip3 install 吗?" "N"; then brew update else return fi else if confirm_action "要运行 apt/pip3 install 吗?" "N"; then sudo apt-get update else return fi fi configure_install_basic noupdate configure_install_useful noupdate configure_install_new noupdate configure_install_eza noupdate } configure_nano() { [ -f ~/.nanorc ] && return if confirm_action "要配置 nano 吗?" "Y"; then pkg_install nano cp $scriptdir/files/.nanorc ~/.nanorc fi } configure_vim() { [ -f ~/.vimrc ] && return if confirm_action "要配置 vim 吗?" "Y"; then pkg_install vim cp $scriptdir/files/.vimrc ~/.vimrc fi } configure_zsh() { [ -d ~/.oh-my-zsh ] && return [ $offline -eq 1 ] && return if confirm_action "要配置 zsh 吗?" "Y"; then pkg_install zsh rm ~/.oh-my-zsh -r git_clone ohmyzsh/ohmyzsh ~/.oh-my-zsh RUNZSH=no ZSH=~/.oh-my-zsh $scriptdir/files/install-ohmyzsh.sh git_clone zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions git_clone zsh-users/zsh-syntax-highlighting ~/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting git_clone paulirish/git-open ~/.oh-my-zsh/custom/plugins/git-open --norecursive pkg_install autojump if ! grep -Fxq "source ~/.oh-my-zsh/custom/00-init.zsh" ~/.zshrc; then local zshrc="$HOME/.zshrc" local search_line="source \$ZSH/oh-my-zsh.sh" local add_line="source ~/.oh-my-zsh/custom/00-init.zsh" if [ "$(uname)" = "Darwin" ]; then # macOS awk -v search="$search_line" -v add="$add_line" '{ if (index($0, search) > 0) print add print $0 }' "$zshrc" >~/.zshrc.temp && mv ~/.zshrc.temp "$zshrc" else # Linux sed -i "\|${search_line}|i ${add_line}" "$zshrc" fi fi # 如果 ~/.zshrc 里面没有 source ~/.zsh_user 则添加 if ! grep -qx "source ~/.zsh_user" ~/.zshrc; then if [ "$(uname)" = "Darwin" ]; then # macOS printf "\nsource ~/.zsh_user\n" >> ~/.zshrc else # Linux sed -i '$a source ~/.zsh_user' ~/.zshrc fi fi # 如果 ~/.zshrc 里面没有 conda initialize 则运行 mamba init zsh if ! grep -q "conda initialize" ~/.zshrc; then if [ -d ~/.miniconda3 ]; then ~/.miniconda3/bin/mamba init zsh elif [ -d ~/.miniforge3 ]; then ~/.miniforge3/bin/mamba init zsh fi fi cp $scriptdir/files/zsh/.zsh_user ~/.zsh_user cp $scriptdir/files/zsh/00-init.zsh ~/.oh-my-zsh/custom/ cp $scriptdir/files/zsh/10-theme.zsh ~/.oh-my-zsh/custom/ cp $scriptdir/files/zsh/20-function.zsh ~/.oh-my-zsh/custom/ cp $scriptdir/files/zsh/50-env.zsh ~/.oh-my-zsh/custom/ cp $scriptdir/files/zsh/51-alias.zsh ~/.oh-my-zsh/custom/ cp $scriptdir/files/zsh/90-other.zsh ~/.oh-my-zsh/custom/ cp $scriptdir/files/zsh/ys-simple.zsh-theme ~/.oh-my-zsh/custom/themes/ [ $abroad -eq 1 ] && return cp $scriptdir/files/zsh/80-proxy.zsh ~/.oh-my-zsh/custom/ fi } configure_tmux() { [ -f ~/.tmux.conf ] && return [ $offline -eq 1 ] && return if confirm_action "要配置 tmux 吗?" "Y"; then sudo apt-get install tmux -y rm ~/.tmux -r git_clone tmux-plugins/tpm ~/.tmux/plugins/tpm --norecursive git_clone tmux-plugins/tmux-sensible ~/.tmux/plugins/tmux-sensible git_clone tmux-plugins/tmux-yank ~/.tmux/plugins/tmux-yank git_clone tmux-plugins/tmux-prefix-highlight ~/.tmux/plugins/tmux-prefix-highlight git_clone seebi/tmux-colors-solarized ~/.tmux/plugins/tmux-colors-solarized cp $scriptdir/files/.tmux.conf ~/.tmux.conf [ "$(uname)" = "Darwin" ] && return sudo apt-get install xsel -y # 能够让 tmux 剪切板与 terminal 同步 fi } configure_docker() { command_exists docker && return [ $offline -eq 1 ] && return if confirm_action "要安装 docker 吗?" "N"; then # 卸载旧版本 sudo apt-get remove docker docker-engine docker.io sudo apt-get update sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release -y # 检查系统架构是否为 x86_64 if [[ $(uname -m) != "x86_64" ]]; then echo "Docker is only supported on amd64 architecture." return fi # 添加软件源的 GPG 密钥,并向 sources.list 中添加 Docker 软件源 if [ $abroad -eq 1 ]; then curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/docker-archive-keyring.gpg >/dev/null echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null else curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/docker-archive-keyring.gpg >/dev/null echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null fi sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io -y sudo systemctl enable docker sudo systemctl start docker # 安装 docker-compose-plugin sudo apt-get install docker-compose-plugin -y # 安装 docker-compose latest_version=$(curl -s "https://api.github.com/repos/docker/compose/releases/latest" | grep -o '"tag_name": ".*"' | cut -d'"' -f4) if [ -z "$latest_version" ]; then latest_version="v2.27.0" fi echo "Latest version of docker-compose is $latest_version" sudo curl -L "$github/docker/compose/releases/download/$latest_version/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose # 如果 user 不是 root 的话,还得顺便配置一下 docker rootless if [[ $EUID -ne 0 ]]; then mkdir -p ~/.config/docker if [ $abroad -eq 1 ]; then cp $scriptdir/files/docker-rootless-daemon-aboard.json ~/.config/docker/daemon.json else cp $scriptdir/files/docker-rootless-daemon-internal.json ~/.config/docker/daemon.json fi sudo apt-get install -y uidmap /usr/bin/dockerd-rootless-setuptool.sh install # 设置 linger 为 on sudo loginctl enable-linger $USER fi fi } configure_yarn() { echo "Incomplete" return curl -fsSL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/yarn.gpg >/dev/null echo "deb [signed-by=/usr/share/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list >/dev/null } configure_mongodb() { echo "Incomplete" return version=7.0 curl -fsSL https://pgp.mongodb.com/server-$version.asc | gpg --dearmor | sudo tee /usr/share/keyrings/mongodb-server-$version.gpg >/dev/null echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/mongodb-server-$version.gpg] https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/$version multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-$version.list >/dev/null } configure_nginx() { [ $offline -eq 1 ] && return if [ ! -f /etc/apt/sources.list.d/nginx.list ]; then curl -fsSL https://nginx.org/keys/nginx_signing.key | gpg --dearmor | sudo tee /usr/share/keyrings/nginx.gpg >/dev/null echo "deb [signed-by=/usr/share/keyrings/nginx.gpg] https://nginx.org/packages/ubuntu/ $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list >/dev/null echo "deb-src [signed-by=/usr/share/keyrings/nginx.gpg] https://nginx.org/packages/ubuntu/ $(lsb_release -cs) nginx" | sudo tee -a /etc/apt/sources.list.d/nginx.list >/dev/null fi if confirm_action "要安装 nginx 吗?" "Y"; then if command_exists nginx && ! confirm_action "检测到旧版 nginx 的存在 ($(nginx -v 2>&1)),是否继续安装?" "N"; then # sudo apt-get remove nginx -y return fi sudo apt-get update sudo apt-get install nginx -y echo "nginx 版本: $(nginx -v 2>&1)" echo "别忘了把 /etc/nginx/sites-enabled 中的配置文件移动到 /etc/nginx/conf.d 中" fi } configure_fail2ban() { [ -f /etc/fail2ban/jail.local ] && return [ $offline -eq 1 ] && return [ "$(uname)" = "Darwin" ] && return if confirm_action "要配置 fail2ban 吗?" "N"; then sudo apt-get install fail2ban -y sudo mkdir -p /etc/fail2ban sudo cp $scriptdir/files/jail.local /etc/fail2ban/jail.local sudo systemctl start fail2ban sudo systemctl enable fail2ban sudo fail2ban-client status sshd fi } configure_iptables() { [ $offline -eq 1 ] && return [ "$(uname)" = "Darwin" ] && return # 如果 ufw 是 active,就直接返回 if command_exists ufw; then if sudo ufw status | grep -q "Status: active"; then echo "检测到 ufw 已启用,跳过 iptables 配置。" return fi if confirm_action "检测到 ufw 已存在,是否直接使用 ufw 进行管理,跳过 iptables" "Y"; then return fi fi if command_exists ifquery && systemctl is-active --quiet networking; then # ifupdown: /etc/network/if-pre-up.d/iptables-load [ -f /etc/network/if-pre-up.d/iptables-load ] && return if confirm_action "要配置 iptables 吗?" "N"; then sudo cp $scriptdir/files/iptables-load /etc/network/if-pre-up.d/iptables-load sudo chmod +x /etc/network/if-pre-up.d/iptables-load sudo sh /etc/network/if-pre-up.d/iptables-load fi else # systemd: /etc/network/iptables-load [ -f /etc/network/iptables-load ] && return if confirm_action "要配置 iptables 吗?" "N"; then if [ -f /etc/network/if-pre-up.d/iptables-load ]; then sudo mv /etc/network/if-pre-up.d/iptables-load /etc/network/iptables-load else sudo cp $scriptdir/files/iptables-load /etc/network/iptables-load sudo chmod +x /etc/network/iptables-load sudo sh /etc/network/iptables-load fi sudo cp $scriptdir/files/iptables-load.service /etc/systemd/system/iptables-load.service sudo chmod +x /etc/systemd/system/iptables-load.service sudo systemctl daemon-reload sudo systemctl start iptables-load.service sudo systemctl enable iptables-load.service fi fi } configure_ufw() { [ $offline -eq 1 ] && return [ "$(uname)" = "Darwin" ] && return ! command_exists ufw && return if sudo ufw status | grep -q "Status: inactive"; then return fi # 如果 ufw 没有被脚本初始化过 if ! sudo ufw status verbose | grep -q "Initialized by lazy"; then if confirm_action "要配置 ufw 吗?" "N"; then # 默认拒绝所有入站连接 sudo ufw default deny incoming sudo ufw default allow outgoing # 允许常用端口 sudo ufw allow ssh comment 'SSH (Initialized by lazy)' sudo ufw allow http sudo ufw allow https sudo ufw allow 2263/tcp comment 'SSH' sudo ufw allow 9443/tcp comment 'gost-proxy' sudo ufw allow 6330/tcp comment 'node-exporter' fi fi } configure_zsh_prefix() { [ -f ~/.zsh_user ] || return if confirm_action "要修改 zsh 的 prefix 吗?" "N"; then read -p "zsh prefix: " new_prefix if [ "$(uname)" = "Darwin" ]; then # macOS sed -i '' "1s/.*/HOST=\"$new_prefix\"/" ~/.zsh_user else # Linux sed -i "1s/.*/HOST=\"$new_prefix\"/" ~/.zsh_user fi fi } configure_hostname() { if confirm_action "要修改 hostname 吗?" "N"; then read -p "hostname: " new_hostname echo $new_hostname | sudo tee /etc/hostname >/dev/null fi } configure_timedate() { [ "$(uname)" = "Darwin" ] && return [[ $(timedatectl | grep "Time zone" | awk '{print $3}') == "Asia/Shanghai" ]] && return if confirm_action "要修改 时区 吗?" "N"; then sudo timedatectl set-timezone Asia/Shanghai fi } configure_bootinfo() { [ -d /etc/update-motd.d/disable ] && return [ "$(uname)" = "Darwin" ] && return if confirm_action "要修改 启动信息 吗?" "Y"; then sudo mkdir /etc/update-motd.d/disable sudo mv /etc/update-motd.d/10-help-text /etc/update-motd.d/disable/ sudo mv /etc/update-motd.d/50-motd-news /etc/update-motd.d/disable/ # sudo mv /etc/update-motd.d/88-esm-announce /etc/update-motd.d/disable/ if [ -d /usr/lib/python3/dist-packages/landscape/sysinfo ]; then sudo sed -i 's/"Network"/"Network_Simple"/g' /usr/lib/python3/dist-packages/landscape/sysinfo/deployment.py sudo cp $scriptdir/files/sysinfo_network_simple.py /usr/lib/python3/dist-packages/landscape/sysinfo/network_simple.py fi fi } configure_oomkiller() { [ -f /etc/default/earlyoom ] && return [ $offline -eq 1 ] && return [ "$(uname)" = "Darwin" ] && return if confirm_action "要启用 earlyoom 吗?" "Y"; then sudo apt-get install earlyoom -y sudo cp $scriptdir/files/earlyoom.conf /etc/default/earlyoom sudo systemctl restart earlyoom fi } configure_proxychains() { [ -f /etc/proxychains4.conf ] && return [ $offline -eq 1 ] && return [ "$(uname)" = "Darwin" ] && return if confirm_action "要配置 proxychains 吗?" "N"; then sudo apt-get install proxychains4 -y sudo cp $scriptdir/files/proxychains4.conf /etc/proxychains4.conf fi } configure_node_exporter() { [ -f /usr/local/bin/node_exporter ] && return [ $offline -eq 1 ] && return if confirm_action "要配置 Node Exporter 吗?" "N"; then latest_version=$(curl -s "https://api.github.com/repos/prometheus/node_exporter/releases/latest" | grep -o '"tag_name": ".*"' | cut -d'"' -f4) if [ -z "$latest_version" ]; then latest_version="v1.8.2" fi echo "Latest version of node-exporter is $latest_version" release="node_exporter-${latest_version#v}.$(uname -s)-$(dpkg --print-architecture).tar.gz" wget $github/prometheus/node_exporter/releases/download/$latest_version/$release -O $tempdir/node_exporter.tar.gz tar -xzf $tempdir/node_exporter.tar.gz -C $tempdir node_exporter_dir=$(find $tempdir -type d -name "node_exporter-*") sudo cp $node_exporter_dir/node_exporter /usr/local/bin/node_exporter sudo chmod +x /usr/local/bin/node_exporter rm $tempdir/node_exporter.tar.gz rm $node_exporter_dir -r # Generate a self-signed certificate # openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -keyout node_exporter.key -out node_exporter.crt # -subj "/C=CN/ST=Beijing/L=Beijing/O=nano.ac/CN=localhost" # -addext "subjectAltName=DNS:localhost,DNS:host.docker.internal,DNS:*.nano.ac,DNS:*.c-4.cc" if [ ! -d "/etc/node_exporter" ]; then sudo mkdir -p /etc/node_exporter fi sudo cp $scriptdir/files/node_exporter.yml /etc/node_exporter/config.yml sudo cp $scriptdir/files/node_exporter.crt /etc/node_exporter/cert.crt sudo chmod 644 /etc/node_exporter/cert.crt sudo cp $scriptdir/files/node_exporter.key /etc/node_exporter/cert.key sudo chmod 644 /etc/node_exporter/cert.key # Create a systemd service sudo cp $scriptdir/files/node_exporter.service /etc/systemd/system/node_exporter.service sudo chmod +x /etc/systemd/system/node_exporter.service sudo systemctl daemon-reload sudo systemctl start node_exporter sudo systemctl enable node_exporter fi } configure_nginx_log() { [ $offline -eq 1 ] && return [ "$(uname)" = "Darwin" ] && return ! command_exists nginx && return [ ! -f /etc/logrotate.d/nginx ] && return [ -z "$(grep 'daily' /etc/logrotate.d/nginx)" ] && return if confirm_action "要配置 nginx 日志轮转修改为每周吗?" "N"; then # 修改 /etc/logrotate.d/nginx 文件,替换 daily 为 weekly sudo sed -i 's/daily/weekly/' /etc/logrotate.d/nginx # 重新加载 logrotate 配置 sudo logrotate -f /etc/logrotate.d/nginx fi } # configure_nodejs() { # [ -f /usr/local/bin/node ] && return # [ $offline -eq 1 ] && return # if confirm_action "要安装 nodejs 吗?" "Y"; then # local version="v20.10.0" # local tarname="node-$version-linux-x64" # wget https://nodejs.org/dist/$version/$tarname.tar.xz -O $tempdir/$tarname.tar.xz # tar -xf $tempdir/$tarname.tar.xz -C $tempdir # sudo cp $tempdir/$tarname/bin/node /usr/local/bin/node # sudo cp $tempdir/$tarname/bin/npm /usr/local/bin/npm # rm $tempdir/$tarname.tar.xz # rm $tempdir/$tarname -r # fi # } configure_git_gpg() { ! command_exists git && return [ ! -f ~/.gitconfig ] && return [ -n "$(git config --global user.signingkey)" ] && return if confirm_action "要配置 git 使用 gpg 签名吗?" "N"; then if [ "$(uname)" = "Darwin" ]; then if ! command_exists 7z; then brew install p7zip fi else if ! command_exists 7za; then sudo apt install p7zip-full -y alias 7z=7za fi fi read_password cp $scriptdir/files/git.key.zip $tempdir/git.key.zip 7z x -p$password $tempdir/git.key.zip -o$tempdir > /dev/null 2>&1 rm $tempdir/git.key.zip if [ ! -s $tempdir/git.key ]; then echo "Wrong password!" return fi gpg --import $tempdir/git.key rm $tempdir/git.key git config --global user.signingkey 93686B78EE43A65A\! git config --global commit.gpgSign true fi } # ============================================================ configure_swap() { # Input the swap size read -p "Swap size (MB): " swap_size # Create a virtual memory file sudo dd if=/dev/zero of=/mnt/swap bs=1M count=$swap_size sudo chmod 0600 /mnt/swap sudo mkswap /mnt/swap sudo swapon /mnt/swap # Write auto mount parameters if ! grep -q swap /etc/fstab; then echo "/mnt/swap swap swap defaults 0 0" | sudo tee -a /etc/fstab >/dev/null fi # Set virtual memory usage if ! grep -q swappiness /etc/sysctl.conf; then echo "vm.swappiness = 10" | sudo tee -a /etc/sysctl.conf >/dev/null else # sed -i 's/vm.swappiness = 0/vm.swappiness = 10/' /etc/sysctl.conf sudo sed -i 's/^vm.swappiness.*/vm.swappiness = 10/' /etc/sysctl.conf fi # Make the configuration take effect sudo sysctl -p } # ============================================================ if [ $# -ne 0 ]; then for func in $@; do declare -F configure_$func >/dev/null || continue echo "Configuring $func..." eval "configure_$func" done return fi configure_tuna configure_upgrade configure_install configure_nano configure_vim configure_zsh configure_zsh_prefix configure_tmux # configure_nodejs configure_docker configure_fail2ban configure_iptables configure_ufw # configure_hostname configure_timedate configure_bootinfo configure_oomkiller # configure_swap configure_node_exporter configure_nginx_log