#!/usr/bin/env bash # Author : Allan Christensen # First Created : 25082022 (DD-MM-YYYY) # Description : Installs multiple isolated Gitea instances on Ubuntu 24.04 # License : MIT License (see LICENSE file for details) # # Are we root # if [[ $(id -u) -ne 0 ]]; then printf "\nMust be root or use sudo.\n\n" ; exit 1 ; fi # # Port 3000 must be temporarily free for the Gitea web installer # giteaport=3000 if ss -tuln | grep -q ":${giteaport}\b"; then printf "\nPort %s appears to be in use.\n" "$giteaport" listener=$(ss -tulpn 2>/dev/null | awk '/:3000\b/ && /LISTEN/ {print $7}' | sed 's/users:(("//; s/",.*//') if [[ "$listener" == gitea* ]]; then printf "Detected a running Gitea-related process: %s\n" "$listener" printf "It looks like another Gitea multi-instance installation has not yet completed.\n" printf "Please finish its web installer and run its postinstall script before continuing.\n\n" elif [[ -n "$listener" ]]; then printf "Process using port 3000 : %s\n" "$listener" printf "This port is required temporarily by the Gitea web installer.\n" printf "Please stop or reconfigure that application before running this installer.\n\n" else printf "Port 3000 is in use by an unknown process.\n" printf "Please ensure it is free before running this installer.\n\n" fi exit 1 fi # # Define variables and functions # fallbackversion=$( -p [options]\n\n" printf -- "Options:\n" printf -- " -a Optional admin username $socketusage\n" printf -- " -m Optional admin password $socketusage\n" printf -- " -h | -help | --help Show this help screen\n\n" printf -- "Examples:\n" printf -- " sudo ./giteainstall -n git1.example.com -p gitea1dbpwd\n" printf -- " sudo ./giteainstall -n git2.example.com -p gitea2dbpwd -m rootpwd\n" printf -- " sudo ./giteainstall -n git3.example.com -p gitea3dbpwd -a admin -m adminpwd\n\n" } serviceno () { printf "\n%s is not running cannot continue...\n\n" "$service"; } servicedead () { status=$(systemctl is-active "$service"); if [[ "$status" != "active" ]]; then serviceno ; exit ; fi ; } inputcheck () { [[ -z "$hostname" ]] && { usage ; printf "\nError! Hostname empty.\n\n" ; exit 1 ; } ; [[ -z "$dbpass" ]] && { usage ; printf "\nError! Database password empty.\n\n" ; exit 1 ; } ; } # # If Nginx and MariaDB are not running then die # service="mariadb" ; servicedead ; service="nginx" ; servicedead # # Check MariaDB authentication method (socket or not) # if mysql -u root -e ";" 2>/dev/null; then socket="SOCKET DETECTED — no need for -a or -m" ; socketusage="SOCKET DETECTED — these flags are not needed" ; socketauth="yes" else socket="NO SOCKET DETECTED — you must use -a and -m" ; socketusage="NO SOCKET DETECTED — these flags are required" ; socketauth="no" ; fi clear # # Check for the latest Gitea version # version=$(curl -s "https://dl.gitea.com/gitea/version.json" | grep -oP '"version"\s*:\s*"\K[^"]+') if [[ -z "$version" ]]; then printf "Could not determine latest version. Falling back to version %s\n\n" "$fallbackversion" ; version="$fallbackversion" ; fi printf "\nUsing Gitea version: %s\n" "$version" # # Configure command line options (safe for set -u) # firstarg="${1:-}" if [[ "$firstarg" == "-help" || "$firstarg" == "--help" ]]; then usage ; exit 0 ; fi if [[ $# -eq 0 || ! "$firstarg" =~ ^- ]]; then usage ; exit 1 ; fi while getopts "n:p:m:a:h" option; do case "$option" in n) hostname=$(echo "$OPTARG" | tr '[:upper:]' '[:lower:]');; p) dbpass="$OPTARG";; m) mariadbpwd="$OPTARG";; a) mariadbadmin="$OPTARG";; h) usage ; exit 0 ;; \?) printf "Type sudo %s -h for help\n" "$0" ; exit 1 ;; esac done inputcheck "$hostname" "$dbpass" # # Check for existing Nginx host file with same domain # hostcheck=$(grep -r --exclude="giteainstall" --exclude="postinstall" --exclude="README.md" "$hostname" /etc/nginx/ 2>/dev/null || true) if [[ -n "$hostcheck" ]]; then printf "\nFound existing configuration mentioning %s — aborting to avoid collision.\n\n" "$hostname" ; exit 1 ; fi # # Create Gitea counter logic # mkdir -p /var/lib/gitea user_counter_file="/var/lib/gitea/giteausercount" [ ! -f "$user_counter_file" ] && printf "0\n" > "$user_counter_file" current_user=$(cat "$user_counter_file") ; next_user=$((current_user + 1)) giteauser="gitea$next_user" ; gitea_db="${giteauser}${giteadb}" ; giteaport=$((3000 + next_user)) printf "%s\n" "$next_user" > "$user_counter_file" # # Download gitea if not already present # if [[ ! -f $gitealocation ]]; then wget --no-verbose "https://dl.gitea.com/gitea/${version}/gitea-${version}-linux-amd64" -O "$gitealocation" || { printf "\nDownload failed. Check your network connection or version string.\n\n" ; exit 1 ; } chmod 755 "$gitealocation" fi # # Clone nginx-snippets; if nginx-snippets exists then just pull latest changes # nginxsnippets="/etc/nginx/nginx-snippets" ; repo="https://git.x-files.dk/webserver/nginx-snippets.git" if [[ -d "$nginxsnippets/.git" ]]; then git -C "$nginxsnippets" pull --quiet ; else git clone --quiet "$repo" "$nginxsnippets" ; fi # # Escape special characters in the password for MySQL # safe_dbpass=$(printf "%s" "$dbpass" | sed "s/'/''/g") ; mariadbadmin="${mariadbadmin:-root}" printf "\nChecking MariaDB access method...\n" if [[ "$socketauth" == "yes" ]]; then dbmethod="socket" ; printf "Socket authentication detected (root)\n" elif [[ -n "${mariadbpwd:-}" && -n "${mariadbadmin:-}" ]]; then dbmethod="admin" ; printf "Using admin user authentication (%s)\n" "$mariadbadmin" else printf "\nERROR: No valid MariaDB authentication method found.\n" ; exit 1 ; fi # # Create Gitea database # case "$dbmethod" in socket) mysql -u root < /etc/systemd/system/$giteauser.service < "$postscript" <> /etc/\$giteauser/app.ini <<'INNER_EOF' [ui.admin] USER_PAGING_NUM = 50 REPO_PAGING_NUM = 50 NOTICE_PAGING_NUM = 25 ORG_PAGING_NUM = 25 [ui.user] USER_PAGING_NUM = 50 REPO_PAGING_NUM = 50 NOTICE_PAGING_NUM = 25 ORG_PAGING_NUM = 25 [ui] THEMES = gitea,arc-green EXPLORE_PAGING_DEFAULT_SORT = alphabetically [other] SHOW_FOOTER_POWERED_BY = false SHOW_FOOTER_VERSION = false SHOW_FOOTER_TEMPLATE_LOAD_TIME = false ENABLE_FEED = false INNER_EOF # Update Nginx proxy to final assigned port sed -i "s/127\\.0\\.0\\.1:3000/127.0.0.1:\$giteaport/" /etc/nginx/conf.d/\$hostname.conf printf "\\nUpdated Nginx proxy for %s to port %s\\n" "\$hostname" "\$giteaport" systemctl reload nginx ; systemctl restart \$giteauser EOF chmod 755 "$postscript" # # Gitea postinstall notice # postnotice=$(cat <