auto-deploy.sh only ever worked because someone chmod +x'd it directly on the server after cloning, outside git - a fix that lived nowhere git could see. A `git checkout --` to that file (recovering from an unrelated direct edit) silently restored the tracked 644 mode, breaking the deploy timer with "Permission denied" until caught via journalctl. bootstrap-env.sh had the identical latent bug, just never triggered since it's only ever run manually. Co-Authored-By: Claude Sonnet 5 <[email protected]>
78 lines
3.1 KiB
Bash
Executable File
78 lines
3.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Prepares a real .env for a fresh clone with minimal manual setup:
|
|
# 1. Copies .env.example -> .env if .env doesn't exist yet.
|
|
# 2. Replaces the three "must be a real random secret, no safe shared
|
|
# default" values (JWT_SECRET, API_KEY_ENCRYPTION_SECRET,
|
|
# POSTGRES_PASSWORD) with freshly generated ones, but ONLY if they
|
|
# still equal the known .env.example placeholder or are blank -
|
|
# running this again after you've customized .env is a no-op.
|
|
#
|
|
# Deliberately does NOT touch DATABASE_URL: docker-compose.prod.yml builds
|
|
# it from POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB directly (same as the
|
|
# dev compose file already does with its hardcoded values), so there's
|
|
# nothing to keep in sync by hand here.
|
|
#
|
|
# Deliberately does NOT set ANTHROPIC_API_KEY / BRAVE_SEARCH_API_KEY /
|
|
# NINJAPEAR_API_KEY / USPTO_API_KEY / TURNSTILE_SITE_KEY / TURNSTILE_SECRET -
|
|
# those are meant to be configured after first boot via the app's own
|
|
# Settings page ("Your API keys" / "Server secrets"), not .env. See
|
|
# KNOWN_LIMITATIONS.md.
|
|
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
ENV_FILE=".env"
|
|
ENV_EXAMPLE=".env.example"
|
|
|
|
if [ ! -f "$ENV_FILE" ]; then
|
|
if [ ! -f "$ENV_EXAMPLE" ]; then
|
|
echo "error: $ENV_EXAMPLE not found" >&2
|
|
exit 1
|
|
fi
|
|
cp "$ENV_EXAMPLE" "$ENV_FILE"
|
|
echo "Created $ENV_FILE from $ENV_EXAMPLE"
|
|
fi
|
|
|
|
# $1 = var name, $2 = known placeholder value in .env.example, $3 = generator command
|
|
_replace_if_placeholder() {
|
|
local var_name="$1" placeholder="$2" generator="$3"
|
|
local current
|
|
current=$(grep -E "^${var_name}=" "$ENV_FILE" | head -n1 | cut -d= -f2-)
|
|
|
|
if [ -z "$current" ] || [ "$current" = "$placeholder" ]; then
|
|
local new_value
|
|
new_value=$(eval "$generator")
|
|
# Escape characters that are special to sed's replacement text.
|
|
local escaped
|
|
escaped=$(printf '%s' "$new_value" | sed -e 's/[\/&]/\\&/g')
|
|
sed -i "s/^${var_name}=.*/${var_name}=${escaped}/" "$ENV_FILE"
|
|
echo "Generated a new ${var_name}"
|
|
fi
|
|
}
|
|
|
|
_replace_if_placeholder "JWT_SECRET" "dev-only-change-me-32-characters-minimum" \
|
|
"openssl rand -hex 32"
|
|
|
|
# Fernet requires exactly 32 raw bytes, urlsafe-base64-encoded - plain hex
|
|
# would pass silently until the first encrypt/decrypt call, then crash.
|
|
_replace_if_placeholder "API_KEY_ENCRYPTION_SECRET" "_wYtsm3nJ070987snBFp2eWVI5pyC0H9gGFUb6Cy4cQ=" \
|
|
"openssl rand -base64 32 | tr '+/' '-_'"
|
|
|
|
_replace_if_placeholder "POSTGRES_PASSWORD" "ciagent" \
|
|
"openssl rand -hex 32"
|
|
|
|
cat <<'EOF'
|
|
|
|
Done. Before running this for real, still set manually in .env:
|
|
- APP_ENV=production, AUTH_MODE=jwt (AUTH_MODE=local refuses to start
|
|
when APP_ENV=production - this is an intentional safety check)
|
|
- FRONTEND_URL / NEXT_PUBLIC_API_URL / BACKEND_URL for your real domain
|
|
- TRUSTED_PROXY_IP_HEADER=CF-Connecting-IP once behind Cloudflare
|
|
- RESEND_API_KEY (or SMTP_*) for real security emails - no admin UI for this one
|
|
|
|
Once the app is running, sign in as the admin account and set these from
|
|
the Settings page instead of .env:
|
|
- Your API keys: Anthropic, Brave Search, NinjaPear, USPTO
|
|
- Server secrets: Cloudflare Turnstile site key + secret
|
|
EOF
|