Ctrl K
ComunidadGuías…

selfhost/env.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/bin/sh
# Sourced by entrypoint.sh in both modes, before anything touches the databases.
# Runs under dash: no [[ ]], no arrays, no ${v//a/b}.

fail() {
    echo "betterlytics: $*" >&2
    exit 1
}

check_version() {
    [ "$APP_VERSION" = "dev" ] && return 0
    [ "$SKIP_VERSION_CHECK" = "true" ] && return 0
    [ "$APP_VERSION" = "$BETTERLYTICS_VERSION" ] && return 0
    echo "Configuration/image version mismatch."
    echo "  betterlytics-selfhost repo: $BETTERLYTICS_VERSION"
    echo "  image:                      $APP_VERSION"
    if [ "$(printf '%s\n%s\n' "$BETTERLYTICS_VERSION" "$APP_VERSION" | sort -V | head -n1)" = "$BETTERLYTICS_VERSION" ]; then
        echo "The repo is older: run \`git pull origin $APP_VERSION\` in betterlytics-selfhost, then \`docker compose up -d --wait\`."
    else
        echo "The image is older: check docker-compose.override.yml for an image override, or run \`docker compose pull\`."
    fi
    exit 1
}

# Tests for non-empty, not for set: compose passes `DOMAIN=` from .env as present but empty.
check_retired_names() {
    if [ -z "$PUBLIC_URL" ]; then
        if [ -n "$DOMAIN$HTTP_SCHEME$FORCE_HTTP_SCHEME" ]; then
            _scheme="https"
            [ "$FORCE_HTTP_SCHEME" = "http" ] && _scheme="http"
            _tls="off"
            [ "$HTTP_SCHEME" = "https" ] && _tls="auto"
            echo "DOMAIN, HTTP_SCHEME and FORCE_HTTP_SCHEME are no longer read. Replace them in .env with:"
            echo "  PUBLIC_URL=${_scheme}://${DOMAIN:-<your domain>}"
            echo "  TLS=${_tls}"
            # A hand-written override may interpolate ${HTTPS_PORT}; without the variable it publishes a random port.
            echo "HTTPS_PORT is no longer read either. If docker-compose.override.yml uses \${HTTPS_PORT}, write 443 there before removing it from .env."
            if [ "$_tls" = "auto" ] && [ "$BL_HTTPS_PUBLISHED" != "true" ]; then
                echo "TLS=auto also needs BL_HTTPS_PUBLISHED=true in the environment of both betterlytics-selfhost and betterlytics-init in docker-compose.override.yml, next to the existing 443 mapping."
            fi
            echo "Then run \`docker compose up -d --wait\` again."
            exit 1
        fi
        fail "PUBLIC_URL is not set. Set it in .env to the address browsers use, for example PUBLIC_URL=https://analytics.example.com."
    fi
    # HTTP_SCHEME=https always meant this container terminates TLS; with TLS off it would start healthy on plain HTTP only.
    if [ "$HTTP_SCHEME" = "https" ] && [ "$TLS" != "auto" ]; then
        echo "HTTP_SCHEME=https is set in .env but TLS is not auto, so Betterlytics would serve only plain HTTP."
        echo "HTTP_SCHEME is no longer read. Pick one in .env:"
        echo "  Built-in HTTPS (this container gets the certificate): set TLS=auto and remove HTTP_SCHEME."
        echo "  Your own reverse proxy in front terminates HTTPS: remove HTTP_SCHEME and leave TLS=off."
        echo "Then run \`docker compose up -d --wait\` again."
        exit 1
    fi
    if [ -n "$DOMAIN$HTTP_SCHEME$FORCE_HTTP_SCHEME" ]; then
        echo "WARNING: DOMAIN, HTTP_SCHEME and FORCE_HTTP_SCHEME in .env are ignored; PUBLIC_URL and TLS are used. Remove them." >&2
    fi
}

# Normalises PUBLIC_URL, defaults TLS, and sets BL_PUBLIC_HOST to host or host:port.
resolve_public_url() {
    # Never echo the value here: it may hold credentials.
    case "$PUBLIC_URL" in
        *@*) fail "PUBLIC_URL must not contain credentials. Use only scheme, host and optional port, for example https://analytics.example.com." ;;
    esac
    _url=$(printf '%s' "$PUBLIC_URL" | tr 'A-Z' 'a-z')
    case "$_url" in
        http://*)
            _scheme="http"
            _default_port="80"
            ;;
        https://*)
            _scheme="https"
            _default_port="443"
            ;;
        *) fail "PUBLIC_URL must start with http:// or https:// (got '$PUBLIC_URL')." ;;
    esac
    BL_PUBLIC_HOST="${_url#*://}"
    BL_PUBLIC_HOST="${BL_PUBLIC_HOST%/}"
    case "$BL_PUBLIC_HOST" in
        ''|:*|*/*|*\?*|*\#*)
            fail "PUBLIC_URL must be only scheme, host and optional port, for example https://analytics.example.com (got '$PUBLIC_URL')." ;;
    esac
    case "$BL_PUBLIC_HOST" in
        \[*) ;;
        *:*)
            _port="${BL_PUBLIC_HOST##*:}"
            case "$_port" in
                ''|*[!0-9]*|0*|??????*) fail "The port in PUBLIC_URL must be a number between 1 and 65535 without leading zeros (got '$PUBLIC_URL')." ;;
            esac
            # Browsers leave the default port out of Origin, so logins would never match.
            [ "$_port" != "$_default_port" ] || fail "Leave the default port out of PUBLIC_URL: use ${_scheme}://${BL_PUBLIC_HOST%:*}."
            ;;
    esac

    TLS="${TLS:-off}"
    case "$TLS" in
        auto|off) ;;
        *) fail "TLS must be auto or off (got '$TLS')." ;;
    esac

    if [ "$TLS" = "auto" ]; then
        [ "$_scheme" = "https" ] || fail "TLS=auto needs an https:// PUBLIC_URL. For plain HTTP set TLS=off."
        case "$BL_PUBLIC_HOST" in
            *:*|localhost|*.localhost)
                fail "TLS=auto needs a public hostname without a port in PUBLIC_URL (got '$BL_PUBLIC_HOST'). Behind your own proxy or on a custom port set TLS=off." ;;
        esac
        if printf '%s' "$BL_PUBLIC_HOST" | grep -qE '^[0-9]{1,3}(\.[0-9]{1,3}){3}$'; then
            fail "TLS=auto cannot get a certificate for an IP address. Use a hostname, or set TLS=off."
        fi
        # Let's Encrypt HTTP-01 reaches the container only through host port 80, browsers only through host port 443.
        # The image cannot see host port mappings; compose passes BIND_ADDRESS and the setup.sh override sets the marker.
        _missing=""
        [ "$HTTP_PORT" = "80" ] || _missing="${_missing}
  HTTP_PORT=80 in .env (currently ${HTTP_PORT:-unset})."
        case $(printf '%s' "$BIND_ADDRESS" | tr 'A-Z' 'a-z') in
            ''|127.*|::1|'[::1]'|localhost)
                _missing="${_missing}
  BIND_ADDRESS=0.0.0.0 in .env, or this server's public or port-forwarded IP (currently ${BIND_ADDRESS:-unset}). Empty or loopback publishes port 80 only to this machine, so Let's Encrypt cannot reach it." ;;
        esac
        [ "$BL_HTTPS_PUBLISHED" = "true" ] || _missing="${_missing}
  Port 443 published in docker-compose.override.yml: betterlytics-selfhost needs ports \"\${BIND_ADDRESS}:443:443\" (if not already there), and both betterlytics-selfhost and betterlytics-init need BL_HTTPS_PUBLISHED=true in environment."
        if [ -n "$_missing" ]; then
            echo "TLS=auto needs ports 80 and 443 of this server published to Betterlytics. Missing:${_missing}"
            echo "setup.sh 'Standalone' writes all of this. Or set TLS=off behind your own reverse proxy."
            exit 1
        fi
    fi

    PUBLIC_URL="${_scheme}://${BL_PUBLIC_HOST}"
    export PUBLIC_URL TLS
}

# Empty counts as unset (an empty `X=` line in .env arrives as ""); an explicit false is kept.
apply_selfhost_defaults() {
    export ENABLE_UPTIME_MONITORING="${ENABLE_UPTIME_MONITORING:-true}"
    export ENABLE_PUBLIC_STATUS_PAGES="${ENABLE_PUBLIC_STATUS_PAGES:-true}"
    export SESSION_REPLAYS_ENABLED="${SESSION_REPLAYS_ENABLED:-true}"
    export ALLOW_PRIVATE_TARGETS="${ALLOW_PRIVATE_TARGETS:-true}"
    export BACKGROUND_JOBS_ENABLED="${BACKGROUND_JOBS_ENABLED:-true}"
    export LOG_LEVEL="${LOG_LEVEL:-info}"
    export WORKER_CLICKHOUSE_WRITE_USER="${WORKER_CLICKHOUSE_WRITE_USER:-worker}"
    export CLICKHOUSE_URL="${CLICKHOUSE_URL:-http://clickhouse:8123}"

    # Always assigned: login origin, links and tracking origin must be the same address.
    export PUBLIC_BASE_URL="$PUBLIC_URL"
    export AUTH_URL="$PUBLIC_URL"
    export PUBLIC_ANALYTICS_BASE_URL="$PUBLIC_URL"
    export PUBLIC_TRACKING_SERVER_ENDPOINT="$PUBLIC_URL"
}