Skip to content

Commit ccbeab9

Browse files
pRizzclaude
andcommitted
feat(docker): add VOLUME directives, deployment docs, and docker-compose.yml
Fix mount persistence when the image is run directly (Railway, Docker Desktop, plain docker run) without the occ CLI. Add Dockerfile VOLUME directives for all 6 critical data paths so Docker creates anonymous volumes automatically. Add deployment documentation for Railway and Docker Desktop, a production-ready docker-compose.yml at the repo root, and deploy guide links in container logs for discoverability. Update existing DigitalOcean docs for consistency. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8cf1f62 commit ccbeab9

8 files changed

Lines changed: 555 additions & 2 deletions

File tree

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,35 @@ Quick deploy provisions a private EC2 instance behind a public ALB with HTTPS.
5353
Docs: `docs/deploy/aws.md` (includes teardown steps and S3 hosting setup for forks)
5454
Credentials: `docs/deploy/aws.md#retrieving-credentials`
5555

56+
## Deploy to Railway
57+
58+
<!-- TODO: Replace TEMPLATE_CODE with the actual Railway template code once the template is created. See docs/deploy/railway.md for template creation instructions. -->
59+
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/new/template/TEMPLATE_CODE)
60+
61+
One-click deploy provisions a Railway service with automatic HTTPS.
62+
63+
> **Important:** Attach a Railway Volume mounted to `/home/opencoder/.local/share/opencode` to prevent data loss across redeploys.
64+
65+
Docs: `docs/deploy/railway.md`
66+
67+
## Run with Docker / Docker Desktop
68+
69+
The fastest way to run opencode-cloud locally:
70+
71+
```bash
72+
docker compose up -d
73+
```
74+
75+
This uses the included `docker-compose.yml` which configures all persistent volumes automatically.
76+
77+
Retrieve the Initial One-Time Password (IOTP) and open `http://localhost:3000`:
78+
79+
```bash
80+
docker compose logs | grep -F "INITIAL ONE-TIME PASSWORD (IOTP): " | tail -n1 | sed 's/.*INITIAL ONE-TIME PASSWORD (IOTP): //'
81+
```
82+
83+
Docs: `docs/deploy/docker-desktop.md`
84+
5685
## Deploy to DigitalOcean (Coming Soon)
5786

5887
DigitalOcean Marketplace one-click deployment is not implemented yet. Support is coming soon.
@@ -113,6 +142,8 @@ docker pull ghcr.io/prizz/opencode-cloud-sandbox:latest
113142
occ start # Pulls or builds the image as needed
114143
```
115144

145+
**Running the image directly** (without the CLI)? Use Docker Compose or configure named volumes for persistence. See `docs/deploy/docker-desktop.md` for Docker Desktop / `docker run`, or `docs/deploy/railway.md` for Railway.
146+
116147
## Requirements
117148

118149
- **Rust 1.85+** - Install via [rustup](https://rustup.rs): `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`

docker-compose.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# opencode-cloud Docker Compose
2+
#
3+
# Quick start:
4+
# docker compose up -d
5+
#
6+
# This configures all persistent volumes automatically so your data
7+
# survives container restarts, updates, and recreation.
8+
#
9+
# First-time setup:
10+
# docker compose logs | grep "INITIAL ONE-TIME PASSWORD"
11+
# Open http://localhost:3000 and enter the IOTP to complete setup.
12+
#
13+
# Docs: https://github.com/pRizz/opencode-cloud
14+
15+
services:
16+
opencode:
17+
image: prizz/opencode-cloud-sandbox:latest
18+
container_name: opencode-cloud-sandbox
19+
restart: unless-stopped
20+
ports:
21+
- "127.0.0.1:3000:3000"
22+
environment:
23+
- OPENCODE_HOST=0.0.0.0
24+
volumes:
25+
- opencode-data:/home/opencoder/.local/share/opencode
26+
- opencode-state:/home/opencoder/.local/state/opencode
27+
- opencode-cache:/home/opencoder/.cache/opencode
28+
- opencode-workspace:/home/opencoder/workspace
29+
- opencode-config:/home/opencoder/.config/opencode
30+
- opencode-users:/var/lib/opencode-users
31+
32+
volumes:
33+
opencode-data:
34+
opencode-state:
35+
opencode-cache:
36+
opencode-workspace:
37+
opencode-config:
38+
opencode-users:

docs/deploy/digitalocean-droplet.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,13 @@ occ restart
223223

224224
## Path 2: Docker-only (Image Direct)
225225

226-
Use this if you don’t want `occ` installed on the Droplet.
226+
Use this if you don't want `occ` installed on the Droplet.
227+
228+
> **Tip:** You can also use `docker compose up -d` with the project's
229+
> [`docker-compose.yml`](https://raw.githubusercontent.com/pRizz/opencode-cloud/main/docker-compose.yml)
230+
> instead of manual `docker run` commands. The Docker image also declares
231+
> `VOLUME` directives for all critical paths, providing anonymous volume
232+
> fallback if you forget explicit `-v` flags.
227233
228234
### 1) Install Docker
229235

docs/deploy/docker-desktop.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# Docker Desktop / Docker CLI
2+
3+
Run opencode-cloud-sandbox locally using Docker Desktop (macOS, Windows, Linux)
4+
or the Docker CLI on any machine.
5+
6+
## Overview
7+
8+
What you get:
9+
10+
- **Sandboxed environment**: opencode runs inside the `prizz/opencode-cloud-sandbox` container
11+
- **Local access**: Web UI at `http://localhost:3000`
12+
- **Persistence**: Named volumes preserve your data across container restarts and updates
13+
14+
No cloud account or `occ` CLI installation is required.
15+
16+
## Quick Start (Docker Compose)
17+
18+
The project includes a `docker-compose.yml` that configures all persistent
19+
volumes automatically.
20+
21+
```bash
22+
# Clone or download docker-compose.yml from the repository root
23+
curl -O https://raw.githubusercontent.com/pRizz/opencode-cloud/main/docker-compose.yml
24+
25+
# Start the service
26+
docker compose up -d
27+
```
28+
29+
Retrieve the Initial One-Time Password (IOTP) from logs:
30+
31+
```bash
32+
docker compose logs | grep -F "INITIAL ONE-TIME PASSWORD (IOTP): " | tail -n1 | sed 's/.*INITIAL ONE-TIME PASSWORD (IOTP): //'
33+
```
34+
35+
Open `http://localhost:3000`, enter the IOTP, and complete first-time setup.
36+
37+
To stop:
38+
39+
```bash
40+
docker compose down
41+
```
42+
43+
To stop and remove volumes (data loss):
44+
45+
```bash
46+
docker compose down -v
47+
```
48+
49+
## Quick Start (Docker CLI)
50+
51+
### 1) Create named volumes
52+
53+
```bash
54+
docker volume create opencode-data
55+
docker volume create opencode-state
56+
docker volume create opencode-cache
57+
docker volume create opencode-workspace
58+
docker volume create opencode-config
59+
docker volume create opencode-users
60+
```
61+
62+
### 2) Run the container
63+
64+
```bash
65+
docker run -d --name opencode-cloud-sandbox \
66+
--restart unless-stopped \
67+
-p 127.0.0.1:3000:3000 \
68+
-e OPENCODE_HOST=0.0.0.0 \
69+
-v opencode-data:/home/opencoder/.local/share/opencode \
70+
-v opencode-state:/home/opencoder/.local/state/opencode \
71+
-v opencode-cache:/home/opencoder/.cache/opencode \
72+
-v opencode-workspace:/home/opencoder/workspace \
73+
-v opencode-config:/home/opencoder/.config/opencode \
74+
-v opencode-users:/var/lib/opencode-users \
75+
prizz/opencode-cloud-sandbox:latest
76+
```
77+
78+
Notes:
79+
80+
- Prefer a **pinned tag** (like `15.2.0`) for reproducible deployments.
81+
- See Docker Hub for tags: https://hub.docker.com/r/prizz/opencode-cloud-sandbox
82+
- Use `-p 3000:3000` instead of `-p 127.0.0.1:3000:3000` to expose on all
83+
network interfaces.
84+
85+
### 3) Complete first-time setup
86+
87+
Retrieve the IOTP from logs:
88+
89+
```bash
90+
docker logs opencode-cloud-sandbox 2>&1 | grep -F "INITIAL ONE-TIME PASSWORD (IOTP): " | tail -n1 | sed 's/.*INITIAL ONE-TIME PASSWORD (IOTP): //'
91+
```
92+
93+
Open `http://localhost:3000` and complete setup:
94+
95+
1. Enter the IOTP on the login page first-time setup panel
96+
2. Continue to passkey setup
97+
3. Either enroll a passkey for the default `opencoder` account, or use
98+
username/password fallback to create your first managed user
99+
100+
The IOTP is invalidated after successful enrollment.
101+
102+
## Quick Start (Docker Desktop GUI)
103+
104+
1. Open Docker Desktop
105+
2. Go to **Images** > search for `prizz/opencode-cloud-sandbox`
106+
3. Pull the image
107+
4. Click **Run** with these optional settings:
108+
- **Port**: map host port `3000` to container port `3000`
109+
5. The container starts with anonymous volumes for persistent data
110+
111+
> **Note:** Anonymous volumes created by Docker Desktop survive container
112+
> **restarts**, but are deleted if you remove the container. For durable
113+
> persistence, use Docker Compose or the CLI method above with named volumes.
114+
115+
To view logs, click the running container in Docker Desktop and open the
116+
**Logs** tab. Search for `INITIAL ONE-TIME PASSWORD` to find the IOTP.
117+
118+
## Persistence
119+
120+
### Volume Paths
121+
122+
The container uses these paths for persistent data:
123+
124+
| Path | Volume Name | Purpose |
125+
|------|-------------|---------|
126+
| `/home/opencoder/.local/share/opencode` | `opencode-data` | Session data, project storage |
127+
| `/home/opencoder/.local/state/opencode` | `opencode-state` | Application state |
128+
| `/home/opencoder/.cache/opencode` | `opencode-cache` | Cache data |
129+
| `/home/opencoder/workspace` | `opencode-workspace` | Project files |
130+
| `/home/opencoder/.config/opencode` | `opencode-config` | Configuration |
131+
| `/var/lib/opencode-users` | `opencode-users` | User accounts |
132+
133+
### What Survives What
134+
135+
| Scenario | Anonymous volumes | Named volumes |
136+
|----------|-------------------|---------------|
137+
| `docker restart` | Data preserved | Data preserved |
138+
| `docker stop` + `docker start` | Data preserved | Data preserved |
139+
| `docker rm` + `docker run` | **Data lost** | Data preserved |
140+
| Image update (`docker pull` + recreate) | **Data lost** | Data preserved |
141+
| `docker compose down` | Data preserved | Data preserved |
142+
| `docker compose down -v` | **Data lost** | **Data lost** |
143+
144+
**Recommendation:** Always use named volumes (via Docker Compose or `-v` flags)
145+
for data you want to keep.
146+
147+
### Anonymous Volume Fallback
148+
149+
The Docker image declares `VOLUME` directives for all six persistent paths.
150+
If you run the container without explicit `-v` flags (e.g., clicking "Run" in
151+
Docker Desktop), Docker creates anonymous volumes automatically. This protects
152+
against accidental data loss on container restarts, but anonymous volumes are
153+
deleted when the container is removed.
154+
155+
## Environment Variables
156+
157+
| Variable | Default | Notes |
158+
|----------|---------|-------|
159+
| `OPENCODE_HOST` | `0.0.0.0` | Must be `0.0.0.0` for Docker Desktop port forwarding to work |
160+
| `OPENCODE_PORT` | `3000` | Container port for the web UI |
161+
162+
## Updating
163+
164+
To update to a newer image version:
165+
166+
```bash
167+
# Docker Compose
168+
docker compose pull
169+
docker compose up -d
170+
171+
# Docker CLI
172+
docker pull prizz/opencode-cloud-sandbox:latest
173+
docker stop opencode-cloud-sandbox
174+
docker rm opencode-cloud-sandbox
175+
# Re-run with the same docker run command from step 2 above
176+
```
177+
178+
Named volumes persist across this process. Your data is preserved.
179+
180+
## Troubleshooting
181+
182+
### Port 3000 already in use
183+
184+
Another service is using port 3000. Change the host port:
185+
186+
```bash
187+
# Docker Compose: edit docker-compose.yml, change "127.0.0.1:3000:3000" to "127.0.0.1:8080:3000"
188+
# Docker CLI: use -p 127.0.0.1:8080:3000
189+
```
190+
191+
Then access via `http://localhost:8080`.
192+
193+
### Container exits immediately
194+
195+
Check logs for errors:
196+
197+
```bash
198+
docker logs opencode-cloud-sandbox
199+
```
200+
201+
Common causes:
202+
- Missing `OPENCODE_HOST=0.0.0.0` environment variable
203+
- Port conflict (see above)
204+
205+
### Permission errors on volumes (macOS)
206+
207+
Docker Desktop on macOS uses a Linux VM. Volume permissions are managed
208+
inside the VM and generally work without issues. If you encounter permission
209+
errors:
210+
211+
1. Ensure you are not mounting host directories that require special Docker
212+
Desktop file sharing settings
213+
2. Named volumes (recommended) avoid macOS file sharing issues entirely
214+
215+
### Data lost after container removal
216+
217+
You used anonymous volumes (Docker Desktop GUI "Run" button without
218+
configuring named volumes). Re-create the container using Docker Compose
219+
or the CLI method with named `-v` flags to prevent this in the future.

0 commit comments

Comments
 (0)