# Deploying OncoDSL Lab on Hugging Face Spaces (free, password gated) This hosts the whole Lab (engine + front end) at a free, always reachable link, behind a password. Co-founders open the link, enter the password, and can run searches themselves. One `Dockerfile` builds a single image that runs the FastAPI engine, the Next.js front end, and a Caddy reverse proxy. Caddy serves the front end, forwards `/api` to the engine, and puts a password on everything. The front end is built to call `/api` on the same origin, so there is no cross-URL wiring. The processed data (including the sealed gene map) is uploaded into the Space, so it lives on Hugging Face: that is the tradeoff of hosting it. The free CPU Space is 2 vCPU and 16 GB RAM, which is plenty for the engine. It does go to sleep when idle and wakes on the next visit (a short cold start), which is fine for co-founders dropping in now and then. ## 1. Create the Space On huggingface.co: New Space -> pick a name -> SDK **Docker** (blank template) -> visibility **Public** (the password, not the visibility, is what keeps it private). This creates a Space with its own README that already declares it a Docker app on port 7860. Leave that README alone. ## 2. Upload the app + data Install the Hugging Face CLI and log in (create a token at huggingface.co/settings/tokens, "write" scope): ``` pip install -U huggingface_hub hf auth login ``` If `hf` is "command not found", the pip scripts folder is not on your PATH; add it (adjust the Python version if needed) and retry: ``` export PATH="$HOME/Library/Python/3.12/bin:$PATH" ``` (The old `huggingface-cli` command is deprecated and no longer works; use `hf`.) From the repo root, upload everything except the heavy or unneeded folders. This auto-handles large files, so the parquet data goes up without any git or LFS setup. Replace USER/SPACE with your Space id: ``` hf upload USER/SPACE . --repo-type=space \ --exclude ".git/*" \ --exclude ".venv/*" \ --exclude "web/node_modules/*" \ --exclude "web/.next/*" \ --exclude "data/raw*" \ --exclude "**/__pycache__/*" \ --exclude "README.md" \ --exclude "OncoDSL_cover_note.docx" ``` Excluding `README.md` keeps the Space's Docker README from step 1. Everything the build needs (the Dockerfile, `deploy/`, the code, and `data/processed*`) is included. ## 3. Set the password In the Space: Settings -> Variables and secrets -> New secret, twice: - `LAB_USER` = `team` (or any username) - `LAB_PASSWORD_HASH` = a bcrypt hash of your chosen password Make the hash with Python (no Docker needed): ``` pip install bcrypt python -c "import bcrypt; print(bcrypt.hashpw(b'CHOOSE-A-PASSWORD', bcrypt.gensalt()).decode())" ``` Paste the printed hash (it starts with `$2`) as the `LAB_PASSWORD_HASH` secret. After setting secrets, hit "Restart this Space" (or Factory rebuild) so they take effect. ## 4. Share it The Space builds automatically (first build takes several minutes). When it is running, the link is `https://huggingface.co/spaces/USER/SPACE`, and the live app is the embedded view (or the "Open in new tab" arrow). Send co-founders that link plus the username (`team`) and password. ## Updating after you change the engine or UI Re-run the same upload command from the repo root: ``` hf upload USER/SPACE . --repo-type=space \ --exclude ".git/*" \ --exclude ".venv/*" \ --exclude "web/node_modules/*" \ --exclude "web/.next/*" \ --exclude "data/raw*" \ --exclude "**/__pycache__/*" \ --exclude "README.md" \ --exclude "OncoDSL_cover_note.docx" ``` It uploads only what changed and the Space rebuilds. The data stays out of your git repo entirely. (If you prefer literal `git push`, the Space is also a git remote; the upload command is just the simplest way in.) ## Notes to pass on to co-founders - The first visit after it has been idle takes a short while to wake up. - A search takes a few minutes and uses real CPU, so run one at a time. ## Fly.io alternative (paid, always warm) The same image runs on Fly.io if you ever want no cold starts. Fly needs a credit card and costs a few dollars a month. Use the included `fly.toml`: `fly apps create NAME`, `fly secrets set LAB_USER=team LAB_PASSWORD_HASH='' -a NAME`, then `fly deploy -a NAME`.