Files
gitea-ubuntu/giteainstall
2025-11-03 17:05:54 +01:00

362 lines
9.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Author : Allan Christensen
# First Created : 12032021 (DD-MM-YYYY)
# Description : Installs Gitea on Ubuntu 24.04
# License : MIT License (see LICENSE file for details)
#
# Are we root
#
if [[ $(id -u) -ne 0 ]]; then echo "" && echo "Must be root or use sudo" && echo "" ; exit ; fi
#
# Check if required services are running or not
#
for svc in nginx mariadb; do systemctl is-active --quiet "$svc" || { printf "\n%s is not running, cannot continue...\n\n" "${svc^}" ; exit 1 ; }; done
#
# 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 — this flag is 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
#
# Define variables and functions
#
fallbackversion=$(<fallback)
#
# Function usage
#
usage() {
printf -- "\ngiteainstall\n\n"
if [[ "$socketauth" == "yes" ]]; then
printf -- "SOCKET DETECTED — no need for -a or -m\n\n"
printf -- "Installs Gitea (single instance) using MariaDB socket authentication.\n\n"
printf -- "Usage:\n"
printf -- " sudo ./giteainstall -n <gitea domain> -p <gitea database password>\n\n"
printf -- "Example:\n"
printf -- " sudo ./giteainstall -n git.example.com -p giteadbpwd\n\n"
else
printf -- "NO SOCKET DETECTED — you must use -a and -m\n\n"
printf -- "Installs Gitea (single instance) using MariaDB admin credentials.\n\n"
printf -- "Usage:\n"
printf -- " sudo ./giteainstall -n <gitea domain> -p <gitea database password> -m <adminpwd> [-a <adminuser>]\n\n"
printf -- "Examples:\n"
printf -- " sudo ./giteainstall -n git.example.com -p giteadbpwd -m rootpwd\n"
printf -- " sudo ./giteainstall -n git.example.com -p giteadbpwd -a admin -m adminpwd\n\n"
fi
printf -- "Options:\n"
printf -- " -h | -help | --help Show this help screen\n\n"
}
#
# Let's go
#
clear
#
# Configure command line options
#
# Check for long or alternate help flags before getopts
if [[ "$1" == "-help" || "$1" == "--help" ]]; then usage ; exit 0 ; fi
# Ensure first argument starts with a dash
if [[ $# -eq 0 || ! $1 =~ ^- ]]; then usage ; exit 1 ; fi
# Parse short options
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;;
\?) echo "Type sudo $0 -h for help"; exit 1;;
esac
done
#
# Parse and validate input
#
if [[ -z "$hostname" || -z "$dbpass" ]]; then
usage
printf "\nERROR: Both -n (domain) and -p (database password) are required.\n\n"
exit 1
fi
# Convert to lowercase (domains are case-insensitive)
hostname=$(echo "$hostname" | tr '[:upper:]' '[:lower:]')
# Disallow leading hyphen
if [[ "$hostname" =~ ^- ]]; then
printf "\nERROR: Domain cannot start with a hyphen.\n"
printf "Example of valid input: git.example.com\n\n"
exit 1
fi
# Disallow spaces, slashes, underscores
if [[ "$hostname" =~ [[:space:]/_] ]]; then
printf "\nERROR: Domain cannot contain spaces, slashes, or underscores.\n\n"
exit 1
fi
# Validate domain format (RFC 1123)
if [[ ! "$hostname" =~ ^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$ ]]; then
printf "\nERROR: Invalid domain format.\n"
printf "Example of valid input: git.example.com\n\n"
exit 1
fi
# Prevent accidental overwrite of existing Nginx config
if [[ -f "/etc/nginx/conf.d/${hostname}.conf" ]]; then
printf "\nERROR: A configuration file already exists for %s.\n" "$hostname"
printf "Refusing to overwrite existing site.\n\n"
exit 1
fi
# Check for existing references in other Nginx configs
hostcheck=$(grep -r --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
# Check for spaces in DB credentials
if [[ "$dbpass" =~ [[:space:]] ]]; then
printf "\nERROR: Database password cannot contain spaces.\n\n"
exit 1
fi
#
# Ensure curl and wget are installed
#
for tool in curl wget; do dpkg -s "$tool" &>/dev/null || apt install -y -qq "$tool" ; done
#
# Check for the latest Gitea version
#
version=$(curl -s https://dl.gitea.com/gitea/version.json | grep -oP '"version"\s*:\s*"\K[^"]+')
#
# Use fallback if version fetch failed
#
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"
#
# Download Gitea
#
wget --no-verbose https://dl.gitea.com/gitea/"$version"/gitea-"$version"-linux-amd64 -O /usr/local/bin/gitea ; chmod 755 /usr/local/bin/gitea
#
# 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")
#
# Determine MariaDB login method
#
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"
printf "Tried socket, root password, and admin credentials.\n\n"
exit 1
fi
#
# Create Gitea database
#
case "$dbmethod" in
socket)
mysql -u root <<EOF
CREATE DATABASE IF NOT EXISTS gitea;
CREATE USER IF NOT EXISTS 'gitea'@'localhost' IDENTIFIED BY '${safe_dbpass//\'/\'\\\'\'}';
GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'localhost';
FLUSH PRIVILEGES;
EOF
;;
admin)
mysql -u "${mariadbadmin}" -p"${mariadbpwd}" <<EOF
CREATE DATABASE IF NOT EXISTS gitea;
CREATE USER IF NOT EXISTS 'gitea'@'localhost' IDENTIFIED BY '${safe_dbpass//\'/\'\\\'\'}';
GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'localhost';
FLUSH PRIVILEGES;
EOF
;;
esac
#
# Create a Gitea Nginx configuration file
#
cp "$nginxsnippets/hostfiles/gitea.80.conf" /etc/nginx/conf.d/"$hostname".conf
sed -i -- "s/DOMAIN/$hostname/g" /etc/nginx/conf.d/"$hostname".conf
#
# Restarting Nginx for changes to take effect
#
systemctl restart nginx
#
# Create Gitea user
#
adduser --system --group --disabled-password --shell /bin/bash --home /home/git --gecos 'Git Version Control' git
#
# Create Gitea standard folders
#
mkdir -p /var/lib/gitea/{custom,data,indexers,public,log}
chown git:git /var/lib/gitea/{data,indexers,log}
chmod 750 /var/lib/gitea/{data,indexers,log}
mkdir /etc/gitea
chown root:git /etc/gitea
chmod 770 /etc/gitea
#
# Create Gitea customization directories
#
mkdir -p /var/lib/gitea/custom/templates
mkdir -p /var/lib/gitea/custom/public/assets/img
#
# Create Gitea systemd file
#
cat > /etc/systemd/system/gitea.service <<'EOF'
[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target
Requires=mariadb.service
[Service]
LimitMEMLOCK=infinity
LimitNOFILE=65535
RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea/
ExecStart=/usr/local/bin/gitea web -c /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
#AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
EOF
#
# Start Gitea services
#
systemctl daemon-reload
systemctl enable gitea
systemctl start gitea
#
# Create postinstall script
#
cat > /tmp/gitea-postinstall <<EOF
#!/usr/bin/env bash
#
# Gitea Postinstall Script
#
if [[ \$(id -u) -ne 0 ]]; then echo "" && echo "Must be root or use sudo" && echo "" ; exit ; fi
cp -Rp /etc/gitea/app.ini /etc/gitea/app.ini.orig
sed -i '/gitea-repositories/a MAX_FILES = 500' /etc/gitea/app.ini
sed -i '/gitea-repositories/a FILE_MAX_SIZE = 200' /etc/gitea/app.ini
sed -i 's/LEVEL = info/LEVEL = warn/' /etc/gitea/app.ini
sed -i 's/MODE = console/MODE = file/' /etc/gitea/app.ini
sed -i 's/DISABLE_SSH = false/DISABLE_SSH = true/' /etc/gitea/app.ini
cat >> /etc/gitea/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
systemctl restart nginx && systemctl restart gitea
rm -f /tmp/gitea-postinstall
EOF
chmod 755 /tmp/gitea-postinstall
#
# Gitea postinstall notice
#
postnotice=$(cat <<EOF
-------------------------------------------------------------------------------------
NEXT STEP: Go to http://$hostname and complete the initial configuration.
-------------------------------------------------------------------------------------
Database User : gitea
Database Name : gitea
Database Password: $dbpass
-------------------------------------------------------------------------------------
IMPORTANT: Once done from a terminal run the following command to finish up
sudo /tmp/gitea-postinstall
-------------------------------------------------------------------------------------
EOF
)
printf '%s\n' "$postnotice"
#
# All done
#
printf "\nAll Done...\n"
#
# End of script
#