Spaces:
Sleeping
Sleeping
File size: 8,474 Bytes
5bd2d41 930c3ef e85a4d4 5bd2d41 e1f9a64 5bd2d41 930c3ef 5bd2d41 e1f9a64 5bd2d41 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | ---
title: OpenCode Cloud
emoji: π€
colorFrom: gray
colorTo: indigo
sdk: docker
app_port: 7860
pinned: false
license: mit
---
# opencode-cloud
Run [opencode](https://opencode.ai) β an open source AI coding agent β as a hosted
server you reach from a browser, from the desktop app, or from a local build of the
web app. One Dockerfile, deployable to **Hugging Face Spaces** or **Railway**.
`opencode serve` is not just an API: the server also serves the web UI on its
catch-all route, so opening the deployment URL gives you the full app, same-origin.
---
## Deploy on Hugging Face Spaces
1. **Create a Space** β SDK **Docker**, blank template. Push this repo to it
(or duplicate an existing Space built from it).
2. **Settings β Variables and secrets** and add:
| Secret | Required | Notes |
|---|---|---|
| `OPENCODE_SERVER_PASSWORD` | **yes** | The container refuses to start without it. This is the only thing protecting a shell. |
| `OPENCODE_SERVER_USERNAME` | no | Defaults to `opencode`. |
| `OPENCODE_API_KEY` | pick β₯1 | [opencode zen](https://opencode.ai/zen) curated models |
| `ANTHROPIC_API_KEY` | pick β₯1 | https://console.anthropic.com |
| `OPENAI_API_KEY` | pick β₯1 | https://platform.openai.com/api-keys |
| `GEMINI_API_KEY` | pick β₯1 | https://aistudio.google.com/apikey |
3. Open the Space URL and log in with `opencode` + your password.
Provider keys work as plain env vars β opencode registers any provider whose
models.dev env var is present, no login step needed.
### Persistence
Free Spaces are **ephemeral** and are stopped after ~48h idle. Sessions, provider
logins and any uncommitted code are lost on restart. Two options:
- **Free:** `git clone` your repo into the workspace and push before you walk away.
- **Paid:** enable persistent storage (Settings β Storage). It mounts at `/data`,
which `entrypoint.sh` detects and uses for the XDG dirs *and* the workspace, so
state survives restarts. Watch the boot log β it prints which mode it picked.
### Public or private Space?
A **private** Space adds your HF login in front of everything, which is the safer
default for browser use. The catch: HF authenticates private Spaces with an
`Authorization: Bearer hf_β¦` header, and opencode wants `Authorization: Basic β¦` β
one header, two claimants. So a private Space works in a browser (HF session
cookie) but a **desktop-app or local-app connection to a private Space will fight
over that header**. Keep the Space public with a long password if you want those.
---
## Deploy on Railway
```bash
railway init # or point a service at this GitHub repo
railway variables --set OPENCODE_SERVER_PASSWORD=...
railway up
```
Railway injects `$PORT`, which `entrypoint.sh` uses automatically. Attach a volume
with mount path `/data` for persistence. Details and caveats: [docs/RAILWAY.md](docs/RAILWAY.md).
---
## Run as a GitHub Codespace
```
Code -> Codespaces -> Create codespace on main
```
Set `OPENCODE_SERVER_PASSWORD` first, as a **Codespaces** secret β repository secrets
and Actions secrets are separate and are not visible here:
```bash
gh secret set OPENCODE_SERVER_PASSWORD --app codespaces --repo OWNER/REPO
```
`.devcontainer/devcontainer.json` builds the same Dockerfile, forwards 7860 publicly and
starts the server on `postStartCommand`. Public is safe only because `entrypoint.sh` refuses
to start without a password; without the secret the codespace comes up with no server and the
reason is in `/tmp/opencode.log`.
Unlike a Space or a Railway service, a codespace **stops after 30 minutes idle** (240 maximum).
It keeps its disk and restarts under the same name and URL, and `postStartCommand` boots the
server again β but it is not always-on, and GitHub deletes a stopped codespace after the
retention period, up to 30 days. State lives under `/workspaces/.opencode-state`, so it
survives a stop and is lost only with the codespace itself.
A personal Free account includes 120 core-hours a month, which is roughly 60 hours of wall
clock on a 2-core machine; the idle timeout is what keeps that from draining.
---
## Keeping the Space in sync with GitHub
`.github/workflows/sync-to-hf-space.yml` builds the image, boots it, checks that
it refuses to start unauthenticated and that it serves an authenticated API and
the web UI β and only then force-pushes `main` to the Space and waits for it to
report `RUNNING`. A broken Dockerfile fails on the runner instead of leaving the
Space stuck in `BUILD_ERROR`.
Configure it under **Settings β Secrets and variables β Actions**:
| Name | Kind | Notes |
|---|---|---|
| `HF_TOKEN` | **secret** | A Hugging Face **write** token. The HF username is derived from it, so it is the only secret needed. |
| `HF_SPACE` | variable | `owner/space-name`. Optional β defaults to this GitHub repo's `owner/name`. A public Space id isn't sensitive, so a variable keeps it readable in logs; a secret of the same name also works. |
GitHub is the source of truth: the sync **force-pushes**, so a commit made only
in the Space's web UI will be discarded. Edit here, not there.
---
## Connecting the desktop app or a local web app
You don't have to use the in-browser UI. In the app, **Settings β Servers β Add**
and enter the deployment URL plus the username/password. The server's CORS
allowlist already covers `localhost`, `*.opencode.ai` and the desktop app's
`oc://renderer` origin, so no extra flags are needed. Only a frontend you host on
your own domain needs `OPENCODE_CORS_ORIGINS=https://your.domain`.
---
## Giving the agent Hugging Face access
Set `HF_TOKEN` as a Space secret (or Railway variable) and the agent can create
and manage Hugging Face repos: the official `hf` CLI is installed in the image,
it picks the token up from the environment with no login step, and `entrypoint.sh`
installs [`agents/hf-spaces.md`](agents/hf-spaces.md) as opencode's global
`AGENTS.md` so the agent knows the recipes. With no `HF_TOKEN` set, that file is
removed and nothing advertises the capability.
> **This hands your HF account to whoever can reach the server.** A standard HF
> write token covers every repo the account can write to β including org repos β
> so the blast radius is much larger than "a shell in a container". Two things
> make it meaningfully safer:
>
> - Use a **fine-grained token** scoped to just the permissions you need (write
> access to Spaces, say) rather than an account-wide write token.
> - Remember the agent reads untrusted content β repos, web pages, issue text.
> Anything it reads can try to talk it into using the token. The instructions
> tell it never to print the token, but that is a speed bump, not a boundary.
---
## Read this before you deploy
- **This is a remote shell.** Every route allows command execution and file
read/write in the container. Basic auth over HTTPS is the entire security model,
so use a long random password, and think twice about what credentials you put in
the container alongside it.
- **Provider OAuth "login with browser" flows don't work on a remote server.**
They bind a `http://localhost:<port>/auth/callback` listener *inside* the
container, so your browser is redirected to your own machine instead. Use API
keys.
- **CPU only, and modest.** Fine for the agent; you can't run local models.
- **Check the host's terms.** A general-purpose remote shell is not the ML-demo
use case Spaces are described for; a public one with a weak password is the way
to get flagged.
---
## Environment variables
| Variable | Default | Purpose |
|---|---|---|
| `OPENCODE_SERVER_PASSWORD` | β | **Required.** Basic auth password. |
| `OPENCODE_SERVER_USERNAME` | `opencode` | Basic auth username. |
| `PORT` | `7860` | Listen port. Railway sets this; HF must match `app_port`. |
| `OPENCODE_STATE_ROOT` | `/data` | Where to look for a writable volume. Codespaces sets `/workspaces/.opencode-state`. |
| `OPENCODE_WORKSPACE` | `$STATE_ROOT/workspace` or `$HOME/workspace` | Directory to serve. |
| `OPENCODE_CORS_ORIGINS` | β | Comma-separated extra CORS origins. |
| `HF_TOKEN` | β | Optional. A Hugging Face token, which lets the agent create and manage HF repos with the bundled `hf` CLI. See the warning below. |
Build arg `OPENCODE_VERSION` pins a release (default: latest).
---
MIT. opencode itself is Β© Anomaly Innovations; this repo is deployment wrapper code.
|