Spaces:
Running
A newer version of the Gradio SDK is available: 6.14.0
GitHub β Hugging Face Space with Custom Domain β Setup Guide
A complete, repeatable playbook. Follow in order. Sections marked β οΈ are the common pitfall spots.
Table of Contents
- Prerequisites
- Create the Hugging Face Space
- Configure the GitHub Repository
- Set Up the Sync Workflow
- README Front Matter (Critical)
- Custom Domain Setup
- Gradio
root_pathRule - Verify End-to-End
- Troubleshooting Reference
1. Prerequisites
| What | Where to get it |
|---|---|
| Hugging Face account | https://huggingface.co |
| HF write token (fine-grained or classic) | HF β Settings β Access Tokens β New token β Role: Write |
| GitHub repo (public or private) | github.com |
| Domain registrar access (for custom domain) | Your registrar (Cloudflare, Namecheap, etc.) |
2. Create the Hugging Face Space
- Go to https://huggingface.co/new-space
- Fill in:
- Owner: your HF username or org
- Space name: e.g.
github-sync-test - SDK: Gradio (or Streamlit)
- Visibility: Public or Private
- Click Create Space β the Space is created with a default
README.md.
You do not need to push any code manually; the GitHub Action will do it.
3. Configure the GitHub Repository
3.1 Add the HF token as a GitHub Secret
- GitHub repo β Settings β Secrets and variables β Actions
- Click New repository secret
- Name:
HF_TOKEN - Value: your HF write token from step 1
- Name:
- Save.
3.2 Minimum required files
your-repo/
βββ README.md β MUST have HF front matter (see Β§5)
βββ main.py β your Gradio app entry point
βββ requirements.txt β at minimum: gradio>=5.0
βββ .github/
βββ workflows/
βββ sync.yml
4. Set Up the Sync Workflow
Create .github/workflows/sync.yml:
name: Sync to Hugging Face
on:
push:
branches: [master] # or "main" β match your default branch
workflow_dispatch: # allows manual trigger from GitHub UI
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history required by hub-sync
lfs: true
- name: Write VERSION file
run: echo "${{ github.sha }}" > VERSION
- uses: huggingface/hub-sync@main
with:
github_repo_id: YOUR_GH_USERNAME/YOUR_GH_REPO
huggingface_repo_id: YOUR_HF_USERNAME/YOUR_SPACE_NAME
repo_type: space # MUST be "space" for HF Spaces
hf_token: ${{ secrets.HF_TOKEN }}
Replace YOUR_GH_USERNAME/YOUR_GH_REPO and YOUR_HF_USERNAME/YOUR_SPACE_NAME with your actual values.
5. README Front Matter (Critical)
β οΈ The single most common cause of sync failures.
The README.md at the repo root must start with this YAML front matter block. Without it, HF rejects the push with "Missing configuration in README".
---
title: your-space-name
emoji: "π€"
colorFrom: blue
colorTo: indigo
sdk: gradio
app_file: main.py
pinned: false
---
# Your Space Title
...rest of your README...
| Field | Notes |
|---|---|
title |
Must match (or at least not conflict with) your HF Space name |
sdk |
gradio or streamlit |
app_file |
The Python file that launches your app (e.g. main.py) |
emoji, colorFrom, colorTo |
Cosmetic β any valid values work |
pinned |
true pins the Space on your profile |
6. Custom Domain Setup
6.1 Add the domain in HF Space settings
- HF Space β Settings β Custom domains
- Enter your domain: e.g.
demo.example.com - HF shows you a CNAME target (looks like
billyaungmyint-github-sync-test.hf.space) - Copy that CNAME target value.
6.2 Add the DNS record at your registrar
| Type | Host | Value | TTL |
|---|---|---|---|
CNAME |
demo (subdomain part only) |
billyaungmyint-github-sync-test.hf.space |
300 or Auto |
If you want an apex/root domain (
example.com), use a CNAME Flattening or ALIAS record β check your registrar's docs. Most registrars support this via Cloudflare's "CNAME at root" feature.
6.3 Wait for DNS propagation
- Typical: 1β5 minutes on Cloudflare, up to 48 hours on others.
- Verify with:
nslookup demo.example.comβ should resolve to HF's servers. - HF will automatically provision a TLS certificate once the CNAME resolves.
6.4 β οΈ No GRADIO_ROOT_PATH needed
When using a custom domain at the root path (e.g. https://demo.example.com):
- Do not set
GRADIO_ROOT_PATHin HF Space variables. - Leave it unset (or set to
""). - Setting it to the old
.hf.spaceURL after a domain change causes"Could not get API info. fetch failed".
Only set GRADIO_ROOT_PATH if your app is served at a subpath, e.g. https://example.com/myapp β set GRADIO_ROOT_PATH=/myapp.
7. Gradio root_path Rule
Use this pattern in your main.py β it is safe for all scenarios:
import os
if __name__ == "__main__":
# Strip trailing slash to avoid double-slash issues.
# Leave GRADIO_ROOT_PATH unset (or "") for custom domains at root.
_root_path = os.getenv("GRADIO_ROOT_PATH", "").rstrip("/")
demo.launch(server_name="0.0.0.0", root_path=_root_path)
| Deployment scenario | GRADIO_ROOT_PATH env var value |
|---|---|
Default .hf.space URL |
(unset) or "" |
Custom domain at root (myapp.com) |
(unset) or "" |
Custom domain at subpath (myapp.com/demo) |
/demo |
| Local dev | (unset) β runs fine |
8. Verify End-to-End
Run through this checklist after initial setup or after any DNS/domain change:
-
nslookup your-domain.comresolves (no NXDOMAIN) -
https://your-domain.comloads the Space (no TLS error) - Browser DevTools β Network: no failed
/infoorqueue/joinrequests - Push a trivial commit to GitHub β Action runs green β Space rebuilds β change appears
- HF Space settings β Custom domains β Status shows β (not "Pending")
9. Troubleshooting Reference
| Error | Cause | Fix |
|---|---|---|
Missing configuration in README |
README has no HF YAML front matter | Add the front matter block (see Β§5) |
Could not get API info. fetch failed |
GRADIO_ROOT_PATH set to wrong URL, or DNS not yet propagated |
Clear GRADIO_ROOT_PATH in Space variables (see Β§6.4 & Β§7) |
HF_TOKEN secret not found / 401 |
Secret missing or token lacks write scope | Re-add secret with a Write token (see Β§3.1) |
Action fails: repo_type: space error |
Wrong repo_type in workflow |
Set repo_type: space in sync.yml (see Β§4) |
| Space stuck on "Building" | Dependency error in requirements.txt |
Check Space build logs; pin a working version |
| TLS certificate "Pending" for >30 min | CNAME not propagated yet or wrong target | Verify CNAME value matches exactly what HF shows |
| Custom domain works but assets 404 | root_path set to a subpath that doesn't exist |
Set GRADIO_ROOT_PATH="" or the correct subpath |
| Space rebuilds but shows old code | fetch-depth: 0 missing in workflow |
Add fetch-depth: 0 to actions/checkout@v4 (see Β§4) |
API Error / ValueError: API key is missing |
Secrets added to GitHub but missing in HF Space | Add API keys directly in HF Space β Settings β Variables and secrets |
10. Using this Template for AI Projects
This repository is designed as a ready-to-use template for future projects, coming with a pre-built Multi-Provider AI Chat Application in main.py.
Built-in Features
- Multi-Provider Backend: Supports Hugging Face (z.ai), Google Gemini, GitHub Models, OpenRouter, and Fireworks.
- Dynamic UI Selection: Gradio UI dropdowns to select providers and dynamically updated models natively without code edits.
- Cost-Optimization Presets: Select quick presets like Ultra Cheap, Budget Dev, Balanced, and Quality Check to auto-configure cost-effective development environments.
- Automatic Fallback: Specify
autoas the backend to automatically cycle through fallback providers if one fails (configured viaAI_FALLBACK_ORDER).
Environment Variables
β οΈ Important Pitfall: GitHub Action secrets do not automatically sync to Hugging Face Space secrets. While HF_TOKEN must be a GitHub Secret for CI/CD, runtime API keys must be added directly to Hugging Face.
1. GitHub Action Secrets (For Sync Only)
HF_TOKEN: Hugging Face write token (Required forhub-syncto work)
2. Hugging Face Space Secrets (For Runtime) Configure these in your HF Space via Settings β Variables and secrets:
HF_TOKEN: Hugging Face token (if you want the space itself to make authenticated HF API calls)GOOGLE_API_KEY: API key for Gemini modelsGITHUB_TOKEN: API key for GitHub ModelsOPENROUTER_API_KEY: API key for OpenRouterFIREWORKS_API_KEY: API key for Fireworks
(Note: For local development, you can place these in a .env file or export them in your terminal).
You can further customize defaults and available choices by setting:
AI_BACKEND: Default provider (e.g.,hf,google,github,auto)<PROVIDER>_MODEL: Default model for the provider (e.g.,GOOGLE_MODEL=gemini-2.0-flash-lite)<PROVIDER>_MODELS: Comma-separated list for model dropdown choices (e.g.,GOOGLE_MODELS=gemini-2.0-flash-lite,gemini-1.5-flash)