Update deployment with nginx+frontned

This commit is contained in:
Kohaku-Blueleaf
2025-10-04 00:52:08 +08:00
parent 3953311a6c
commit 7f713d6610
5 changed files with 111 additions and 11 deletions

View File

@@ -48,6 +48,7 @@ See [API.md](./API.md) for detailed API documentation and workflow diagrams.
### Prerequisites ### Prerequisites
- Docker and Docker Compose - Docker and Docker Compose
- Node.js and npm (or compatible package manager) for building the frontend
- Python 3.10+ (for testing with `huggingface_hub` client) - Python 3.10+ (for testing with `huggingface_hub` client)
- [Optional] - [Optional]
- S3 Storage (MinIO is default one which run with docker compose) - S3 Storage (MinIO is default one which run with docker compose)
@@ -89,16 +90,17 @@ environment:
The default setup exposes these ports: The default setup exposes these ports:
- `48888` - KohakuHub API (main interface) - `28080` - **KohakuHub Web UI (main user/API interface)**
- `48888` - KohakuHub API (for clients like `huggingface_hub`)
- `28000` - LakeFS Web UI + API - `28000` - LakeFS Web UI + API
- `29000` - MinIO Web Console - `29000` - MinIO Web Console
- `29001` - MinIO S3 API - `29001` - MinIO S3 API
- `25432` - PostgreSQL (optional, for external access) - `25432` - PostgreSQL (optional, for external access)
**For production deployment**, you should: **For production deployment**, you should:
1. **Only expose port 48888** (KohakuHub API) to users 1. **Only expose port 8080** (or 443 with HTTPS) to users.
2. Keep other ports internal or behind a firewall 2. The Web UI will proxy requests to the API. Keep other ports internal or behind a firewall.
3. Use a reverse proxy (nginx/traefik) with HTTPS 3. Use a reverse proxy (nginx/traefik) with HTTPS.
#### **Public Endpoint Configuration** #### **Public Endpoint Configuration**
@@ -120,17 +122,23 @@ The S3 public endpoint is used for generating download URLs. It should point to
export UID=$(id -u) export UID=$(id -u)
export GID=$(id -g) export GID=$(id -g)
# Start all services # Build Frontend and Start all services
docker compose up -d --build ./deploy.sh
## You can manually set them up
# npm install --prefix ./src/kohaku-hub-ui
# npm run build --prefix ./src/kohaku-hub-ui
# docker compose up -d --build
``` ```
Services will start in this order: Services will start in this order:
1. MinIO (S3 storage) 1. MinIO (S3 storage)
2. PostgreSQL (metadata database) 2. PostgreSQL (metadata database)
3. LakeFS (version control) 3. LakeFS (version control)
4. KohakuHub API (main application) 4. KohakuHub API (backend application)
5. **KohakuHub Web UI (Nginx, fronten + reverse proxy to API server)**
### 4. Verify Installation ### 5. Verify Installation
Check that all services are running: Check that all services are running:
@@ -139,11 +147,12 @@ docker compose ps
``` ```
Access the web interfaces: Access the web interfaces:
- **KohakuHub API**: http://localhost:48888/docs (API documentation) - **KohakuHub Web UI**: http://localhost:28080 (main interface, include API)
- **KohakuHub API Docs**: http://localhost:48888/docs (API documentation)
- **LakeFS Web UI**: http://localhost:28000 (repository browser) - **LakeFS Web UI**: http://localhost:28000 (repository browser)
- **MinIO Console**: http://localhost:29000 (storage browser) - **MinIO Console**: http://localhost:29000 (storage browser)
### 5. Test with Python Client ### 6. Test with Python Client
```bash ```bash
# Install the official HuggingFace client # Install the official HuggingFace client

4
deploy.sh Normal file
View File

@@ -0,0 +1,4 @@
npm install --prefix ./src/kohaku-hub-ui
npm run build --prefix ./src/kohaku-hub-ui
docker-compose up -d --build

View File

@@ -2,6 +2,18 @@
version: "3.9" version: "3.9"
services: services:
hub-ui:
image: nginx:alpine
container_name: hub-ui
restart: always
ports:
- "28080:80" # Expose Web UI on host port 28080
volumes:
- ./src/kohaku-hub-ui/dist:/usr/share/nginx/html # Mount the built frontend assets
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf # Mount the Nginx configuration
depends_on:
- hub-api
hub-api: hub-api:
build: . # Build the image from the Dockerfile in the current directory build: . # Build the image from the Dockerfile in the current directory
container_name: hub-api container_name: hub-api
@@ -27,7 +39,7 @@ services:
- KOHAKU_HUB_LAKEFS_ENDPOINT=http://lakefs:28000 - KOHAKU_HUB_LAKEFS_ENDPOINT=http://lakefs:28000
- KOHAKU_HUB_LAKEFS_REPO_NAMESPACE=hf - KOHAKU_HUB_LAKEFS_REPO_NAMESPACE=hf
## Application Configuration ## Application Configuration
- KOHAKU_HUB_BASE_URL=http://127.0.0.1:48888 - KOHAKU_HUB_BASE_URL=http://127.0.0.1:28080 # Web UI will proxy requests to hub-api, we use hub-ui url here
- KOHAKU_HUB_DB_BACKEND=postgres - KOHAKU_HUB_DB_BACKEND=postgres
- KOHAKU_HUB_DATABASE_URL=postgresql://hub:hubpass@postgres:5432/hubdb # Linking to the 'postgres' service - KOHAKU_HUB_DATABASE_URL=postgresql://hub:hubpass@postgres:5432/hubdb # Linking to the 'postgres' service
## SMTP Configuration (Email Verification - Optional) ## SMTP Configuration (Email Verification - Optional)

73
docker/nginx/default.conf Normal file
View File

@@ -0,0 +1,73 @@
server {
listen 80;
server_name localhost;
# Allow large client request bodies for file uploads in commits
client_max_body_size 100G;
# Root directory for the built Vue.js application
root /usr/share/nginx/html;
index index.html;
# =================================================================
# API PROXY RULES
#
# These specific locations are evaluated BEFORE the general SPA rule.
# The order of these proxy rules matters.
# =================================================================
# 1. Standard API prefixes (highest priority for matching)
location /api/ {
proxy_pass http://hub-api:48888;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /org/ {
proxy_pass http://hub-api:48888;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 2. Git LFS routes (critical for large file uploads/downloads)
# Matches URLs like /kohaku/test-2.git/info/lfs/objects/batch
location ~ \.git/info/lfs/ {
proxy_pass http://hub-api:48888;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 3. File resolution routes (for downloads)
# This is the most specific pattern and should be checked first.
# Matches /models/user/repo/resolve/...
location ~ ^/(models|datasets|spaces)/[^/]+/[^/]+/resolve/ {
proxy_pass http://hub-api:48888;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# This is the legacy pattern.
# Matches /user/repo/resolve/...
# By placing it after the more specific rule above, we avoid conflicts.
location ~ ^/[^/]+/[^/]+/resolve/ {
proxy_pass http://hub-api:48888;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# =================================================================
# FRONTEND SINGLE PAGE APP (SPA)
#
# This is the final fallback. If no API rule above matched,
# Nginx assumes it's a frontend route and serves the SPA.
# =================================================================
location / {
try_files $uri $uri/ /index.html;
}
}

View File

@@ -26,6 +26,8 @@ declare module 'vue' {
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: typeof import('element-plus/es')['ElSelect']
ElSkeleton: typeof import('element-plus/es')['ElSkeleton'] ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
HelloWorld: typeof import('./components/HelloWorld.vue')['default'] HelloWorld: typeof import('./components/HelloWorld.vue')['default']
MarkdownPage: typeof import('./components/common/MarkdownPage.vue')['default'] MarkdownPage: typeof import('./components/common/MarkdownPage.vue')['default']