feat: configure deployment for optical-dev.oliver.solutions/amazon-transcreation
- Apache reverse proxy config (replaces nginx — server already runs Apache) - Next.js basePath set to /amazon-transcreation for subpath deployment - Frontend on port 3050 (3000 taken), backend on 8040 - WebSocket URL auto-detects protocol from page location - Deploy script handles Apache config injection into existing vhost - All Docker ports bound to 127.0.0.1 (Apache handles external access) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4a5c1c6dfe
commit
3fe93c2b22
7 changed files with 143 additions and 49 deletions
|
|
@ -25,6 +25,7 @@ STORAGE_ROOT=/storage
|
|||
# LLM Model
|
||||
LLM_MODEL=claude-sonnet-4-6
|
||||
|
||||
# Frontend (empty = same-origin behind nginx)
|
||||
NEXT_PUBLIC_API_URL=
|
||||
# Frontend (set at Docker build time via docker-compose.prod.yml)
|
||||
NEXT_PUBLIC_API_URL=/amazon-transcreation
|
||||
NEXT_PUBLIC_WS_URL=
|
||||
NEXT_PUBLIC_BASE_PATH=/amazon-transcreation
|
||||
|
|
|
|||
44
apache/amazon-transcreation.conf
Normal file
44
apache/amazon-transcreation.conf
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# ============================================================
|
||||
# Amazon Transcreation Platform — Apache Reverse Proxy
|
||||
# ============================================================
|
||||
# Add this inside your existing <VirtualHost *:443> block for
|
||||
# optical-dev.oliver.solutions, or Include this file from it.
|
||||
#
|
||||
# Required Apache modules (enable if not already):
|
||||
# sudo a2enmod proxy proxy_http proxy_wstunnel rewrite
|
||||
# sudo systemctl restart apache2
|
||||
# ============================================================
|
||||
|
||||
# --- API + Backend routes ---
|
||||
ProxyPass /amazon-transcreation/api http://127.0.0.1:8040/api
|
||||
ProxyPassReverse /amazon-transcreation/api http://127.0.0.1:8040/api
|
||||
|
||||
ProxyPass /amazon-transcreation/health http://127.0.0.1:8040/health
|
||||
ProxyPassReverse /amazon-transcreation/health http://127.0.0.1:8040/health
|
||||
|
||||
ProxyPass /amazon-transcreation/docs http://127.0.0.1:8040/docs
|
||||
ProxyPassReverse /amazon-transcreation/docs http://127.0.0.1:8040/docs
|
||||
|
||||
ProxyPass /amazon-transcreation/openapi.json http://127.0.0.1:8040/openapi.json
|
||||
ProxyPassReverse /amazon-transcreation/openapi.json http://127.0.0.1:8040/openapi.json
|
||||
|
||||
# --- WebSocket (job monitoring) ---
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTP:Upgrade} websocket [NC]
|
||||
RewriteCond %{HTTP:Connection} upgrade [NC]
|
||||
RewriteRule ^/amazon-transcreation/ws/(.*) ws://127.0.0.1:8040/ws/$1 [P,L]
|
||||
|
||||
ProxyPass /amazon-transcreation/ws http://127.0.0.1:8040/ws
|
||||
ProxyPassReverse /amazon-transcreation/ws http://127.0.0.1:8040/ws
|
||||
|
||||
# --- Frontend (Next.js) ---
|
||||
# Must come AFTER the more specific /api, /ws, /health rules
|
||||
ProxyPass /amazon-transcreation http://127.0.0.1:3050/amazon-transcreation
|
||||
ProxyPassReverse /amazon-transcreation http://127.0.0.1:3050/amazon-transcreation
|
||||
|
||||
# Increase timeouts for long-running agent API calls
|
||||
ProxyTimeout 300
|
||||
|
||||
# Pass original host header
|
||||
ProxyPreserveHost On
|
||||
RequestHeader set X-Forwarded-Proto "https"
|
||||
93
deploy.sh
93
deploy.sh
|
|
@ -7,7 +7,8 @@
|
|||
# Updates: ./deploy.sh
|
||||
# Full rebuild: ./deploy.sh --rebuild
|
||||
#
|
||||
# Expected location: /opt/amazon-transcreation
|
||||
# Location: /opt/amazon-transcreation
|
||||
# URL: https://optical-dev.oliver.solutions/amazon-transcreation
|
||||
# ============================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
|
@ -39,7 +40,7 @@ for arg in "$@"; do
|
|||
--rebuild) REBUILD=true ;;
|
||||
--help)
|
||||
echo "Usage: $0 [--init] [--rebuild]"
|
||||
echo " --init First-time setup (create .env, run migrations, seed data)"
|
||||
echo " --init First-time setup (create .env, run migrations, seed data, configure Apache)"
|
||||
echo " --rebuild Force rebuild all Docker images (no cache)"
|
||||
echo " (no args) Pull latest code, rebuild changed images, restart"
|
||||
exit 0
|
||||
|
|
@ -69,10 +70,10 @@ if [ "$INIT" = true ]; then
|
|||
cp .env.production.example .env
|
||||
# Generate a real JWT secret
|
||||
JWT_SECRET=$(python3 -c "import secrets; print(secrets.token_hex(32))" 2>/dev/null || openssl rand -hex 32)
|
||||
sed -i.bak "s/CHANGE_ME_GENERATE_WITH.*/$JWT_SECRET/" .env && rm -f .env.bak
|
||||
sed -i "s/CHANGE_ME_GENERATE_WITH.*/$JWT_SECRET/" .env
|
||||
# Generate a real DB password
|
||||
DB_PASS=$(python3 -c "import secrets; print(secrets.token_hex(16))" 2>/dev/null || openssl rand -hex 16)
|
||||
sed -i.bak "s/CHANGE_ME_DB_PASSWORD/$DB_PASS/g" .env && rm -f .env.bak
|
||||
sed -i "s/CHANGE_ME_DB_PASSWORD/$DB_PASS/g" .env
|
||||
warn ".env created from template. You MUST edit it to set:"
|
||||
warn " - ANTHROPIC_API_KEY (your Claude API key)"
|
||||
warn ""
|
||||
|
|
@ -95,7 +96,6 @@ if [ "$INIT" = true ]; then
|
|||
# Create storage directories
|
||||
log "Creating storage directories..."
|
||||
mkdir -p storage/amazon/{tm,ref}
|
||||
mkdir -p nginx/ssl
|
||||
|
||||
# Build all images
|
||||
log "Building all Docker images (this may take a few minutes)..."
|
||||
|
|
@ -110,11 +110,12 @@ if [ "$INIT" = true ]; then
|
|||
# Start backend for migrations
|
||||
log "Starting backend..."
|
||||
$COMPOSE up -d backend
|
||||
sleep 5
|
||||
|
||||
# Wait for backend to be ready
|
||||
log "Waiting for backend to start..."
|
||||
for i in $(seq 1 30); do
|
||||
if $COMPOSE exec -T backend python -c "print('ok')" >/dev/null 2>&1; then
|
||||
if curl -sf http://127.0.0.1:8040/health >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
|
|
@ -131,8 +132,8 @@ if [ "$INIT" = true ]; then
|
|||
--source "../Agent build + supporting JSONs/JSON REFS and TMs" \
|
||||
--target storage/amazon
|
||||
else
|
||||
warn "Reference files source directory not found. Skipping import."
|
||||
warn "You can run this manually later:"
|
||||
warn "Reference files source directory not found at ../Agent build + supporting JSONs/JSON REFS and TMs"
|
||||
warn "You can import them manually later:"
|
||||
warn " python3 seed/import_reference_files.py --source /path/to/JSON_REFS_and_TMs --target storage/amazon"
|
||||
fi
|
||||
|
||||
|
|
@ -145,14 +146,61 @@ if [ "$INIT" = true ]; then
|
|||
log "Starting all services..."
|
||||
$COMPOSE up -d
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# Apache configuration
|
||||
# ---------------------------------------------------------------
|
||||
log "Configuring Apache reverse proxy..."
|
||||
|
||||
# Enable required modules
|
||||
a2enmod proxy proxy_http proxy_wstunnel rewrite headers 2>/dev/null || true
|
||||
|
||||
# Find the SSL vhost for optical-dev.oliver.solutions
|
||||
VHOST_FILE=$(grep -rl "optical-dev.oliver.solutions" /etc/apache2/sites-enabled/ 2>/dev/null | head -1 || true)
|
||||
|
||||
if [ -n "$VHOST_FILE" ]; then
|
||||
# Check if already configured
|
||||
if grep -q "amazon-transcreation" "$VHOST_FILE" 2>/dev/null; then
|
||||
log "Apache already has amazon-transcreation config in $VHOST_FILE"
|
||||
else
|
||||
warn "Found vhost at: $VHOST_FILE"
|
||||
warn ""
|
||||
warn "Add the following INSIDE the <VirtualHost *:443> block, before </VirtualHost>:"
|
||||
warn ""
|
||||
warn " Include /opt/amazon-transcreation/apache/amazon-transcreation.conf"
|
||||
warn ""
|
||||
warn "Then run: sudo systemctl reload apache2"
|
||||
echo ""
|
||||
read -p "Want me to add it automatically? [y/N] " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
# Insert Include line before </VirtualHost>
|
||||
sed -i "/<\/VirtualHost>/i\\ Include /opt/amazon-transcreation/apache/amazon-transcreation.conf" "$VHOST_FILE"
|
||||
systemctl reload apache2
|
||||
log "Apache config added and reloaded."
|
||||
fi
|
||||
fi
|
||||
else
|
||||
warn "Could not find Apache vhost for optical-dev.oliver.solutions"
|
||||
warn "Manually add this to your SSL vhost:"
|
||||
warn " Include /opt/amazon-transcreation/apache/amazon-transcreation.conf"
|
||||
warn "Then: sudo systemctl reload apache2"
|
||||
fi
|
||||
|
||||
# Health check
|
||||
sleep 3
|
||||
if curl -sf http://127.0.0.1:8040/health >/dev/null 2>&1; then
|
||||
log "Backend health check passed"
|
||||
else
|
||||
warn "Backend health check failed — check logs: $COMPOSE logs backend"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log "=== SETUP COMPLETE ==="
|
||||
log ""
|
||||
log "Services:"
|
||||
log " Frontend: http://localhost (via nginx)"
|
||||
log " API: http://localhost/api/v1"
|
||||
log " API Docs: http://localhost/docs"
|
||||
log " Health: http://localhost/health"
|
||||
log "URL: https://optical-dev.oliver.solutions/amazon-transcreation"
|
||||
log ""
|
||||
log "Services running:"
|
||||
$COMPOSE ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
|
||||
log ""
|
||||
log "Test credentials:"
|
||||
log " admin@amazon.com / admin123!"
|
||||
|
|
@ -160,9 +208,9 @@ if [ "$INIT" = true ]; then
|
|||
log " reviewer@amazon.com / reviewer123!"
|
||||
log ""
|
||||
log "Next steps:"
|
||||
log " 1. Update ANTHROPIC_API_KEY in .env if not done"
|
||||
log " 2. Change default user passwords via the admin panel"
|
||||
log " 3. For HTTPS, add certs to nginx/ssl/ and uncomment the SSL block in nginx/nginx.conf"
|
||||
log " 1. Verify ANTHROPIC_API_KEY is set in .env"
|
||||
log " 2. Ensure Apache config is loaded (see above)"
|
||||
log " 3. Change default passwords via admin panel"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
|
@ -197,19 +245,16 @@ log "Restarting all services..."
|
|||
$COMPOSE up -d
|
||||
|
||||
# Health check
|
||||
log "Waiting for services to start..."
|
||||
log "Waiting for services..."
|
||||
sleep 5
|
||||
|
||||
HEALTH=$(curl -sf http://localhost/health 2>/dev/null || echo '{"status":"error"}')
|
||||
if echo "$HEALTH" | grep -q '"healthy"'; then
|
||||
if curl -sf http://127.0.0.1:8040/health >/dev/null 2>&1; then
|
||||
log "Health check passed"
|
||||
else
|
||||
warn "Health check returned: $HEALTH"
|
||||
warn "Check logs: docker compose -f $COMPOSE_FILE logs --tail 50"
|
||||
warn "Health check failed — check: $COMPOSE logs --tail 50"
|
||||
fi
|
||||
|
||||
# Show running containers
|
||||
echo ""
|
||||
$COMPOSE ps
|
||||
$COMPOSE ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
|
||||
echo ""
|
||||
log "Deploy complete."
|
||||
log "Deploy complete. URL: https://optical-dev.oliver.solutions/amazon-transcreation"
|
||||
|
|
|
|||
|
|
@ -68,28 +68,16 @@ services:
|
|||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-/api}
|
||||
- NEXT_PUBLIC_WS_URL=${NEXT_PUBLIC_WS_URL:-}
|
||||
- NEXT_PUBLIC_API_URL=/amazon-transcreation
|
||||
- NEXT_PUBLIC_WS_URL=
|
||||
- NEXT_PUBLIC_BASE_PATH=/amazon-transcreation
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:3000:3000"
|
||||
- "127.0.0.1:3050:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
depends_on:
|
||||
- backend
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./nginx/ssl:/etc/nginx/ssl:ro
|
||||
depends_on:
|
||||
- frontend
|
||||
- backend
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Accept build-time env vars for API URL
|
||||
ARG NEXT_PUBLIC_API_URL=http://localhost:8040
|
||||
ARG NEXT_PUBLIC_WS_URL=ws://localhost:8040
|
||||
# Accept build-time env vars
|
||||
ARG NEXT_PUBLIC_API_URL=
|
||||
ARG NEXT_PUBLIC_WS_URL=
|
||||
ARG NEXT_PUBLIC_BASE_PATH=
|
||||
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
|
||||
ENV NEXT_PUBLIC_WS_URL=$NEXT_PUBLIC_WS_URL
|
||||
ENV NEXT_PUBLIC_BASE_PATH=$NEXT_PUBLIC_BASE_PATH
|
||||
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN npm ci
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
output: 'standalone',
|
||||
basePath: process.env.NEXT_PUBLIC_BASE_PATH || '',
|
||||
assetPrefix: process.env.NEXT_PUBLIC_BASE_PATH || '',
|
||||
images: {
|
||||
domains: ['localhost'],
|
||||
domains: ['localhost', 'optical-dev.oliver.solutions'],
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,19 @@ import { getToken } from "./auth";
|
|||
|
||||
type MessageHandler = (message: WSMessage) => void;
|
||||
|
||||
const WS_BASE_URL =
|
||||
process.env.NEXT_PUBLIC_WS_URL || "ws://localhost:8000";
|
||||
function getWsBaseUrl(): string {
|
||||
// If explicit WS URL is set, use it
|
||||
const explicit = process.env.NEXT_PUBLIC_WS_URL;
|
||||
if (explicit) return explicit;
|
||||
|
||||
// Auto-detect from current page location (works behind reverse proxy)
|
||||
if (typeof window !== "undefined") {
|
||||
const proto = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||
return `${proto}//${window.location.host}`;
|
||||
}
|
||||
|
||||
return "ws://localhost:8040";
|
||||
}
|
||||
|
||||
export class WebSocketClient {
|
||||
private ws: WebSocket | null = null;
|
||||
|
|
@ -17,7 +28,8 @@ export class WebSocketClient {
|
|||
|
||||
constructor(jobId: string) {
|
||||
const token = getToken();
|
||||
this.url = `${WS_BASE_URL}/ws/jobs/${jobId}?token=${token}`;
|
||||
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
|
||||
this.url = `${getWsBaseUrl()}${basePath}/ws/jobs/${jobId}?token=${token}`;
|
||||
}
|
||||
|
||||
connect(): void {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue