Spaces:
Running
Running
| # 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) | | |