#!/usr/bin/env bash set -Eeuo pipefail DEPLOY_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" cd "$DEPLOY_ROOT" fail() { printf 'ERROR: %s\n' "$*" >&2 exit 1 } read_env_setting() { local key="$1" local value value="$( sed -n "s/^[[:space:]]*${key}[[:space:]]*=[[:space:]]*//p" .env | tail -n 1 )" value="${value#"${value%%[![:space:]]*}"}" value="${value%"${value##*[![:space:]]}"}" value="${value#\"}" value="${value%\"}" value="${value#\'}" value="${value%\'}" printf '%s' "$value" } require_env() { [[ -f .env ]] || fail "copy .env.example to .env and configure it first" BROKER_DOMAIN="$(read_env_setting BROKER_DOMAIN)" GITEA_DOMAIN="$(read_env_setting GITEA_DOMAIN)" LETSENCRYPT_EMAIL="$(read_env_setting LETSENCRYPT_EMAIL)" SSL_MODE="$(read_env_setting SSL_MODE)" SSL_MODE="${SSL_MODE:-letsencrypt}" SSL_CERTIFICATE_DIR="$(read_env_setting SSL_CERTIFICATE_DIR)" SSL_CERTIFICATE_FILE="$(read_env_setting SSL_CERTIFICATE_FILE)" SSL_CERTIFICATE_KEY_FILE="$(read_env_setting SSL_CERTIFICATE_KEY_FILE)" SSL_CERTIFICATE_FILE="${SSL_CERTIFICATE_FILE:-fullchain.pem}" SSL_CERTIFICATE_KEY_FILE="${SSL_CERTIFICATE_KEY_FILE:-privkey.pem}" : "${BROKER_DOMAIN:?BROKER_DOMAIN is required}" : "${GITEA_DOMAIN:?GITEA_DOMAIN is required}" case "$SSL_MODE" in letsencrypt) : "${LETSENCRYPT_EMAIL:?LETSENCRYPT_EMAIL is required for SSL_MODE=letsencrypt}" SSL_CERTIFICATE_DIR="${SSL_CERTIFICATE_DIR:-./config/letsencrypt/live/${BROKER_DOMAIN}}" ;; custom) SSL_CERTIFICATE_DIR="${SSL_CERTIFICATE_DIR:-./config/ssl}" [[ -f "${SSL_CERTIFICATE_DIR}/${SSL_CERTIFICATE_FILE}" ]] || fail "custom certificate was not found at ${SSL_CERTIFICATE_DIR}/${SSL_CERTIFICATE_FILE}" [[ -f "${SSL_CERTIFICATE_DIR}/${SSL_CERTIFICATE_KEY_FILE}" ]] || fail "custom certificate key was not found at ${SSL_CERTIFICATE_DIR}/${SSL_CERTIFICATE_KEY_FILE}" ;; *) fail "SSL_MODE must be letsencrypt or custom" ;; esac export SSL_CERTIFICATE_DIR SSL_CERTIFICATE_FILE SSL_CERTIFICATE_KEY_FILE } prepare() { mkdir -p \ config/broker \ config/gitea/data \ config/gitea/config \ config/letsencrypt \ config/ssl \ config/certbot-webroot \ config/backups chmod 700 config/broker config/gitea/data config/gitea/config config/backups if [[ "$(id -u)" == 0 ]]; then chown -R 1000:1000 config/broker config/gitea fi docker network inspect tapm-edge >/dev/null 2>&1 || docker network create tapm-edge >/dev/null } case "${1:-}" in prepare) require_env prepare ;; bootstrap) require_env prepare docker compose up -d gitea nginx if [[ "$SSL_MODE" == "letsencrypt" ]]; then docker compose --profile tools run --rm certbot certonly \ --webroot --webroot-path /var/www/certbot \ --non-interactive --agree-tos \ --email "$LETSENCRYPT_EMAIL" \ --cert-name "$BROKER_DOMAIN" \ -d "$BROKER_DOMAIN" -d "$GITEA_DOMAIN" fi docker compose -f compose.yaml -f compose.tls.yaml up -d nginx ;; start) require_env prepare docker compose -f compose.yaml -f compose.tls.yaml up -d --build ;; start-direct) require_env prepare docker compose \ -f compose.yaml \ -f compose.tls.yaml \ -f compose.direct.yaml \ up -d --build ;; create-admin) require_env command -v openssl >/dev/null 2>&1 || fail "openssl is required to generate the temporary password" printf 'Gitea administrator username [taiadmin]: ' read -r admin_username admin_username="${admin_username:-taiadmin}" printf 'Gitea administrator email: ' read -r admin_email [[ -n "$admin_email" ]] || fail "an administrator email is required" temporary_password="$(openssl rand -base64 24)" docker compose exec -T gitea gitea admin user create \ --admin \ --username "$admin_username" \ --email "$admin_email" \ --password "$temporary_password" \ --must-change-password printf '\nGitea administrator created.\n' printf 'Username: %s\n' "$admin_username" printf 'Temporary password: %s\n' "$temporary_password" printf 'Sign in at https://%s/ and change the password immediately.\n' \ "$GITEA_DOMAIN" ;; renew) require_env [[ "$SSL_MODE" == "letsencrypt" ]] || fail "automatic renewal is only available with SSL_MODE=letsencrypt" docker compose --profile tools run --rm certbot renew --quiet docker compose -f compose.yaml -f compose.tls.yaml exec nginx nginx -s reload ;; backup) require_env prepare stamp="$(date -u +%Y%m%dT%H%M%SZ)" destination="config/backups/${stamp}" mkdir -p "$destination" docker compose stop broker docker compose stop gitea cp -a config/broker "$destination/" cp -a config/gitea "$destination/" docker compose -f compose.yaml -f compose.tls.yaml start gitea broker printf 'Backup created at %s\n' "$destination" ;; status) docker compose -f compose.yaml -f compose.tls.yaml ps ;; *) printf 'Usage: %s {prepare|bootstrap|start|start-direct|create-admin|renew|backup|status}\n' "$0" exit 2 ;; esac