Add frontend and Caddy to Docker Compose dev environment

Containerize the frontend dev server (Vite) and add a Caddy reverse
proxy for HTTPS termination, replacing the manual local setup. The
Caddy config proxies /api/* to the backend and everything else to the
frontend dev server.

Also simplify start.sh: remove --local Poetry mode, extract
get_compose_cmd helper, and document new services and DEV_HOST env var.
This commit is contained in:
Viktor Barzin 2026-02-06 23:45:29 +00:00
parent 2626870396
commit e55902d813
No known key found for this signature in database
GPG key ID: 0EB088298288D958
3 changed files with 89 additions and 92 deletions

View file

@ -1,5 +1,3 @@
version: "3.8"
services: services:
redis: redis:
image: redis:8 image: redis:8
@ -111,6 +109,37 @@ services:
networks: networks:
- rec-network - rec-network
frontend:
image: node:24-alpine
container_name: rec-frontend
working_dir: /app
ports:
- "5173:5173"
volumes:
- ./frontend:/app
- frontend_node_modules:/app/node_modules
environment:
- DEV_HOST=${DEV_HOST:-localhost}
command: sh -c "npm ci && npm run dev -- --host"
networks:
- rec-network
caddy:
image: caddy:alpine
container_name: rec-caddy
ports:
- "443:443"
volumes:
- ./frontend/Caddyfile.dev:/etc/caddy/Caddyfile
- caddy_data:/data
environment:
- DEV_HOST=${DEV_HOST:-localhost}
depends_on:
- frontend
- app
networks:
- rec-network
networks: networks:
rec-network: rec-network:
driver: bridge driver: bridge
@ -119,3 +148,5 @@ volumes:
redis_data: redis_data:
mysql_data: mysql_data:
app_venv: app_venv:
frontend_node_modules:
caddy_data:

View file

@ -0,0 +1,11 @@
{$DEV_HOST:localhost}:443 {
tls internal
handle /api/* {
reverse_proxy app:5001
}
handle {
reverse_proxy frontend:5173
}
}

View file

@ -2,9 +2,13 @@
set -eu set -eu
# Real Estate Crawler - Development Server # Real Estate Crawler - Development Server
# Starts all backend services + frontend + Caddy HTTPS proxy via Docker Compose.
#
# Usage: # Usage:
# ./start.sh - Start with Docker (recommended) # ./start.sh - Start all services (backend + frontend)
# ./start.sh --local - Start locally (requires Poetry and dependencies) # ./start.sh --build - Rebuild images before starting
# ./start.sh --down - Stop and remove all containers
# ./start.sh --logs - Follow logs from all services
# ./start.sh --help - Show help # ./start.sh --help - Show help
show_help() { show_help() {
@ -14,16 +18,40 @@ show_help() {
echo "" echo ""
echo "Options:" echo "Options:"
echo " (default) Start all services with Docker Compose" echo " (default) Start all services with Docker Compose"
echo " --local Run locally with Poetry (requires local deps)"
echo " --build Rebuild Docker images before starting" echo " --build Rebuild Docker images before starting"
echo " --down Stop and remove all containers" echo " --down Stop and remove all containers"
echo " --logs Follow logs from all services" echo " --logs Follow logs from all services"
echo " --help Show this help message" echo " --help Show this help message"
echo "" echo ""
echo "Services started:"
echo " redis Redis broker + cache (port 6379)"
echo " mysql MySQL database (port 3306)"
echo " app FastAPI backend (hot-reload) (port 5001)"
echo " celery Celery background worker"
echo " celery-beat Celery periodic scheduler"
echo " frontend Vite dev server (hot-reload) (port 5173)"
echo " caddy HTTPS reverse proxy (port 443)"
echo ""
echo "Environment variables:"
echo " DEV_HOST Hostname for HTTPS access (default: localhost)"
echo " Set this to your dev machine's hostname for OIDC auth."
echo ""
echo "Examples:" echo "Examples:"
echo " ./start.sh # Start with Docker" echo " ./start.sh # Start everything"
echo " ./start.sh --build # Rebuild and start" echo " ./start.sh --build # Rebuild and start"
echo " ./start.sh --local # Run locally with Poetry" echo " DEV_HOST=devvm.local ./start.sh # Start with custom hostname"
}
get_compose_cmd() {
if command -v docker &> /dev/null; then
echo "docker compose"
elif command -v podman-compose &> /dev/null; then
echo "podman-compose"
else
echo "❌ Error: Neither docker nor podman-compose found." >&2
echo " Install Docker: https://docs.docker.com/get-docker/" >&2
exit 1
fi
} }
start_docker() { start_docker() {
@ -32,96 +60,26 @@ start_docker() {
build_flag="--build" build_flag="--build"
fi fi
echo "🐳 Starting services with Docker Compose..." echo "Starting all services with Docker Compose..."
echo "" echo ""
# Check if docker/podman is available local compose_cmd
if command -v docker &> /dev/null; then compose_cmd=$(get_compose_cmd)
COMPOSE_CMD="docker compose"
elif command -v podman-compose &> /dev/null; then
COMPOSE_CMD="podman-compose"
else
echo "❌ Error: Neither docker nor podman-compose found."
echo " Install Docker: https://docs.docker.com/get-docker/"
echo " Or run locally: ./start.sh --local"
exit 1
fi
$COMPOSE_CMD up $build_flag $compose_cmd up $build_flag
} }
stop_docker() { stop_docker() {
echo "🛑 Stopping all containers..." echo "Stopping all containers..."
if command -v docker &> /dev/null; then local compose_cmd
docker compose down compose_cmd=$(get_compose_cmd)
elif command -v podman-compose &> /dev/null; then $compose_cmd down
podman-compose down
fi
} }
show_logs() { show_logs() {
if command -v docker &> /dev/null; then local compose_cmd
docker compose logs -f compose_cmd=$(get_compose_cmd)
elif command -v podman-compose &> /dev/null; then $compose_cmd logs -f
podman-compose logs -f
fi
}
start_local() {
echo "🛠️ Starting locally with Poetry..."
echo ""
# Check Poetry is available
if ! command -v poetry &> /dev/null; then
echo "❌ Error: Poetry not found."
echo " Install: curl -sSL https://install.python-poetry.org | python3 -"
echo " Or use Docker: ./start.sh"
exit 1
fi
# Source .env if it exists
if [[ -f .env ]]; then
set -a
source .env
set +a
fi
ENV_MODE=${ENV:-"dev"}
# Ensure Redis is running
if ! nc -z localhost 6379 2>/dev/null; then
echo "📦 Starting Redis container..."
docker run -d --rm --name rec-redis-local -p 6379:6379 redis:latest || true
sleep 2
fi
echo "✅ Redis OK"
# Test celery connection
poetry run python celery_app.py
# Start Celery worker in background
echo "🔧 Starting Celery worker..."
if [[ "$ENV_MODE" == "dev" ]]; then
poetry run celery -A celery_app worker --loglevel=info &
else
poetry run alembic upgrade head
poetry run celery -A celery_app worker --beat --loglevel=info &
fi
CELERY_PID=$!
cleanup() {
echo ""
echo "🛑 Stopping Celery worker (PID: $CELERY_PID)..."
kill "$CELERY_PID" 2>/dev/null || true
wait "$CELERY_PID" 2>/dev/null || true
}
trap cleanup EXIT SIGINT SIGTERM
# Start uvicorn
echo "🚀 Starting API server on http://localhost:5001"
echo ""
poetry run uvicorn api.app:app --host 0.0.0.0 --port 5001 --reload
} }
# Parse arguments # Parse arguments
@ -129,9 +87,6 @@ case "${1:-}" in
--help|-h) --help|-h)
show_help show_help
;; ;;
--local)
start_local
;;
--down) --down)
stop_docker stop_docker
;; ;;