/ opencodehub / scripts / prod-setup.sh
swadhinbiswas feat: implement air-gapped mode, UI fixes, and project management integrations · 7/9/2026
e3bd4a1
162 lines · 6.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/bin/bash
# OpenCodeHub Production Setup Script
# ====================================
# Generates secrets, validates config, and starts the production stack.
#
# Usage:
#   bash scripts/prod-setup.sh              # Interactive setup
#   bash scripts/prod-setup.sh --auto       # Non-interactive (CI/CD)
#   bash scripts/prod-setup.sh --start      # Setup + start
set -euo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

ENV_FILE=".env"
AUTO_MODE=false
START_AFTER=false

for arg in "$@"; do
  case $arg in
    --auto) AUTO_MODE=true ;;
    --start) START_AFTER=true ;;
  esac
done

echo -e "${GREEN}╔══════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║   OpenCodeHub Production Setup            ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════╝${NC}"
echo ""

# ── 1. Generate secrets if .env doesn't exist ────────────────
if [ ! -f "$ENV_FILE" ]; then
  echo -e "${YELLOW}No .env found. Generating from .env.example...${NC}"
  cp .env.example .env

  # Generate all required secrets
  JWT_SECRET=$(openssl rand -base64 32)
  SESSION_SECRET=$(openssl rand -base64 32)
  INTERNAL_HOOK_SECRET=$(openssl rand -hex 32)
  CRON_SECRET=$(openssl rand -hex 32)
  AI_CONFIG_ENCRYPTION_KEY=$(openssl rand -hex 32)
  WORKFLOW_SECRET_ENCRYPTION_KEY=$(openssl rand -hex 32)
  RUNNER_SECRET=$(openssl rand -hex 32)
  POSTGRES_PASSWORD=$(openssl rand -base64 24 | tr -d '=' | tr '/+' '_-')
  REDIS_PASSWORD=$(openssl rand -base64 32 | tr -d '=' | tr '/+' '_-')

  # Replace placeholder values in .env
  sed -i "s|JWT_SECRET=.*|JWT_SECRET=$JWT_SECRET|" "$ENV_FILE"
  sed -i "s|SESSION_SECRET=.*|SESSION_SECRET=$SESSION_SECRET|" "$ENV_FILE"
  sed -i "s|INTERNAL_HOOK_SECRET=.*|INTERNAL_HOOK_SECRET=$INTERNAL_HOOK_SECRET|" "$ENV_FILE"
  sed -i "s|CRON_SECRET=.*|CRON_SECRET=$CRON_SECRET|" "$ENV_FILE"
  sed -i "s|AI_CONFIG_ENCRYPTION_KEY=.*|AI_CONFIG_ENCRYPTION_KEY=$AI_CONFIG_ENCRYPTION_KEY|" "$ENV_FILE"
  sed -i "s|WORKFLOW_SECRET_ENCRYPTION_KEY=.*|WORKFLOW_SECRET_ENCRYPTION_KEY=$WORKFLOW_SECRET_ENCRYPTION_KEY|" "$ENV_FILE"
  sed -i "s|RUNNER_SECRET=.*|RUNNER_SECRET=$RUNNER_SECRET|" "$ENV_FILE"
  sed -i "s|POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$POSTGRES_PASSWORD|" "$ENV_FILE"
  sed -i "s|REDIS_PASSWORD=.*|REDIS_PASSWORD=$REDIS_PASSWORD|" "$ENV_FILE"

  # Generate backup encryption key
  BACKUP_KEY=$(openssl rand -hex 32)
  sed -i "s|BACKUP_ENCRYPTION_KEY=.*|BACKUP_ENCRYPTION_KEY=$BACKUP_KEY|" "$ENV_FILE"

  echo -e "${GREEN}✓ Secrets generated and written to .env${NC}"
else
  echo -e "${GREEN}.env already exists, using existing config${NC}"
fi

# ── 2. Validate required variables ───────────────────────────
echo ""
echo "Validating configuration..."

REQUIRED_VARS=(
  "JWT_SECRET"
  "INTERNAL_HOOK_SECRET"
  "CRON_SECRET"
  "AI_CONFIG_ENCRYPTION_KEY"
  "WORKFLOW_SECRET_ENCRYPTION_KEY"
  "RUNNER_SECRET"
  "POSTGRES_PASSWORD"
  "REDIS_PASSWORD"
)

MISSING=0
for var in "${REQUIRED_VARS[@]}"; do
  value=$(grep "^${var}=" "$ENV_FILE" 2>/dev/null | cut -d'=' -f2-)
  if [ -z "$value" ] || echo "$value" | grep -q "change-this\|^$\|Set "; then
    echo -e "${RED}✗ $var is not set or still has default value${NC}"
    MISSING=1
  else
    echo -e "${GREEN}✓ $var${NC}"
  fi
done

if [ "$MISSING" -eq 1 ]; then
  echo ""
  echo -e "${RED}Some secrets are missing. Run without --auto to fix interactively.${NC}"
  if [ "$AUTO_MODE" = false ]; then
    echo "Edit .env and re-run this script."
  fi
  exit 1
fi

# ── 3. Validate SITE_URL ─────────────────────────────────────
SITE_URL=$(grep "^SITE_URL=" "$ENV_FILE" 2>/dev/null | cut -d'=' -f2-)
if echo "$SITE_URL" | grep -q "localhost\|127.0.0.1"; then
  echo -e "${YELLOW}⚠ SITE_URL is set to localhost — change to your public domain for production${NC}"
  if [ "$AUTO_MODE" = false ]; then
    read -p "Enter your production domain (e.g., https://git.example.com): " NEW_URL
    if [ -n "$NEW_URL" ]; then
      sed -i "s|SITE_URL=.*|SITE_URL=$NEW_URL|" "$ENV_FILE"
      sed -i "s|SERVER_URL=.*|SERVER_URL=$NEW_URL|" "$ENV_FILE"
      sed -i "s|ALLOWED_ORIGINS=.*|ALLOWED_ORIGINS=$NEW_URL|" "$ENV_FILE"
      echo -e "${GREEN}✓ SITE_URL updated to $NEW_URL${NC}"
    fi
  fi
fi

# ── 4. Check Docker ──────────────────────────────────────────
echo ""
if ! command -v docker &> /dev/null; then
  echo -e "${RED}Docker is not installed. Please install Docker first.${NC}"
  exit 1
fi

if ! docker compose version &> /dev/null; then
  echo -e "${RED}Docker Compose V2 is not available.${NC}"
  exit 1
fi

echo -e "${GREEN}✓ Docker $(docker --version | awk '{print $3}')${NC}"
echo -e "${GREEN}✓ Docker Compose $(docker compose version | awk '{print $4}')${NC}"

# ── 5. Print summary ─────────────────────────────────────────
echo ""
echo -e "${GREEN}Configuration summary:${NC}"
echo "  App:           http://localhost:4321 (internal)"
echo "  SSH Git:       ssh://git@localhost:2222"
echo "  Database:      PostgreSQL (internal)"
echo "  Redis:         (internal, password-protected)"
echo "  Metrics:       http://localhost:4321/api/metrics (internal)"
echo ""
echo -e "${YELLOW}To start with Caddy reverse proxy (recommended for production):${NC}"
echo "  docker compose --profile production up -d"
echo ""
echo -e "${YELLOW}To start without Caddy (development/testing):${NC}"
echo "  docker compose up -d"
echo ""
echo -e "${YELLOW}To include CI runner:${NC}"
echo "  docker compose --profile production --profile with-runner up -d"
echo ""

# ── 6. Start if requested ────────────────────────────────────
if [ "$START_AFTER" = true ]; then
  echo "Starting production stack..."
  docker compose --profile production up -d
  echo ""
  echo -e "${GREEN}OpenCodeHub is starting. Check status with:${NC}"
  echo "  docker compose ps"
  echo "  docker compose logs -f app"
fi