How to Deploy DeepTutor to Production: Complete Docker Setup Guide

Deploy DeepTutor to production by configuring environment variables from .env.example, building the multi-stage Docker image, and running docker compose up -d to launch the all-in-one container that supervises both the FastAPI backend (port 8001) and Next.js frontend (port 3782).

DeepTutor is an open-source intelligent tutoring system developed by HKUDS that pairs a FastAPI backend with a Next.js frontend. To deploy DeepTutor to production, the repository packages both services into a single Docker image orchestrated by supervisord, enabling portable deployments across local machines, VPS instances, or cloud platforms.

Step 1 – Configure Production Environment Variables

Begin by copying the template and setting your LLM provider credentials. The application requires API keys for both the language model and embedding service to function.

cp .env.example .env

Edit .env to include at minimum:

LLM_BINDING=openai
LLM_MODEL=gpt-4o-mini
LLM_API_KEY=sk-xxxxxxxxxxxx
EMBEDDING_BINDING=openai
EMBEDDING_MODEL=text-embedding-3-large
EMBEDDING_API_KEY=sk-xxxxxxxxxxxx
EMBEDDING_DIMENSION=3072

Remote Server Configuration

For deployments where the browser accesses the backend over a network, you must set NEXT_PUBLIC_API_BASE_EXTERNAL (or NEXT_PUBLIC_API_BASE) in .env. This variable tells the frontend the public address of the FastAPI server (e.g., https://my-server.com:8001). According to the docker-compose.yml configuration, this value is propagated into the container at runtime docker-compose.yml.

Step 2 – Build the Multi-Stage Production Image

The Dockerfile uses a multi-stage build process that compiles the Next.js frontend, installs Python dependencies, and assembles the final production image Dockerfile.

Run the build command:

docker compose build

This process:

  1. Builds the frontend assets in a Node.js stage
  2. Installs Python requirements into a slim base image
  3. Copies built assets and application code into the final stage

Step 3 – Launch with Docker Compose

Start the production stack in detached mode:

docker compose up -d

The docker-compose.yml exposes two ports: 8001 for the FastAPI backend and 3782 for the Next.js frontend. It also mounts persistent volumes for user data storage docker-compose.yml.

Verify both services are healthy:

docker compose ps
curl -f http://localhost:8001/

Architecture: How the Container Orchestrates Services

During startup, the entrypoint.sh script (embedded in the Dockerfile at lines 60-68) validates the configuration, creates necessary user-data directories, and launches supervisord Dockerfile.

supervisord then manages two background processes via generated helper scripts:

  • start-backend.sh: Executes uvicorn on the port defined by BACKEND_PORT (default 8001) Dockerfile
  • start-frontend.sh: Performs runtime substitution of __NEXT_PUBLIC_API_BASE_PLACEHOLDER__ with the actual API URL from environment variables, then starts the Next.js standalone server on FRONTEND_PORT (default 3782) Dockerfile

Because Next.js inlines public environment variables at build time, the placeholder replacement technique enables true runtime configuration without requiring image rebuilds when API endpoints change.

Development Mode with Hot-Reload

For local development, use the override file to enable hot-reloading and volume-mounted source code:

docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build

The docker-compose.dev.yml modifies the build context to include full node_modules and mounts local directories for live code changes.

Summary

  • DeepTutor packages both frontend and backend into a single Docker image supervised by supervisord for simplified deployments.
  • Configure .env with LLM credentials and set NEXT_PUBLIC_API_BASE_EXTERNAL for remote access.
  • Build once using the multi-stage Dockerfile that handles Node.js compilation and Python dependency installation.
  • Expose ports 8001 and 3782 via Docker Compose, with persistent volumes for data storage.
  • Runtime frontend configuration is achieved via placeholder replacement in start-frontend.sh, eliminating the need to rebuild for different API endpoints.

Frequently Asked Questions

What ports does DeepTutor use in production?

DeepTutor exposes port 8001 for the FastAPI backend API and port 3782 for the Next.js frontend web interface. These are mapped in docker-compose.yml and can be customized via the BACKEND_PORT and FRONTEND_PORT environment variables.

How do I deploy DeepTutor to a remote server with a public domain?

Set NEXT_PUBLIC_API_BASE_EXTERNAL in your .env file to the public HTTPS or HTTP address of your backend (e.g., https://api.example.com:8001). The start-frontend.sh script automatically injects this URL into the built frontend at container startup, allowing the browser to reach the backend across networks.

Can I run DeepTutor without Docker?

While the repository is optimized for Docker deployment, you can run the FastAPI backend directly with uvicorn and the Next.js frontend with npm start after manually installing dependencies and setting all required environment variables. However, the Docker approach is strongly recommended for production consistency.

How do I update my DeepTutor production deployment?

Pull the latest code changes, rebuild the image with docker compose build, and restart the containers with docker compose up -d. Your data persists in the mounted volumes defined in docker-compose.yml, so the update will not affect stored user data.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →