Files
owain 5e2b220366
Build and push images / build-backend (push) Failing after 2m5s
Build and push images / build-worker (push) Failing after 4s
Build and push images / build-frontend (push) Failing after 4s
Rename fittracker to milevault throughout
2026-06-06 14:12:28 +01:00

210 lines
8.9 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# MileVault installer
# Usage: curl -fsSL https://raw.githubusercontent.com/you/milevault/main/install.sh | bash
# Or: bash install.sh
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
BOLD='\033[1m'
info() { echo -e "${GREEN}${NC} $*"; }
warn() { echo -e "${YELLOW}!${NC} $*"; }
error() { echo -e "${RED}$*${NC}"; exit 1; }
step() { echo -e "\n${CYAN}${BOLD}── $* ──${NC}"; }
echo -e "${BOLD}"
echo " ███████╗██╗████████╗████████╗██████╗ █████╗ ██████╗██╗ ██╗███████╗██████╗ "
echo " ██╔════╝██║╚══██╔══╝╚══██╔══╝██╔══██╗██╔══██╗██╔════╝██║ ██╔╝██╔════╝██╔══██╗"
echo " █████╗ ██║ ██║ ██║ ██████╔╝███████║██║ █████╔╝ █████╗ ██████╔╝"
echo " ██╔══╝ ██║ ██║ ██║ ██╔══██╗██╔══██║██║ ██╔═██╗ ██╔══╝ ██╔══██╗"
echo " ██║ ██║ ██║ ██║ ██║ ██║██║ ██║╚██████╗██║ ██╗███████╗██║ ██║"
echo " ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝"
echo -e "${NC}"
echo " Self-hosted fitness tracking — Garmin & Strava"
echo ""
# ── Preflight checks ──────────────────────────────────────────────────────────
step "Checking requirements"
command -v docker >/dev/null 2>&1 || error "Docker is not installed. Install from https://docs.docker.com/get-docker/"
info "Docker found: $(docker --version | head -1)"
# Check docker compose (v2 plugin or v1 standalone)
if docker compose version >/dev/null 2>&1; then
COMPOSE_CMD="docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
COMPOSE_CMD="docker-compose"
else
error "Docker Compose not found. Install from https://docs.docker.com/compose/install/"
fi
info "Docker Compose found: $($COMPOSE_CMD version | head -1)"
# Check Docker daemon is running
docker info >/dev/null 2>&1 || error "Docker daemon is not running. Start Docker and retry."
info "Docker daemon is running"
# ── Install directory ─────────────────────────────────────────────────────────
step "Setting up install directory"
INSTALL_DIR="${FITTRACKER_DIR:-$HOME/milevault}"
if [ -d "$INSTALL_DIR" ] && [ "$(ls -A "$INSTALL_DIR" 2>/dev/null)" ]; then
warn "Directory $INSTALL_DIR already exists."
read -rp " Continue and update existing install? [y/N] " confirm
[[ "$confirm" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 0; }
fi
mkdir -p "$INSTALL_DIR"
cd "$INSTALL_DIR"
info "Install directory: $INSTALL_DIR"
# ── Download project files ────────────────────────────────────────────────────
step "Downloading MileVault"
# If we're already inside the repo (files exist), skip download
if [ -f "docker-compose.yml" ]; then
info "Project files already present — skipping download"
else
# Try git first, fall back to curl
if command -v git >/dev/null 2>&1; then
git clone --depth 1 https://github.com/yourusername/milevault.git . 2>/dev/null || {
warn "Git clone failed — copying bundled files instead"
}
fi
# Fallback: if running this script from inside a downloaded zip, the files are next to it
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ "$SCRIPT_DIR" != "$INSTALL_DIR" ] && [ -f "$SCRIPT_DIR/docker-compose.yml" ]; then
cp -r "$SCRIPT_DIR"/. "$INSTALL_DIR/"
info "Copied project files from $SCRIPT_DIR"
fi
fi
[ -f "docker-compose.yml" ] || error "docker-compose.yml not found. Place install.sh inside the project directory."
info "Project files ready"
# ── Generate .env ─────────────────────────────────────────────────────────────
step "Configuring environment"
if [ -f ".env" ]; then
warn ".env already exists — skipping generation (delete it to regenerate)"
else
# Generate secure random values
if command -v openssl >/dev/null 2>&1; then
SECRET_KEY=$(openssl rand -hex 32)
DB_PASSWORD=$(openssl rand -base64 18 | tr -d '/+=')
REDIS_PASSWORD=$(openssl rand -base64 12 | tr -d '/+=')
ADMIN_PASSWORD=$(openssl rand -base64 12 | tr -d '/+=')
else
# Fallback if openssl not available
SECRET_KEY=$(cat /dev/urandom | tr -dc 'a-f0-9' | head -c 64)
DB_PASSWORD=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 18)
REDIS_PASSWORD=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 12)
ADMIN_PASSWORD=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 12)
fi
ADMIN_USERNAME="${FITTRACKER_ADMIN:-admin}"
PORT="${FITTRACKER_PORT:-80}"
cat > .env << ENV
# MileVault configuration — generated $(date)
# Edit this file to change settings, then run: docker compose up -d
# Admin login
ADMIN_USERNAME=${ADMIN_USERNAME}
ADMIN_PASSWORD=${ADMIN_PASSWORD}
# Secrets (auto-generated — do not share)
SECRET_KEY=${SECRET_KEY}
DB_PASSWORD=${DB_PASSWORD}
DB_USER=milevault
REDIS_PASSWORD=${REDIS_PASSWORD}
# Server
HTTP_PORT=${PORT}
ENVIRONMENT=production
# Optional: Mapbox token for satellite map tiles (free at mapbox.com)
VITE_MAPBOX_TOKEN=
# Optional: PocketID passkey authentication
# POCKETID_ISSUER=https://your-pocketid.example.com
# POCKETID_CLIENT_ID=milevault
# POCKETID_CLIENT_SECRET=
ENV
info ".env created with secure random secrets"
# Save credentials for display at end
SHOW_CREDS=true
fi
source .env
# ── Build & start ─────────────────────────────────────────────────────────────
step "Building and starting containers"
echo " This takes 35 minutes on first run (building images)..."
echo ""
$COMPOSE_CMD up -d --build
# ── Wait for healthy ──────────────────────────────────────────────────────────
step "Waiting for services to be ready"
TIMEOUT=120
ELAPSED=0
printf " Waiting"
while ! docker inspect milevault_backend 2>/dev/null | grep -q '"healthy"' ; do
if [ $ELAPSED -ge $TIMEOUT ]; then
echo ""
warn "Backend taking longer than expected. Check logs: docker compose logs backend"
break
fi
printf "."
sleep 3
ELAPSED=$((ELAPSED + 3))
done
echo ""
info "All services are up"
# ── Done ──────────────────────────────────────────────────────────────────────
PORT="${HTTP_PORT:-80}"
URL="http://localhost${PORT:+:${PORT}}"
[[ "$PORT" == "80" ]] && URL="http://localhost"
echo ""
echo -e "${GREEN}${BOLD}╔══════════════════════════════════════════╗${NC}"
echo -e "${GREEN}${BOLD}║ MileVault is ready! ║${NC}"
echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════╝${NC}"
echo ""
echo -e " 🌐 Open: ${CYAN}${URL}${NC}"
echo -e " 👤 Username: ${BOLD}${ADMIN_USERNAME:-admin}${NC}"
if [ "${SHOW_CREDS:-false}" = "true" ]; then
echo -e " 🔑 Password: ${BOLD}${ADMIN_PASSWORD}${NC}"
echo ""
warn "Save this password — it won't be shown again."
warn "It's also stored in: ${INSTALL_DIR}/.env"
else
echo -e " 🔑 Password: (see ${INSTALL_DIR}/.env — ADMIN_PASSWORD)"
fi
echo ""
echo " Useful commands:"
echo " docker compose logs -f # View live logs"
echo " docker compose logs backend # Backend logs only"
echo " docker compose down # Stop everything"
echo " docker compose up -d # Start again"
echo " docker compose pull && docker compose up -d --build # Update"
echo ""
echo " Import your data:"
echo " Go to ${URL} → Import → upload your Garmin export ZIP or Strava ZIP"
echo ""