configured app to run on custom port with apache reverse proxy, wrote deploy.sh script

This commit is contained in:
michael 2026-02-02 16:56:48 -06:00
parent 490d560306
commit c66d498d04
11 changed files with 277 additions and 29 deletions

View file

@ -215,7 +215,7 @@ events {
http {
upstream backend {
server backend:8000;
server backend:8048;
}
upstream frontend {
@ -405,7 +405,7 @@ docker-compose -f docker-compose.prod.yml exec backend python -c "from app.datab
docker-compose -f docker-compose.prod.yml logs frontend
# Check if backend is accessible
curl http://backend:8000/health
curl http://backend:8048/health
```
### SSL certificate issues

View file

@ -41,7 +41,7 @@
4. Configure:
- Name: "APAC Ops Bot"
- Supported account types: "Accounts in this organizational directory only"
- Redirect URI: `http://localhost:8000/api/v1/auth/msal/callback`
- Redirect URI: `http://localhost:8048/api/v1/auth/msal/callback`
5. After registration, note down:
- **Application (client) ID**
- **Directory (tenant) ID**
@ -81,9 +81,9 @@ docker-compose logs postgres
docker-compose up --build backend
```
The backend will be available at: **http://localhost:8000**
- API Docs: http://localhost:8000/docs
- Health Check: http://localhost:8000/health
The backend will be available at: **http://localhost:8048**
- API Docs: http://localhost:8048/docs
- Health Check: http://localhost:8048/health
### Step 4: Run Database Migrations
@ -115,7 +115,7 @@ The frontend will be available at: **http://localhost:3000**
```bash
# Health check
curl http://localhost:8000/health
curl http://localhost:8048/health
# Expected response:
# {"status":"healthy","app":"Seapac Ops Bot","environment":"development"}
@ -184,7 +184,7 @@ apac-ops-bot/
**Solution:**
```bash
# Check what's using the port
lsof -i :8000 # or :5432, :6379
lsof -i :8048 # or :5432, :6379
# Stop existing containers
docker-compose down

View file

@ -68,7 +68,7 @@ cp .env.example .env
**Required Frontend environment variables:**
- `REACT_APP_AZURE_CLIENT_ID` - Same as backend Azure client ID
- `REACT_APP_AZURE_TENANT_ID` - Same as backend Azure tenant ID
- `REACT_APP_API_URL` - Backend API URL (default: http://localhost:8000/api/v1)
- `REACT_APP_API_URL` - Backend API URL (default: /apac-ops-bot-back/api/v1)
### 3. Start services with Docker Compose
@ -80,7 +80,7 @@ docker-compose up --build
This will start:
- PostgreSQL (port 5432)
- Redis (port 6379)
- Backend API (port 8000)
- Backend API (port 8048)
- Frontend (port 3000)
**First run:** The backend will automatically create database tables on startup.
@ -88,8 +88,8 @@ This will start:
### 4. Access the application
- **Frontend Application:** http://localhost:3000
- **API Documentation:** http://localhost:8000/docs
- **Health Check:** http://localhost:8000/health
- **API Documentation:** http://localhost:8048/docs
- **Health Check:** http://localhost:8048/health
## Development
@ -185,8 +185,8 @@ apac-ops-bot/
## API Documentation
Once the backend is running, access the interactive API documentation at:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
- Swagger UI: http://localhost:8048/docs
- ReDoc: http://localhost:8048/redoc
## Security

View file

@ -12,7 +12,7 @@ DATABASE_URL=postgresql+asyncpg://apac_ops_bot:password@localhost:5432/apac_ops_
AZURE_TENANT_ID=your-tenant-id
AZURE_CLIENT_ID=your-client-id
AZURE_CLIENT_SECRET=your-client-secret
AZURE_REDIRECT_URI=http://localhost:8000/api/v1/auth/msal/callback
AZURE_REDIRECT_URI=http://localhost:8048/api/v1/auth/msal/callback
# OpenAI Responses API
OPENAI_API_KEY=your-openai-api-key-here

View file

@ -30,10 +30,10 @@ RUN pip install --no-cache-dir -r requirements-dev.txt
COPY . .
# Expose port
EXPOSE 8000
EXPOSE 8048
# Development command (with hot reload)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8048", "--reload"]
# Stage 3: Production environment
FROM base as production
@ -47,7 +47,7 @@ RUN useradd -m -u 1000 appuser && \
USER appuser
# Expose port
EXPOSE 8000
EXPOSE 8048
# Production command with multiple workers
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8048", "--workers", "4"]

View file

@ -78,6 +78,6 @@ if __name__ == "__main__":
uvicorn.run(
"app.main:app",
host="0.0.0.0",
port=8000,
port=8048,
reload=settings.DEBUG,
)

View file

@ -78,13 +78,13 @@ def test_settings_azure_ad_configuration():
AZURE_TENANT_ID="test-tenant-id",
AZURE_CLIENT_ID="test-client-id",
AZURE_CLIENT_SECRET="test-client-secret",
AZURE_REDIRECT_URI="http://localhost:8000/api/v1/auth/callback",
AZURE_REDIRECT_URI="http://localhost:8048/api/v1/auth/callback",
)
assert settings.AZURE_TENANT_ID == "test-tenant-id"
assert settings.AZURE_CLIENT_ID == "test-client-id"
assert settings.AZURE_CLIENT_SECRET == "test-client-secret"
assert settings.AZURE_REDIRECT_URI == "http://localhost:8000/api/v1/auth/callback"
assert settings.AZURE_REDIRECT_URI == "http://localhost:8048/api/v1/auth/callback"
def test_settings_redis_url():

244
deploy.sh Executable file
View file

@ -0,0 +1,244 @@
#!/bin/bash
#
# APAC Ops Bot Deployment Script
# Idempotent deployment for Ubuntu server at /opt/apac-ops-bot/
#
# Usage: sudo ./deploy.sh
#
# Note: Run 'git pull origin main' manually before running this script
# (root user typically doesn't have SSH keys for git)
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] ${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] ${GREEN}[SUCCESS]${NC} $1"
}
log_warn() {
echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] ${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] ${RED}[ERROR]${NC} $1"
}
# Error handler
error_exit() {
log_error "$1"
exit 1
}
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FRONTEND_DEPLOY_PATH="/var/www/html/apac-ops-bot"
BACKEND_PORT=8048
HEALTH_CHECK_RETRIES=30
HEALTH_CHECK_INTERVAL=2
log_info "Starting APAC Ops Bot deployment..."
log_info "Working directory: $SCRIPT_DIR"
# -----------------------------------------------------------------------------
# Pre-flight checks
# -----------------------------------------------------------------------------
log_info "Running pre-flight checks..."
# Check if running as root
if [[ $EUID -ne 0 ]]; then
error_exit "This script must be run as root (use sudo)"
fi
# Check Docker
if ! command -v docker &> /dev/null; then
error_exit "Docker is not installed"
fi
log_info "Docker found: $(docker --version)"
# Check docker-compose (try both v1 and v2 syntax)
if command -v docker-compose &> /dev/null; then
DOCKER_COMPOSE="docker-compose"
elif docker compose version &> /dev/null; then
DOCKER_COMPOSE="docker compose"
else
error_exit "docker-compose is not installed"
fi
log_info "Docker Compose found: $($DOCKER_COMPOSE version --short 2>/dev/null || $DOCKER_COMPOSE version)"
# Check Node.js
if ! command -v node &> /dev/null; then
error_exit "Node.js is not installed"
fi
NODE_VERSION=$(node --version)
log_info "Node.js found: $NODE_VERSION"
# Check npm
if ! command -v npm &> /dev/null; then
error_exit "npm is not installed"
fi
log_info "npm found: $(npm --version)"
# Check .env files
if [[ ! -f "$SCRIPT_DIR/backend/.env" ]]; then
error_exit "Backend .env file not found at $SCRIPT_DIR/backend/.env"
fi
log_info "Backend .env file found"
if [[ ! -f "$SCRIPT_DIR/frontend/.env" ]]; then
log_warn "Frontend .env file not found at $SCRIPT_DIR/frontend/.env (may use defaults)"
fi
# Verify docker-compose.yml exists
if [[ ! -f "$SCRIPT_DIR/docker-compose.yml" ]]; then
error_exit "docker-compose.yml not found"
fi
log_success "Pre-flight checks passed"
# -----------------------------------------------------------------------------
# Build Docker containers
# -----------------------------------------------------------------------------
log_info "Building Docker containers..."
cd "$SCRIPT_DIR"
$DOCKER_COMPOSE build --pull || error_exit "Docker build failed"
log_success "Docker containers built"
# -----------------------------------------------------------------------------
# Restart Docker services
# -----------------------------------------------------------------------------
log_info "Starting Docker services..."
$DOCKER_COMPOSE up -d || error_exit "Failed to start Docker services"
# Wait for postgres to be healthy
log_info "Waiting for PostgreSQL to be ready..."
POSTGRES_READY=false
for i in $(seq 1 $HEALTH_CHECK_RETRIES); do
if $DOCKER_COMPOSE exec -T postgres pg_isready -U apac_ops_bot &> /dev/null; then
POSTGRES_READY=true
break
fi
log_info "Waiting for PostgreSQL... (attempt $i/$HEALTH_CHECK_RETRIES)"
sleep $HEALTH_CHECK_INTERVAL
done
if [[ "$POSTGRES_READY" != "true" ]]; then
error_exit "PostgreSQL failed to become ready"
fi
log_success "Docker services started and PostgreSQL is ready"
# -----------------------------------------------------------------------------
# Run database migrations
# -----------------------------------------------------------------------------
log_info "Running database migrations..."
$DOCKER_COMPOSE exec -T backend alembic upgrade head || error_exit "Database migrations failed"
log_success "Database migrations completed"
# -----------------------------------------------------------------------------
# Build frontend
# -----------------------------------------------------------------------------
log_info "Building frontend..."
cd "$SCRIPT_DIR/frontend"
# Clean install dependencies
log_info "Installing frontend dependencies..."
npm ci || error_exit "npm ci failed"
# Build production bundle
log_info "Creating production build..."
npm run build || error_exit "Frontend build failed"
if [[ ! -d "$SCRIPT_DIR/frontend/build" ]]; then
error_exit "Frontend build directory not found"
fi
log_success "Frontend built successfully"
# -----------------------------------------------------------------------------
# Deploy frontend to Apache
# -----------------------------------------------------------------------------
log_info "Deploying frontend to Apache..."
# Create deployment directory if it doesn't exist
mkdir -p "$FRONTEND_DEPLOY_PATH"
# Clear existing files
rm -rf "${FRONTEND_DEPLOY_PATH:?}"/*
# Copy new build
cp -r "$SCRIPT_DIR/frontend/build/"* "$FRONTEND_DEPLOY_PATH/"
# Set proper ownership
chown -R www-data:www-data "$FRONTEND_DEPLOY_PATH"
# Verify index.html exists
if [[ ! -f "$FRONTEND_DEPLOY_PATH/index.html" ]]; then
error_exit "Frontend deployment verification failed - index.html not found"
fi
log_success "Frontend deployed to $FRONTEND_DEPLOY_PATH"
# -----------------------------------------------------------------------------
# Verification
# -----------------------------------------------------------------------------
log_info "Running verification checks..."
# Wait for backend to be ready
log_info "Waiting for backend health check..."
BACKEND_READY=false
for i in $(seq 1 $HEALTH_CHECK_RETRIES); do
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$BACKEND_PORT/health" 2>/dev/null || echo "000")
if [[ "$HTTP_STATUS" == "200" ]]; then
BACKEND_READY=true
break
fi
log_info "Waiting for backend... (attempt $i/$HEALTH_CHECK_RETRIES, status: $HTTP_STATUS)"
sleep $HEALTH_CHECK_INTERVAL
done
if [[ "$BACKEND_READY" != "true" ]]; then
log_warn "Backend health check failed - service may still be starting"
else
log_success "Backend health check passed"
fi
# Verify Docker containers are running
log_info "Docker container status:"
cd "$SCRIPT_DIR"
$DOCKER_COMPOSE ps
# -----------------------------------------------------------------------------
# Summary
# -----------------------------------------------------------------------------
echo ""
echo "=============================================="
COMMIT_HASH=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
COMMIT_MSG=$(git log -1 --pretty=format:"%s" 2>/dev/null || echo "unknown")
if [[ "$BACKEND_READY" == "true" ]]; then
log_success "Deployment completed successfully!"
else
log_warn "Deployment completed with warnings (backend may still be starting)"
fi
echo ""
log_info "Deployed commit: $COMMIT_HASH - $COMMIT_MSG"
log_info "Frontend path: $FRONTEND_DEPLOY_PATH"
log_info "Backend URL: http://localhost:$BACKEND_PORT"
echo "=============================================="

View file

@ -44,11 +44,11 @@ services:
dockerfile: Dockerfile
target: development
container_name: apac_ops_bot_backend
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
command: uvicorn app.main:app --host 0.0.0.0 --port 8048 --reload
volumes:
- ./backend:/app
ports:
- "8000:8000"
- "8048:8048"
env_file:
- ./backend/.env
environment:
@ -78,8 +78,8 @@ services:
env_file:
- ./frontend/.env
environment:
- REACT_APP_API_URL=http://83.151.203.105:8000/api/v1
- REACT_APP_WS_URL=ws://83.151.203.105:8000/ws
- REACT_APP_API_URL=/apac-ops-bot-back/api/v1
- REACT_APP_WS_URL=/apac-ops-bot-back/ws
depends_on:
- backend
networks:

View file

@ -1,6 +1,10 @@
# API Configuration
REACT_APP_API_URL=http://localhost:8000/api/v1
REACT_APP_WS_URL=ws://localhost:8000/ws
# For production with Apache reverse proxy:
REACT_APP_API_URL=/apac-ops-bot-back/api/v1
REACT_APP_WS_URL=/apac-ops-bot-back/ws
# For local development without proxy:
# REACT_APP_API_URL=http://localhost:8048/api/v1
# REACT_APP_WS_URL=ws://localhost:8048/ws
# Azure AD / MSAL Configuration
REACT_APP_AZURE_CLIENT_ID=your-client-id-here

View file

@ -6,7 +6,7 @@
import axios, { AxiosInstance, InternalAxiosRequestConfig } from 'axios';
const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:8000/api/v1';
const API_URL = process.env.REACT_APP_API_URL || '/apac-ops-bot-back/api/v1';
// Create axios instance
const apiClient: AxiosInstance = axios.create({