github-sync-test / docs /github-hf-custom-domain-guide.md
billyaungmyint's picture
Sync from GitHub via hub-sync
f643bf9 verified
|
raw
history blame
7.57 kB
# 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
1. [Prerequisites](#1-prerequisites)
2. [Create the Hugging Face Space](#2-create-the-hugging-face-space)
3. [Configure the GitHub Repository](#3-configure-the-github-repository)
4. [Set Up the Sync Workflow](#4-set-up-the-sync-workflow)
5. [README Front Matter (Critical)](#5-readme-front-matter-critical)
6. [Custom Domain Setup](#6-custom-domain-setup)
7. [Gradio `root_path` Rule](#7-gradio-root_path-rule)
8. [Verify End-to-End](#8-verify-end-to-end)
9. [Troubleshooting Reference](#9-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
1. Go to https://huggingface.co/new-space
2. Fill in:
- **Owner**: your HF username or org
- **Space name**: e.g. `github-sync-test`
- **SDK**: Gradio (or Streamlit)
- **Visibility**: Public or Private
3. 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
1. GitHub repo β†’ **Settings** β†’ **Secrets and variables** β†’ **Actions**
2. Click **New repository secret**
- Name: `HF_TOKEN`
- Value: your HF write token from step 1
3. 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`:
```yaml
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".
```markdown
---
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
1. HF Space β†’ **Settings** β†’ **Custom domains**
2. Enter your domain: e.g. `demo.example.com`
3. HF shows you a **CNAME target** (looks like `billyaungmyint-github-sync-test.hf.space`)
4. 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_PATH` in HF Space variables.
- Leave it unset (or set to `""`).
- Setting it to the old `.hf.space` URL **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:
```python
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.com` resolves (no NXDOMAIN)
- [ ] `https://your-domain.com` loads the Space (no TLS error)
- [ ] Browser DevTools β†’ Network: no failed `/info` or `queue/join` requests
- [ ] 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) |