feat(scripts): generate REDIS_PASSWORD on setup, plumb through compose (#458)

* feat(scripts): generate REDIS_PASSWORD on setup, plumb through compose

Per the discussion on #453, this takes the recommended path of extending
the setup scripts rather than introducing a parallel compose file.

  - scripts/setup_remote.sh now generates REDIS_PASSWORD alongside
    OSS_JWT_SECRET and POSTGRES_PASSWORD and writes it to the rendered
    .env (with a short comment noting it can be rotated, unlike the
    postgres password which is baked into the volume on first init).
  - scripts/start_docker.sh now generates REDIS_PASSWORD on first run
    if missing, mirroring the existing OSS_JWT_SECRET pattern (reuses
    generate_secret, which falls back through python3 → openssl →
    /dev/urandom).
  - docker-compose.yaml and docker-compose-local.yaml now interpolate
    ${REDIS_PASSWORD:-redissecret} in the redis --requirepass, the redis
    healthcheck, and the api REDIS_URL.

The :-redissecret fallback preserves backwards compatibility for users
with an existing .env that predates this change — they keep the old
value until they regenerate. New installs (via either script) get a
secure random hex.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Harden local Docker secret setup

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Abhishek Kumar <abhishek@a6k.me>
This commit is contained in:
Manuel Bruña 2026-06-21 04:41:31 -03:00 committed by GitHub
parent ac91019d38
commit 17054e3f26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 99 additions and 12 deletions

View file

@ -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"

View file

@ -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

View file

@ -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 |
<Warning>
@ -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:
<CodeGroup>
```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.
</Warning>
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.

View file

@ -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"
''

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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"

View file

@ -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"