commit c6d620b08a6dcacc612603d87f86bdf9c9744edc Author: Phan Hữu Tài Date: Fri May 22 21:07:57 2026 +0700 Add setup_ubuntu_env.sh diff --git a/setup_ubuntu_env.sh b/setup_ubuntu_env.sh new file mode 100644 index 0000000..39cbad4 --- /dev/null +++ b/setup_ubuntu_env.sh @@ -0,0 +1,606 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# ----------------------------------------------------------------------------- +# Standalone Ubuntu deployment bootstrap +# Download this single file to the server, make it executable, then run it. +# Configuration +# ----------------------------------------------------------------------------- + +if [[ -t 1 ]]; then + COLOR_INFO='\033[1;34m' + COLOR_WARN='\033[1;33m' + COLOR_ERROR='\033[1;31m' + COLOR_RESET='\033[0m' +else + COLOR_INFO='' + COLOR_WARN='' + COLOR_ERROR='' + COLOR_RESET='' +fi + +BASE_PACKAGES=( + apt-transport-https + build-essential + ca-certificates + curl + git + gnupg + jq + lsb-release + software-properties-common + unzip + wget + zip +) + +INSTALL_DOCKER=false +INSTALL_NODE=false +INSTALL_AWS=false +INSTALL_AZURE=false +INSTALL_ANSIBLE=true +INSTALL_INFISICAL=true +INSTALL_PYTHON=false +INSTALL_PHP=false +INSTALL_COMPOSER=false +INSTALL_JAVA=false +INSTALL_MAVEN=false +INSTALL_GO=false +INSTALL_COREPACK=false +INSTALL_NGINX=false +INSTALL_UFW=false +INSTALL_FAIL2BAN=false +INSTALL_CERTBOT=false +INSTALL_PM2=false +DEPLOY_NODE=false +DEPLOY_PYTHON=false +DEPLOY_DOCKER=false +DEPLOY_LARAVEL=false +DEPLOY_SPRINGBOOT=false +DEPLOY_NEXT=false +DEPLOY_NUXT=false +DEPLOY_GO_FIBER=false +UPDATE_ONLY=false + +# ----------------------------------------------------------------------------- +# Logging and helpers +# ----------------------------------------------------------------------------- + +log() { + printf '%b[INFO]%b %s\n' "${COLOR_INFO}" "${COLOR_RESET}" "$1" +} + +warn() { + printf '%b[WARN]%b %s\n' "${COLOR_WARN}" "${COLOR_RESET}" "$1" +} + +die() { + printf '%b[ERROR]%b %s\n' "${COLOR_ERROR}" "${COLOR_RESET}" "$1" >&2 + exit 1 +} + +install_apt_packages() { + DEBIAN_FRONTEND=noninteractive apt-get install -y "$@" +} + +enable_service() { + systemctl enable --now "$1" +} + +run_when_enabled() { + local enabled="$1" + local handler="$2" + + if [[ "${enabled}" == true ]]; then + "${handler}" + fi +} + +usage() { + cat <<'EOF' +Usage: ./setup_ubuntu_tools.sh [options] + +This is a standalone bootstrap script. +You only need this single file on the Ubuntu server. + +Default behavior: + - Update apt cache + - Upgrade installed packages + - Install common base tools for Ubuntu servers + - Install Ansible and Infisical CLI + +Options: + --deploy-laravel Install a ready-to-deploy Laravel server stack + --deploy-springboot Install a ready-to-deploy Spring Boot server stack + --deploy-next Install a ready-to-deploy Next.js server stack + --deploy-nuxt Install a ready-to-deploy Nuxt server stack + --deploy-go-fiber Install a ready-to-deploy Go Fiber server stack + --deploy-node Install a ready-to-deploy Node.js server stack + --deploy-python Install a ready-to-deploy Python server stack + --deploy-docker Install a ready-to-deploy Docker server stack + --docker Install Docker Engine and Docker Compose plugin + --node Install Node.js LTS + --aws Install AWS CLI v2 + --azure Install Azure CLI + --no-ansible Skip default Ansible installation + --no-infisical Skip default Infisical CLI installation + --python Install Python 3, venv and pip + --php Install PHP runtime for Laravel-style apps + --composer Install Composer + --java Install OpenJDK 21 + --maven Install Maven + --go Install Go toolchain from Ubuntu repo + --corepack Enable pnpm and yarn via Corepack + --nginx Install and enable Nginx + --ufw Install and configure UFW for SSH, HTTP, HTTPS + --fail2ban Install and enable Fail2ban + --certbot Install Certbot for Let's Encrypt + --pm2 Install PM2 globally with npm + --update-only Only run apt update and upgrade + -h, --help Show this help + +Examples: + wget https://your-server/setup_ubuntu_tools.sh + chmod +x setup_ubuntu_tools.sh + sudo ./setup_ubuntu_tools.sh --deploy-laravel + ./setup_ubuntu_tools.sh --deploy-laravel + ./setup_ubuntu_tools.sh --deploy-springboot + ./setup_ubuntu_tools.sh --deploy-next + ./setup_ubuntu_tools.sh --deploy-go-fiber + ./setup_ubuntu_tools.sh --deploy-node + ./setup_ubuntu_tools.sh --deploy-python + ./setup_ubuntu_tools.sh --deploy-docker + ./setup_ubuntu_tools.sh --docker --node --python --nginx + sudo ./setup_ubuntu_tools.sh --docker --aws --azure +EOF +} + +require_root() { + if [[ "${EUID}" -ne 0 ]]; then + die "Please run this script with sudo or as root." + fi +} + +require_ubuntu() { + if [[ ! -r /etc/os-release ]]; then + die "Cannot detect operating system." + fi + + . /etc/os-release + + if [[ "${ID:-}" != "ubuntu" ]]; then + die "This script currently supports Ubuntu only." + fi +} + +# ----------------------------------------------------------------------------- +# Installers +# ----------------------------------------------------------------------------- + +system_update() { + log "Updating apt package index" + apt-get update -y + + log "Upgrading installed packages" + DEBIAN_FRONTEND=noninteractive apt-get upgrade -y +} + +install_base_tooling() { + log "Installing base packages" + install_apt_packages "${BASE_PACKAGES[@]}" +} + +install_runtime_python() { + log "Installing Python tools" + install_apt_packages python3 python3-pip python3-venv +} + +install_runtime_php() { + log "Installing PHP runtime and common Laravel extensions" + install_apt_packages \ + php-cli \ + php-common \ + php-curl \ + php-fpm \ + php-mbstring \ + php-mysql \ + php-xml \ + php-zip \ + php-bcmath \ + php-intl +} + +install_runtime_composer() { + log "Installing Composer" + install_apt_packages composer +} + +install_runtime_java() { + log "Installing OpenJDK 21" + install_apt_packages openjdk-21-jdk +} + +install_runtime_maven() { + log "Installing Maven" + install_apt_packages maven +} + +install_runtime_go() { + log "Installing Go toolchain" + install_apt_packages golang-go +} + +install_service_nginx() { + log "Installing Nginx" + install_apt_packages nginx + enable_service nginx +} + +install_service_ufw() { + log "Installing and configuring UFW" + install_apt_packages ufw + ufw allow OpenSSH + ufw allow 'Nginx Full' + ufw --force enable +} + +install_service_fail2ban() { + log "Installing Fail2ban" + install_apt_packages fail2ban + enable_service fail2ban +} + +install_service_certbot() { + log "Installing Certbot" + install_apt_packages certbot python3-certbot-nginx +} + +install_runtime_node() { + log "Installing Node.js LTS" + curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - + install_apt_packages nodejs +} + +install_runtime_corepack() { + if ! command -v corepack >/dev/null 2>&1; then + die "Corepack requires Node.js. Re-run with --node, --deploy-next, or --deploy-nuxt." + fi + + log "Enabling corepack and preparing pnpm/yarn" + corepack enable + corepack prepare pnpm@latest --activate + corepack prepare yarn@stable --activate +} + +install_runtime_pm2() { + if ! command -v npm >/dev/null 2>&1; then + die "PM2 requires Node.js. Re-run with --node or --deploy-node." + fi + + log "Installing PM2" + npm install -g pm2 +} + +install_cli_aws() { + local tmp_dir + tmp_dir="$(mktemp -d)" + + log "Installing AWS CLI v2" + curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "${tmp_dir}/awscliv2.zip" + unzip -q "${tmp_dir}/awscliv2.zip" -d "${tmp_dir}" + "${tmp_dir}/aws/install" --update + rm -rf "${tmp_dir}" +} + +install_cli_azure() { + log "Installing Azure CLI" + curl -fsSL https://aka.ms/InstallAzureCLIDeb | bash +} + +install_cli_ansible() { + log "Installing Ansible" + install_apt_packages ansible +} + +install_cli_infisical() { + log "Installing Infisical CLI" + curl -fsSL https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh | bash + apt-get update -y + install_apt_packages infisical +} + +install_runtime_docker() { + log "Setting up Docker repository" + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc + chmod a+r /etc/apt/keyrings/docker.asc + + . /etc/os-release + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu ${VERSION_CODENAME} stable" \ + > /etc/apt/sources.list.d/docker.list + + apt-get update -y + + log "Installing Docker Engine" + install_apt_packages \ + docker-ce \ + docker-ce-cli \ + containerd.io \ + docker-buildx-plugin \ + docker-compose-plugin + + if [[ -n "${SUDO_USER:-}" ]]; then + usermod -aG docker "${SUDO_USER}" || warn "Could not add ${SUDO_USER} to docker group" + warn "Log out and back in to use Docker without sudo." + fi +} + +prepare_deploy_directories() { + log "Creating common deployment directories" + install -d -m 0755 /var/www/apps + install -d -m 0755 /var/log/apps +} + +enable_common_web_profile() { + INSTALL_NGINX=true + INSTALL_UFW=true + INSTALL_FAIL2BAN=true + INSTALL_CERTBOT=true +} + +enable_profile_laravel() { + INSTALL_PHP=true + INSTALL_COMPOSER=true + enable_common_web_profile +} + +enable_profile_springboot() { + INSTALL_JAVA=true + INSTALL_MAVEN=true + enable_common_web_profile +} + +enable_profile_next() { + INSTALL_NODE=true + INSTALL_COREPACK=true + INSTALL_PM2=true + enable_common_web_profile +} + +enable_profile_nuxt() { + enable_profile_next +} + +enable_profile_go_fiber() { + INSTALL_GO=true + enable_common_web_profile +} + +enable_profile_node() { + INSTALL_NODE=true + INSTALL_PM2=true + enable_common_web_profile +} + +enable_profile_python() { + INSTALL_PYTHON=true + enable_common_web_profile +} + +enable_profile_docker() { + INSTALL_DOCKER=true + enable_common_web_profile +} + +# ----------------------------------------------------------------------------- +# Profiles +# ----------------------------------------------------------------------------- + +apply_deploy_profiles() { + if [[ "${DEPLOY_NODE}" == true ]]; then + enable_profile_node + fi + + if [[ "${DEPLOY_PYTHON}" == true ]]; then + enable_profile_python + fi + + if [[ "${DEPLOY_DOCKER}" == true ]]; then + enable_profile_docker + fi + + if [[ "${DEPLOY_LARAVEL}" == true ]]; then + enable_profile_laravel + fi + + if [[ "${DEPLOY_SPRINGBOOT}" == true ]]; then + enable_profile_springboot + fi + + if [[ "${DEPLOY_NEXT}" == true ]]; then + enable_profile_next + fi + + if [[ "${DEPLOY_NUXT}" == true ]]; then + enable_profile_nuxt + fi + + if [[ "${DEPLOY_GO_FIBER}" == true ]]; then + enable_profile_go_fiber + fi +} + +# ----------------------------------------------------------------------------- +# Output +# ----------------------------------------------------------------------------- + +show_versions() { + log "Installed versions" + command -v git >/dev/null 2>&1 && git --version || true + command -v curl >/dev/null 2>&1 && curl --version | head -n 1 || true + command -v jq >/dev/null 2>&1 && jq --version || true + command -v python3 >/dev/null 2>&1 && python3 --version || true + command -v php >/dev/null 2>&1 && php --version | head -n 1 || true + command -v composer >/dev/null 2>&1 && composer --version || true + command -v java >/dev/null 2>&1 && java --version | head -n 1 || true + command -v mvn >/dev/null 2>&1 && mvn --version | head -n 1 || true + command -v go >/dev/null 2>&1 && go version || true + command -v node >/dev/null 2>&1 && node --version || true + command -v npm >/dev/null 2>&1 && npm --version || true + command -v pnpm >/dev/null 2>&1 && pnpm --version || true + command -v yarn >/dev/null 2>&1 && yarn --version || true + command -v pm2 >/dev/null 2>&1 && pm2 --version || true + command -v ansible >/dev/null 2>&1 && ansible --version | head -n 1 || true + command -v infisical >/dev/null 2>&1 && infisical --version || true + command -v aws >/dev/null 2>&1 && aws --version || true + command -v az >/dev/null 2>&1 && az version | jq -r '.["azure-cli"]' || true + command -v docker >/dev/null 2>&1 && docker --version || true + command -v nginx >/dev/null 2>&1 && nginx -v 2>&1 || true + command -v certbot >/dev/null 2>&1 && certbot --version || true +} + +# ----------------------------------------------------------------------------- +# CLI +# ----------------------------------------------------------------------------- + +parse_args() { + while [[ $# -gt 0 ]]; do + case "$1" in + --deploy-laravel) + DEPLOY_LARAVEL=true + ;; + --deploy-springboot) + DEPLOY_SPRINGBOOT=true + ;; + --deploy-next) + DEPLOY_NEXT=true + ;; + --deploy-nuxt) + DEPLOY_NUXT=true + ;; + --deploy-go-fiber) + DEPLOY_GO_FIBER=true + ;; + --deploy-node) + DEPLOY_NODE=true + ;; + --deploy-python) + DEPLOY_PYTHON=true + ;; + --deploy-docker) + DEPLOY_DOCKER=true + ;; + --docker) + INSTALL_DOCKER=true + ;; + --node) + INSTALL_NODE=true + ;; + --aws) + INSTALL_AWS=true + ;; + --azure) + INSTALL_AZURE=true + ;; + --no-ansible) + INSTALL_ANSIBLE=false + ;; + --no-infisical) + INSTALL_INFISICAL=false + ;; + --python) + INSTALL_PYTHON=true + ;; + --php) + INSTALL_PHP=true + ;; + --composer) + INSTALL_COMPOSER=true + ;; + --java) + INSTALL_JAVA=true + ;; + --maven) + INSTALL_MAVEN=true + ;; + --go) + INSTALL_GO=true + ;; + --corepack) + INSTALL_COREPACK=true + ;; + --nginx) + INSTALL_NGINX=true + ;; + --ufw) + INSTALL_UFW=true + ;; + --fail2ban) + INSTALL_FAIL2BAN=true + ;; + --certbot) + INSTALL_CERTBOT=true + ;; + --pm2) + INSTALL_PM2=true + ;; + --update-only) + UPDATE_ONLY=true + ;; + -h|--help) + usage + exit 0 + ;; + *) + die "Unknown option: $1" + ;; + esac + shift + done +} + +# ----------------------------------------------------------------------------- +# Main flow +# ----------------------------------------------------------------------------- + +main() { + parse_args "$@" + require_root + require_ubuntu + apply_deploy_profiles + system_update + + if [[ "${UPDATE_ONLY}" == true ]]; then + log "Update-only mode complete" + exit 0 + fi + + install_base_tooling + prepare_deploy_directories + + run_when_enabled "${INSTALL_PYTHON}" install_runtime_python + run_when_enabled "${INSTALL_PHP}" install_runtime_php + run_when_enabled "${INSTALL_COMPOSER}" install_runtime_composer + run_when_enabled "${INSTALL_JAVA}" install_runtime_java + run_when_enabled "${INSTALL_MAVEN}" install_runtime_maven + run_when_enabled "${INSTALL_GO}" install_runtime_go + run_when_enabled "${INSTALL_NODE}" install_runtime_node + run_when_enabled "${INSTALL_COREPACK}" install_runtime_corepack + run_when_enabled "${INSTALL_PM2}" install_runtime_pm2 + run_when_enabled "${INSTALL_ANSIBLE}" install_cli_ansible + run_when_enabled "${INSTALL_INFISICAL}" install_cli_infisical + run_when_enabled "${INSTALL_AWS}" install_cli_aws + run_when_enabled "${INSTALL_AZURE}" install_cli_azure + run_when_enabled "${INSTALL_DOCKER}" install_runtime_docker + run_when_enabled "${INSTALL_NGINX}" install_service_nginx + run_when_enabled "${INSTALL_UFW}" install_service_ufw + run_when_enabled "${INSTALL_FAIL2BAN}" install_service_fail2ban + run_when_enabled "${INSTALL_CERTBOT}" install_service_certbot + + show_versions + log "Bootstrap complete" +} + +main "$@" \ No newline at end of file