From 1e6e41e4269f58104fbe0ca8b27a837b7e4b7666 Mon Sep 17 00:00:00 2001 From: Woody Date: Mon, 18 May 2026 14:47:22 +0800 Subject: [PATCH] feat: HTTPS support with nginx reverse proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add nginx as reverse proxy (HTTP→HTTPS redirect, self-signed cert) - start.sh entrypoint: generates SSL cert, starts nginx + uvicorn - Single-stage Dockerfile (no separate frontend build stage) - Expose ports 80 and 443 in docker-compose - Update README port references for HTTPS --- Dockerfile | 39 +++++++++++---------------------------- README.md | 8 ++++---- docker-compose.yml | 2 ++ nginx.conf | 13 +++++++++++++ start.sh | 24 ++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 start.sh diff --git a/Dockerfile b/Dockerfile index c508937..2a15b98 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,44 +1,27 @@ -# Stage 1: Build frontend -FROM node:20-alpine AS frontend-build - -WORKDIR /app/frontend - -COPY frontend/package.json frontend/package-lock.json ./ -RUN npm ci - -COPY frontend/ ./ -ENV VITE_API_BASE_URL=/api/v1 -RUN npm run build - -# Stage 2: Production runtime FROM python:3.11-slim WORKDIR /app -# Install system dependencies (ffmpeg for video audio extraction) RUN apt-get update && apt-get install -y --no-install-recommends \ - tini \ - ffmpeg \ + nginx openssl tini ffmpeg curl \ && rm -rf /var/lib/apt/lists/* -# Install Python dependencies COPY backend/requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt -# Copy backend source COPY backend/ ./ +COPY frontend/dist ./frontend/dist -# Copy built frontend from stage 1 -COPY --from=frontend-build /app/frontend/dist ./frontend/dist +RUN rm -f /etc/nginx/sites-enabled/default /etc/nginx/conf.d/default.conf +COPY nginx.conf /etc/nginx/conf.d/default.conf -# Create data directories -RUN mkdir -p /app/chroma_db /app/document_chunk /app/data /app/uploads /app/app/log +COPY start.sh /start.sh +RUN chmod +x /start.sh -# Expose port -EXPOSE 8000 +RUN mkdir -p /app/chroma_db /app/document_chunk /app/data /app/uploads /app/app/log \ + /etc/nginx/ssl /var/log/nginx /var/lib/nginx + +EXPOSE 80 443 -# Use tini as init to handle signals properly ENTRYPOINT ["tini", "--"] - -# Start uvicorn -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] +CMD ["/start.sh"] diff --git a/README.md b/README.md index 7810c85..2a9f387 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ gunzip legco_reranker_amd64.tar.gz docker load -i legco_reranker_amd64.tar # Run -docker run -d --name legco -p 80:8000 --env-file backend/.env \ +docker run -d --name legco -p 80:80 -p 443:443 --env-file backend/.env \ -v chroma_data:/app/chroma_db \ -v chunk_data:/app/document_chunk \ -v sqlite_data:/app/data \ @@ -168,7 +168,7 @@ docker run -d --name legco -p 80:8000 --env-file backend/.env \ Before transferring to the server, test the amd64 image locally. Pass all config inline (no `--env-file`): ```bash -docker run -d --name legco_test -p 8888:8000 \ +docker run -d --name legco_test -p 8888:443 \ -e LLM_BASE_URL=https://openrouter.ai/api/v1 \ -e LLM_API_KEY=your_key_here \ -e LLM_MODEL_NAME=qwen/qwen3.6-35b-a3b \ @@ -196,8 +196,8 @@ docker run -d --name legco_test -p 8888:8000 \ -v ~/woody/legco/data/data:/app/data \ legco_reranker:amd64.01.02 -# Verify -curl http://localhost:8888/health +# Verify (accept self-signed cert with -k) +curl -k https://localhost:8888/health # Clean up docker rm -f legco_test diff --git a/docker-compose.yml b/docker-compose.yml index 79f5ed1..708d203 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,8 @@ services: build: . container_name: legco_reranker ports: + - "80:80" + - "443:443" - "8000:8000" env_file: - ./backend/.env diff --git a/nginx.conf b/nginx.conf index 3b12a13..07dd3b2 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,6 +1,19 @@ +# HTTP → HTTPS redirect server { listen 80; server_name _; + return 301 https://$host$request_uri; +} + +# HTTPS server +server { + listen 443 ssl; + server_name _; + + ssl_certificate /etc/nginx/ssl/server.crt; + ssl_certificate_key /etc/nginx/ssl/server.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; client_max_body_size 350M; diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..ae8fda8 --- /dev/null +++ b/start.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -e + +CERT_DIR="/etc/nginx/ssl" +CERT_FILE="$CERT_DIR/server.crt" +KEY_FILE="$CERT_DIR/server.key" + +mkdir -p "$CERT_DIR" + +if [ ! -f "$CERT_FILE" ] || [ ! -f "$KEY_FILE" ]; then + echo "Generating self-signed SSL certificate..." + openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout "$KEY_FILE" \ + -out "$CERT_FILE" \ + -subj "/C=HK/ST=HongKong/L=HongKong/O=LegCoReranker/CN=localhost" \ + -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" + echo "Self-signed certificate generated." +fi + +echo "Starting nginx..." +nginx + +echo "Starting uvicorn..." +exec tini -- uvicorn app.main:app --host 0.0.0.0 --port 8000