diff --git a/docker-compose.yaml b/docker-compose.yaml index b645d295..610bc41f 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -31,11 +31,11 @@ services: ports: - "6379:6379" command: > - --requirepass redissecret + --requirepass ${REDIS_PASSWORD:-redissecret} volumes: - redis_data:/data healthcheck: - test: ["CMD", "redis-cli", "-a", "redissecret", "ping"] + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-redissecret}", "ping"] interval: 3s timeout: 10s retries: 10 @@ -143,7 +143,7 @@ services: DATABASE_URL: "postgresql+asyncpg://postgres:${POSTGRES_PASSWORD:-postgres}@postgres:5432/postgres" # Redis configuration (using containerized redis) - REDIS_URL: "redis://:redissecret@redis:6379" + REDIS_URL: "redis://:${REDIS_PASSWORD:-redissecret}@redis:6379" # Storage configuration - using local MinIO ENABLE_AWS_S3: "false" diff --git a/docs/deployment/docker.mdx b/docs/deployment/docker.mdx index 04934e50..d5727108 100644 --- a/docs/deployment/docker.mdx +++ b/docs/deployment/docker.mdx @@ -56,7 +56,8 @@ Invoke-WebRequest -OutFile start_docker.ps1 https://raw.githubusercontent.com/do This setup: - Downloads the latest docker-compose.yaml -- Creates `OSS_JWT_SECRET` in `.env` if one does not already exist +- Creates `OSS_JWT_SECRET` and `REDIS_PASSWORD` in `.env` if they do not already exist +- Creates `POSTGRES_PASSWORD` for brand-new `.env` files; existing installs keep their original Postgres password - Prompts before running Docker Compose - Starts all required services including PostgreSQL, Redis, MinIO, API, and UI - Pulls the latest images automatically diff --git a/docs/deployment/update.mdx b/docs/deployment/update.mdx index b2897788..b8eb414b 100644 --- a/docs/deployment/update.mdx +++ b/docs/deployment/update.mdx @@ -18,13 +18,12 @@ Dograh publishes two images — `dograh-api` and `dograh-ui` — to both contain - **GitHub Container Registry** — [github.com/orgs/dograh-hq/packages](https://github.com/orgs/dograh-hq/packages) - **Docker Hub** — [hub.docker.com/u/dograhai](https://hub.docker.com/u/dograhai) -Each release is published under two kinds of tags. Note the formats differ between GitHub releases and the Docker image tags — `update_remote.sh` understands both and normalizes for you. +Each release is published under release tags. Note the formats differ between GitHub releases and Docker image tags — `update_remote.sh` understands both and normalizes for you. | Where | Tag format | Example | When to use | |-------|-----------|---------|-------------| -| GitHub release tag | `dograh-vX.Y.Z` | `dograh-v1.28.0` | What you see at [github.com/dograh-hq/dograh/releases](https://github.com/dograh-hq/dograh/releases) | +| GitHub release tag | `dograh-vX.Y.Z` | `dograh-v1.28.0` | Use when copying the version from a GitHub release | | Docker image tag (semver) | `X.Y.Z` | `1.28.0` | Stable, recommended for production | -| Docker image tag (SHA) | short SHA | `a1b2c3d` | Bleeding edge — any commit merged to `main` | | Docker image tag (`latest`) | `latest` | `latest` | Tracks the most recent release tag | @@ -49,7 +48,7 @@ curl -o update_remote.sh https://raw.githubusercontent.com/dograh-hq/dograh/main bash update_remote.sh ``` -You'll be prompted for the target version, defaulting to the most recent release. Accepted forms: bare semver (`1.28.0`), v-prefixed (`v1.28.0`), the full GitHub tag (`dograh-v1.28.0`), or `main` for bleeding edge — the script normalizes them. Non-interactive callers can set it via environment variable and skip the confirmation prompt: +You'll be prompted for the target version, defaulting to the most recent release. Accepted forms: bare semver (`1.28.0`), v-prefixed (`v1.28.0`), the full GitHub tag (`dograh-v1.28.0`), or `main` to refresh deployment files from the default branch — the script normalizes them. Non-interactive callers can set it via environment variable and skip the confirmation prompt: ```bash TARGET_VERSION=1.28.0 DOGRAH_UPDATE_YES=1 bash update_remote.sh @@ -67,15 +66,17 @@ The script overwrites `docker-compose.yaml` and the remote helper bundle (`remot ## Local deployment -For local Docker installs (the [Quick Start](/deployment/docker#quick-start) flow or `setup_local.sh` / `setup_local.ps1`), there are no host-side config files to refresh — stop the stack, then use the startup script to preserve `OSS_JWT_SECRET` and pull new images: +For local Docker installs (the [Quick Start](/deployment/docker#quick-start) flow or `setup_local.sh` / `setup_local.ps1`), refresh `docker-compose.yaml` and the startup script, stop the stack, then run the startup script. The script preserves existing `.env` secrets, creates `REDIS_PASSWORD` if it is missing, and only creates `POSTGRES_PASSWORD` for brand-new `.env` files so existing Postgres volumes keep using their original password: ```bash macOS/Linux +curl -o docker-compose.yaml https://raw.githubusercontent.com/dograh-hq/dograh/main/docker-compose.yaml curl -o start_docker.sh https://raw.githubusercontent.com/dograh-hq/dograh/main/scripts/start_docker.sh && chmod +x start_docker.sh docker compose down ./start_docker.sh ``` ```powershell Windows +Invoke-WebRequest -OutFile docker-compose.yaml https://raw.githubusercontent.com/dograh-hq/dograh/main/docker-compose.yaml Invoke-WebRequest -OutFile start_docker.ps1 https://raw.githubusercontent.com/dograh-hq/dograh/main/scripts/start_docker.ps1 docker compose down .\start_docker.ps1 @@ -144,6 +145,6 @@ sudo docker compose --profile remote up -d If you update the `pipecat` submodule, you **must** run `git submodule update --init --recursive` before rebuilding, or the Docker build will not pick up `pipecat` changes. -If you maintain a fork with local customizations on top of upstream, merging conflicts in `docker-compose.yaml`, `remote_up.sh`, `scripts/run_dograh_init.sh`, `deploy/templates/*`, or `setup_remote.sh` is up to you — resolve them as you would any other git merge. Leave `OSS_JWT_SECRET` and `TURN_SECRET` in `.env` unchanged across updates to preserve sessions and WebRTC auth. +If you maintain a fork with local customizations on top of upstream, merging conflicts in `docker-compose.yaml`, `remote_up.sh`, `scripts/run_dograh_init.sh`, `deploy/templates/*`, or `setup_remote.sh` is up to you — resolve them as you would any other git merge. Leave `OSS_JWT_SECRET`, `TURN_SECRET`, `POSTGRES_PASSWORD`, and `REDIS_PASSWORD` in `.env` unchanged across updates to preserve sessions, WebRTC auth, and service credentials. The same migration warning above applies: rolling back across a schema change can leave the DB in a state the older API can't read. diff --git a/scripts/setup_local.ps1 b/scripts/setup_local.ps1 index d8b99137..ae594b72 100644 --- a/scripts/setup_local.ps1 +++ b/scripts/setup_local.ps1 @@ -244,6 +244,7 @@ if ($UseCoturn) { Write-Info "[2/$TotalSteps] Creating environment file..." $ossJwtSecret = New-HexSecret 32 $postgresPassword = New-HexSecret 32 +$redisPassword = New-HexSecret 32 $envLines = @( '# Container registry for Dograh images' @@ -257,6 +258,11 @@ $envLines = @( '# is baked into the postgres data volume when it is first created.' "POSTGRES_PASSWORD=$postgresPassword" '' + "# Redis password. Used by the redis container's --requirepass and the API's" + '# REDIS_URL. This can be rotated by updating .env and recreating the redis' + '# container.' + "REDIS_PASSWORD=$redisPassword" + '' '# Telemetry (set to false to disable)' "ENABLE_TELEMETRY=$EnableTelemetry" '' diff --git a/scripts/setup_local.sh b/scripts/setup_local.sh index e94fb60c..4c74b316 100755 --- a/scripts/setup_local.sh +++ b/scripts/setup_local.sh @@ -151,6 +151,7 @@ ENV_STEP=$TOTAL_STEPS echo -e "${BLUE}[$ENV_STEP/$TOTAL_STEPS] Creating environment file...${NC}" OSS_JWT_SECRET=$(openssl rand -hex 32) POSTGRES_PASSWORD=$(openssl rand -hex 32) +REDIS_PASSWORD=$(openssl rand -hex 32) cat > .env << ENV_EOF # Container registry for Dograh images @@ -164,6 +165,11 @@ OSS_JWT_SECRET=$OSS_JWT_SECRET # baked into the postgres data volume when it is first created. POSTGRES_PASSWORD=$POSTGRES_PASSWORD +# Redis password. Used by the redis container's --requirepass and the API's +# REDIS_URL. This can be rotated by updating .env and recreating the redis +# container. +REDIS_PASSWORD=$REDIS_PASSWORD + # Telemetry (set to false to disable) ENABLE_TELEMETRY=$ENABLE_TELEMETRY diff --git a/scripts/setup_remote.sh b/scripts/setup_remote.sh index f1a0d149..b1a75d50 100755 --- a/scripts/setup_remote.sh +++ b/scripts/setup_remote.sh @@ -252,6 +252,7 @@ echo -e "${GREEN}✓ SSL certificates generated${NC}" echo -e "${BLUE}[4/$TOTAL] Creating environment file...${NC}" OSS_JWT_SECRET=$(openssl rand -hex 32) POSTGRES_PASSWORD=$(openssl rand -hex 32) +REDIS_PASSWORD=$(openssl rand -hex 32) cat > .env << ENV_EOF # Remote deployments run with production signaling and HTTPS defaults @@ -282,6 +283,11 @@ OSS_JWT_SECRET=$OSS_JWT_SECRET # baked into the postgres data volume when it is first created. POSTGRES_PASSWORD=$POSTGRES_PASSWORD +# Redis password. Used by the redis container's --requirepass and the API's +# REDIS_URL. Unlike postgres, this is not baked into a volume and can be +# rotated by updating .env and recreating the redis container. +REDIS_PASSWORD=$REDIS_PASSWORD + # Telemetry (set to false to disable) ENABLE_TELEMETRY=$ENABLE_TELEMETRY diff --git a/scripts/start_docker.ps1 b/scripts/start_docker.ps1 index e039bb9a..8fff43ba 100644 --- a/scripts/start_docker.ps1 +++ b/scripts/start_docker.ps1 @@ -65,6 +65,8 @@ if (-not (Test-Path 'docker-compose.yaml')) { exit 1 } +$envFileExisted = Test-Path $EnvFile + $existingSecret = Get-DotEnvValue -Path $EnvFile -Key 'OSS_JWT_SECRET' if ([string]::IsNullOrEmpty($existingSecret)) { Set-DotEnvValue -Path $EnvFile -Key 'OSS_JWT_SECRET' -Value (New-HexSecret) @@ -73,6 +75,26 @@ if ([string]::IsNullOrEmpty($existingSecret)) { Write-Host "OSS_JWT_SECRET is already set in $EnvFile." } +$existingPostgresPassword = Get-DotEnvValue -Path $EnvFile -Key 'POSTGRES_PASSWORD' +if ([string]::IsNullOrEmpty($existingPostgresPassword)) { + if (-not $envFileExisted) { + Set-DotEnvValue -Path $EnvFile -Key 'POSTGRES_PASSWORD' -Value (New-HexSecret) + Write-Host "Created POSTGRES_PASSWORD in $EnvFile." + } else { + Write-Host "POSTGRES_PASSWORD is not set in $EnvFile; keeping the docker-compose fallback for existing local data volumes." + } +} else { + Write-Host "POSTGRES_PASSWORD is already set in $EnvFile." +} + +$existingRedisPassword = Get-DotEnvValue -Path $EnvFile -Key 'REDIS_PASSWORD' +if ([string]::IsNullOrEmpty($existingRedisPassword)) { + Set-DotEnvValue -Path $EnvFile -Key 'REDIS_PASSWORD' -Value (New-HexSecret) + Write-Host "Created REDIS_PASSWORD in $EnvFile." +} else { + Write-Host "REDIS_PASSWORD is already set in $EnvFile." +} + Write-Host '' Write-Host "Docker registry: $Registry" Write-Host "Telemetry enabled: $EnableTelemetry" diff --git a/scripts/start_docker.sh b/scripts/start_docker.sh index 9cb96750..199f3b8d 100755 --- a/scripts/start_docker.sh +++ b/scripts/start_docker.sh @@ -23,7 +23,7 @@ generate_secret() { return fi - fail "Could not generate OSS_JWT_SECRET. Install python3 or openssl, or set OSS_JWT_SECRET manually in .env." + fail "Could not generate a secret. Install python3 or openssl, or set secrets manually in .env." } dotenv_value() { @@ -76,6 +76,11 @@ set_dotenv_value() { [[ -f docker-compose.yaml ]] || fail "docker-compose.yaml not found. Download it first, then re-run this script." +env_file_existed=false +if [[ -f "$ENV_FILE" ]]; then + env_file_existed=true +fi + existing_secret="$(dotenv_value OSS_JWT_SECRET || true)" if [[ -z "$existing_secret" ]]; then set_dotenv_value OSS_JWT_SECRET "$(generate_secret)" @@ -84,6 +89,26 @@ else echo "OSS_JWT_SECRET is already set in $ENV_FILE." fi +existing_postgres_password="$(dotenv_value POSTGRES_PASSWORD || true)" +if [[ -z "$existing_postgres_password" ]]; then + if [[ "$env_file_existed" == "false" ]]; then + set_dotenv_value POSTGRES_PASSWORD "$(generate_secret)" + echo "Created POSTGRES_PASSWORD in $ENV_FILE." + else + echo "POSTGRES_PASSWORD is not set in $ENV_FILE; keeping the docker-compose fallback for existing local data volumes." + fi +else + echo "POSTGRES_PASSWORD is already set in $ENV_FILE." +fi + +existing_redis_password="$(dotenv_value REDIS_PASSWORD || true)" +if [[ -z "$existing_redis_password" ]]; then + set_dotenv_value REDIS_PASSWORD "$(generate_secret)" + echo "Created REDIS_PASSWORD in $ENV_FILE." +else + echo "REDIS_PASSWORD is already set in $ENV_FILE." +fi + echo "" echo "Docker registry: $REGISTRY" echo "Telemetry enabled: $ENABLE_TELEMETRY" diff --git a/scripts/update_remote.sh b/scripts/update_remote.sh index 1dc75e71..922f1f80 100755 --- a/scripts/update_remote.sh +++ b/scripts/update_remote.sh @@ -31,6 +31,22 @@ trap cleanup EXIT REPO="dograh-hq/dograh" TIMESTAMP=$(date +%Y%m%d-%H%M%S) +generate_secret() { + if command -v python3 >/dev/null 2>&1 && python3 -c 'import secrets; print(secrets.token_hex(32))'; then + return + fi + + if command -v openssl >/dev/null 2>&1 && openssl rand -hex 32; then + return + fi + + if [[ -r /dev/urandom ]] && command -v od >/dev/null 2>&1 && command -v tr >/dev/null 2>&1 && od -An -N32 -tx1 /dev/urandom | tr -d ' \n'; then + return + fi + + dograh_fail "Could not generate REDIS_PASSWORD. Install python3 or openssl, or set REDIS_PASSWORD manually in .env." +} + echo -e "${BLUE}" echo "╔══════════════════════════════════════════════════════════════╗" echo "║ Dograh Remote Update ║" @@ -96,7 +112,7 @@ if [[ -z "$TARGET_VERSION" ]]; then if [[ -t 0 ]]; then echo "" echo -e "${YELLOW}Target version. Accepted forms: bare semver (1.28.0), v-prefixed (v1.28.0),${NC}" - echo -e "${YELLOW}full git tag (dograh-v1.28.0), or 'main' for bleeding edge.${NC}" + echo -e "${YELLOW}full git tag (dograh-v1.28.0), or 'main' for the latest deployment files.${NC}" read -p "[$LATEST_TAG]: " TARGET_VERSION TARGET_VERSION="${TARGET_VERSION:-$LATEST_TAG}" else @@ -219,6 +235,10 @@ fi echo -e "${BLUE}[3/3] Synchronizing environment and validating init-based remote config...${NC}" dograh_set_env_key .env FASTAPI_WORKERS "$FASTAPI_WORKERS" +if [[ -z "${REDIS_PASSWORD:-}" ]]; then + dograh_set_env_key .env REDIS_PASSWORD "$(generate_secret)" + dograh_success "✓ REDIS_PASSWORD created in .env" +fi dograh_prepare_remote_install "$(pwd)" docker compose config -q dograh_success "✓ Remote init configuration validated"