Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Use CUDA devel base image so nvcc and headers are available for kernel compilation
FROM nvidia/cuda:13.3.1-devel-ubuntu26.04

ENV DEBIAN_FRONTEND=noninteractive \
PYTHONUNBUFFERED=1 \
CUDA_HOME=/usr/local/cuda \
PATH="/opt/venv/bin:/usr/local/cuda/bin:$PATH" \
LD_LIBRARY_PATH="/usr/local/cuda/lib64:$LD_LIBRARY_PATH" \
CPATH="/usr/local/cuda/include:$CPATH" \
LIBRARY_PATH="/usr/local/cuda/lib64:$LIBRARY_PATH"

# Install build prerequisites and git
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
ninja-build \
git \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# Install uv binary
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

WORKDIR /app

# Provision Python 3.11/3.12 virtualenv via uv (avoids Python 3.14 ABI incompatibilities)
RUN uv venv /opt/venv --python 3.11 && \
uv pip install --no-cache "setuptools<70.0.0" wheel torch ninja && \
uv pip install --no-cache "freetoken[accel]"

EXPOSE 1919

ENTRYPOINT ["ft", "serve"]
CMD ["--host", "0.0.0.0", "--port", "1919"]
27 changes: 27 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
services:
freetoken:
image: freetoken:latest
container_name: freetoken-server
ipc: host
ports:
- "1919:1919"
environment:
- HF_TOKEN=${HF_TOKEN:-}
- HF_HOME=/root/.cache/huggingface
volumes:
- ~/.cache/huggingface:/root/.cache/huggingface
command:
- "--model"
- "${MODEL_NAME:-Qwen/Qwen3.6-35B-A3B}"
- "--host"
- "0.0.0.0"
- "--port"
- "1919"
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
restart: unless-stopped
151 changes: 151 additions & 0 deletions docs/docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Running FreeToken with Docker & Docker Compose

This guide explains how to build, configure, and serve LLMs using FreeToken in a GPU-accelerated Docker container with automatic Hugging Face model downloading.

---

## Prerequisites

- **NVIDIA GPU** with Pascal architecture or newer (Hopper, Ada Lovelace, Ampere, Turing supported).
- **NVIDIA Driver**: Recommended `r580+` (or latest CUDA-compatible driver).
- **Docker Engine** (24.0+) & **Docker Compose** (v2+).
- **NVIDIA Container Toolkit** installed and configured as the default Docker runtime.

Verify GPU passthrough is working before proceeding:
```bash
docker run --rm --gpus all nvidia/cuda:13.3.1-base-ubuntu26.04 nvidia-smi
```

---

## Project Structure

Ensure the following files are in your project directory:

```text
.
├── Dockerfile
├── docker-compose.yml
├── .env # Optional: override default models & tokens
└── DOCKER_README.md
```

---

## 1. Build the Docker Image

Build the image locally and tag it as `freetoken:latest`:

```bash
docker build -t freetoken:latest .
```

---

## 2. Configuration (`.env`)

Create a `.env` file in the same directory to configure your model and credentials:

```env
# Required only for gated/private models (e.g., meta-llama/Llama-3.1-8B-Instruct)
HF_TOKEN=hf_your_token_here

# Hugging Face model repository ID
MODEL_NAME=Qwen/Qwen3.6-35B-A3B
```

---

## 3. Running with Docker Compose

### Start the Service
```bash
docker compose up -d
```

### View Logs & Download Progress
FreeToken downloads weights directly to the mounted Hugging Face cache on the host (`~/.cache/huggingface`):
```bash
docker compose logs -f freetoken
```

Wait until you see:
```text
API server is ready to serve on 0.0.0.0:1919
```

### Stop the Service
```bash
docker compose down
```

---

## 4. Alternative: Running via `docker run` (CLI)

If you prefer running a standalone container without Compose:

```bash
docker run -d \
--name freetoken-server \
--gpus all \
--ipc=host \
-p 1919:1919 \
-e HF_TOKEN="${HF_TOKEN}" \
-e HF_HOME="/root/.cache/huggingface" \
-v ~/.cache/huggingface:/root/.cache/huggingface \
freetoken:latest \
--model "Qwen/Qwen3.6-35B-A3B" \
--host 0.0.0.0 \
--port 1919
```

---

## 5. Testing the API

FreeToken exposes an OpenAI-compatible HTTP API on port `1919`.

### OpenAI-Compatible Chat Completion (`curl`)

```bash
curl [http://127.0.0.1:1919/v1/chat/completions](http://127.0.0.1:1919/v1/chat/completions) \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen2.5-Coder-32B-Instruct",
"messages": [
{"role": "system", "content": "You are a helpful coding assistant."},
{"role": "user", "content": "Write a quick Python script to calculate Fibonacci numbers."}
],
"temperature": 0.7,
"max_tokens": 512
}'
```

### Python Client Example (`openai` SDK)

```python
from openai import OpenAI

client = OpenAI(
base_url="http://localhost:1919/v1",
api_key="none"
)

response = client.chat.completions.create(
model="Qwen/Qwen2.5-Coder-32B-Instruct",
messages=[
{"role": "user", "content": "Explain KV caching in two sentences."}
]
)

print(response.choices[0].message.content)
```

---

## 6. Performance & Troubleshooting Notes

- **`ipc: host`**: Required. High-performance LLM engines use shared memory (`/dev/shm`) for multi-worker communication and KV cache transfers. Omitting this can cause immediate `Bus error` or `CUDA OOM` crashes.
- **Persistent Cache**: Model weights are stored in `~/.cache/huggingface` on the host machine. Subsequent runs will load from disk instantly without re-downloading.
- **Custom Model Paths**: To load local safetensors or GGUF files instead of downloading from Hugging Face, mount your local directory into the container (e.g., `-v /path/to/models:/models`) and set `--model /models/your-model-folder`.