FROM python:3.10-slim WORKDIR /app # Install system dependencies including nginx RUN apt-get update && apt-get install -y \ build-essential \ curl \ nginx \ && rm -rf /var/lib/apt/lists/* # Install Node.js for the frontend build RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \ && apt-get install -y nodejs \ && rm -rf /var/lib/apt/lists/* # Copy backend requirements and install COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy backend files COPY main.py . COPY rfp_analyzer.py . COPY rubric.yaml . # Copy frontend files COPY ui-svelte/ ./ui-svelte/ # Build frontend WORKDIR /app/ui-svelte # Fix npm permissions and install RUN npm config set cache /tmp/.npm --global && \ npm install && \ chmod -R 755 node_modules/.bin # Build with explicit path to vite RUN npx vite build # Configure nginx WORKDIR /app # Create writable directories for nginx RUN mkdir -p /tmp/nginx/body /tmp/nginx/proxy /tmp/nginx/fastcgi /tmp/nginx/uwsgi /tmp/nginx/scgi && \ chmod -R 777 /tmp/nginx # Configure nginx to use /tmp directories (no root required) RUN echo 'pid /tmp/nginx.pid;\n\ error_log /dev/stderr warn;\n\ \n\ events {\n\ worker_connections 1024;\n\ }\n\ \n\ http {\n\ include /etc/nginx/mime.types;\n\ default_type application/octet-stream;\n\ \n\ # Use /tmp directories for nginx temporary files\n\ client_body_temp_path /tmp/nginx/body;\n\ proxy_temp_path /tmp/nginx/proxy;\n\ fastcgi_temp_path /tmp/nginx/fastcgi;\n\ uwsgi_temp_path /tmp/nginx/uwsgi;\n\ scgi_temp_path /tmp/nginx/scgi;\n\ \n\ access_log /dev/stdout;\n\ \n\ sendfile on;\n\ tcp_nopush on;\n\ tcp_nodelay on;\n\ keepalive_timeout 65;\n\ types_hash_max_size 2048;\n\ \n\ server {\n\ listen 7860;\n\ server_name _;\n\ \n\ # Serve static files from Svelte build\n\ root /app/ui-svelte/dist;\n\ index index.html;\n\ \n\ # API proxy to FastAPI backend\n\ location /analyze {\n\ proxy_pass http://localhost:8000;\n\ proxy_http_version 1.1;\n\ proxy_set_header Upgrade $http_upgrade;\n\ proxy_set_header Connection "upgrade";\n\ proxy_set_header Host $host;\n\ proxy_set_header X-Real-IP $remote_addr;\n\ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n\ proxy_set_header X-Forwarded-Proto $scheme;\n\ proxy_read_timeout 300s;\n\ proxy_connect_timeout 75s;\n\ }\n\ \n\ location /preview-pdf {\n\ proxy_pass http://localhost:8000;\n\ proxy_http_version 1.1;\n\ proxy_set_header Host $host;\n\ proxy_set_header X-Real-IP $remote_addr;\n\ proxy_read_timeout 300s;\n\ }\n\ \n\ location /health {\n\ proxy_pass http://localhost:8000;\n\ }\n\ \n\ location /docs {\n\ proxy_pass http://localhost:8000;\n\ }\n\ \n\ location /openapi.json {\n\ proxy_pass http://localhost:8000;\n\ }\n\ \n\ # Serve static files\n\ location / {\n\ try_files $uri $uri/ /index.html;\n\ }\n\ \n\ # Disable buffering for large uploads\n\ client_max_body_size 100M;\n\ proxy_buffering off;\n\ }\n\ }\n\ ' > /etc/nginx/nginx.conf # Create startup script RUN echo '#!/bin/bash\n\ set -e\n\ \n\ # Start FastAPI backend in background\n\ echo "Starting FastAPI backend..."\n\ uvicorn main:app --host 0.0.0.0 --port 8000 &\n\ BACKEND_PID=$!\n\ \n\ # Wait for backend to be ready\n\ echo "Waiting for backend to start..."\n\ sleep 5\n\ \n\ # Start nginx\n\ echo "Starting nginx on port 7860..."\n\ nginx -g "daemon off;" &\n\ NGINX_PID=$!\n\ \n\ echo "✅ RFP Analyzer is running!"\n\ echo " Backend: http://localhost:8000"\n\ echo " Frontend: http://localhost:7860"\n\ \n\ # Wait for any process to exit\n\ wait -n\n\ \n\ # Exit with status of process that exited first\n\ exit $?\n\ ' > /app/start.sh && chmod +x /app/start.sh EXPOSE 7860 8000 CMD ["/app/start.sh"]