Skip to content

Commit 7eaf004

Browse files
authored
Run Docker web container with nginx (#721)
* WIP * Allow running docker web independently, update docs * Move return later * Remove graphql nginx
1 parent 5c063da commit 7eaf004

5 files changed

Lines changed: 161 additions & 43 deletions

File tree

DOCKER.md

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
# Docker Build and Run Guide
22

3-
This guide explains how to build and run the In the Loop frontend using Docker.
3+
This guide explains how to build and run In the Loop services using Docker.
44

55
## Overview
66

7-
The Docker image builds the production frontend and serves it using Vite's preview server.
7+
In the Loop consists of three Docker services:
8+
9+
- **web**: Production frontend served via nginx
10+
- **sync**: Backend API and WebSocket sync service (Cloudflare Worker)
11+
- **iframe-outputs**: Sandboxed output rendering service
812

913
## Prerequisites
1014

@@ -51,9 +55,7 @@ The services communicate via the `intheloop-network` Docker network:
5155

5256
## Testing Images Individually
5357

54-
The main issue is the `web` Docker image needing access to `localhost:8787`. Docker won't be able to access ports on the host machine. If you want to run it, the easiest way is to also run the `sync` image in Docker.
55-
56-
Otherwise, you can test these images individually to make sure they're working.
58+
You can build and run individual services for testing. The `web` service requires the `sync` service to be accessible.
5759

5860
### Building and Running Individual Images
5961

@@ -65,13 +67,30 @@ Build the web image:
6567
docker build -f Dockerfile.web -t intheloop-web:latest .
6668
```
6769

68-
Run the web service:
70+
**Running with docker-compose (recommended):**
71+
72+
The web service automatically connects to the `sync` service via Docker network DNS:
6973

7074
```shell
71-
docker run -p 5173:5173 intheloop-web:latest
75+
docker compose up web
7276
```
7377

74-
The web service will be available at `http://localhost:5173`. Note that it expects the sync service to be available at `http://sync:8787` (when running in docker-compose) or you'll need to configure the `VITE_API_TARGET` environment variable.
78+
**Running standalone:**
79+
80+
When running standalone, you need to specify where the sync service is located using the `SYNC_HOST` environment variable:
81+
82+
```shell
83+
# If sync is running on host machine (Mac/Windows)
84+
docker run -p 5173:5173 -e SYNC_HOST=host.docker.internal intheloop-web:latest
85+
86+
# If sync is running on host machine (Linux)
87+
docker run -p 5173:5173 -e SYNC_HOST=172.17.0.1 intheloop-web:latest
88+
89+
# If sync is running in another Docker container with a known IP
90+
docker run -p 5173:5173 -e SYNC_HOST=<container-ip> intheloop-web:latest
91+
```
92+
93+
The web service will be available at `http://localhost:5173`. By default, `SYNC_HOST` is set to `sync` (for docker-compose usage).
7594

7695
#### Iframe Outputs Service
7796

@@ -104,3 +123,29 @@ docker run -p 8787:8787 intheloop-sync:latest
104123
```
105124

106125
The sync service will be available at `http://localhost:8787`.
126+
127+
## Environment Variables
128+
129+
### Web Service
130+
131+
- `SYNC_HOST` (default: `sync`): Hostname or IP address of the sync service. Used by nginx to proxy API requests. Set to `sync` for docker-compose, or override for standalone runs.
132+
133+
### Sync Service
134+
135+
The sync service uses environment variables from `.dev.vars` file. See `.dev.vars.example` for configuration options.
136+
137+
## Troubleshooting
138+
139+
### "host not found in upstream 'sync'"
140+
141+
This error occurs when running the web container standalone without setting `SYNC_HOST`. Either:
142+
143+
1. Use docker-compose to run all services together, or
144+
2. Set `SYNC_HOST` environment variable when running the web container standalone
145+
146+
### Web service can't connect to sync service
147+
148+
- Verify the sync service is running and accessible
149+
- Check that `SYNC_HOST` is set correctly for your environment
150+
- On Linux, you may need to use the Docker bridge IP (`172.17.0.1`) instead of `host.docker.internal`
151+
- Ensure both containers are on the same Docker network if running separately

Dockerfile.web

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,52 @@
1-
# Single-stage Dockerfile for In the Loop
2-
# Copies source files and runs the dev server
3-
4-
FROM node:23-alpine
1+
# syntax=docker/dockerfile:1.4
2+
# Build stage
3+
FROM node:23-alpine AS builder
54
RUN apk add --no-cache bash git && corepack enable && corepack prepare pnpm@latest --activate
65
WORKDIR /app
76

8-
# ---
9-
# Install dependencies
10-
# ---
11-
12-
# Copy package files first
7+
# Copy workspace files
138
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
9+
10+
# Copy package.json files for all packages
1411
COPY packages/agent-core/package.json ./packages/agent-core/
1512
COPY packages/ai-core/package.json ./packages/ai-core/
1613
COPY packages/pyodide-runtime/package.json ./packages/pyodide-runtime/
1714
COPY packages/schema/package.json ./packages/schema/
1815

19-
# Install dependencies
20-
RUN pnpm install --no-frozen-lockfile
21-
22-
# ---
23-
# Copy source files
24-
# ---
25-
26-
# Copy everything else (filtered by .dockerignore)
27-
COPY . .
28-
29-
# Override env files from examples
30-
COPY .env.example .env
31-
COPY .dev.vars.example .dev.vars
16+
# Install dependencies with cache mount
17+
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
18+
pnpm install --frozen-lockfile
3219

33-
# ---
34-
# Set environment variables
35-
# ---
20+
# Copy source files needed for build
21+
COPY packages ./packages
22+
COPY src ./src
23+
COPY public ./public
24+
COPY vite.config.ts tsconfig.json tsconfig.node.json ./
25+
COPY index.html ./
26+
COPY vite-plugins ./vite-plugins
3627

3728
# Set git commit hash to avoid git commands in container
3829
ENV VITE_GIT_COMMIT_HASH=docker-build
3930
ENV VITE_API_TARGET=http://sync:8787
40-
ENV VITE_HOST=0.0.0.0
4131

42-
# ---
43-
# Run server
44-
# ---
32+
# Build the web app
33+
RUN pnpm build
4534

46-
# Expose port
47-
EXPOSE 5173
35+
# Production stage
36+
FROM nginx:alpine
37+
38+
# Copy built files from builder stage
39+
COPY --from=builder /app/dist /usr/share/nginx/html
40+
41+
# Copy nginx configuration
42+
COPY nginx-main.conf /etc/nginx/nginx.conf
43+
# Copy as template - nginx:alpine automatically processes templates in /etc/nginx/templates/
44+
COPY nginx.conf /etc/nginx/templates/default.conf.template
4845

49-
# Keep container running for debugging/SSH access
50-
# CMD ["tail", "-f", "/dev/null"]
46+
# Set default SYNC_HOST (can be overridden at runtime)
47+
ENV SYNC_HOST=sync
48+
49+
# Expose port 5173
50+
EXPOSE 5173
5151

52-
# Run dev server
53-
CMD ["pnpm", "run", "dev:web", "--port", "5173"]
52+
# nginx:alpine entrypoint automatically processes templates and starts nginx

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,32 @@ Learn more about [what works today](./docs/what-works-today.md).
149149

150150
You can help make it better by contributing. We welcome code contributions and ideas! See the documentation links below for more information.
151151

152+
## Docker
153+
154+
In the Loop can be run using Docker Compose for a complete production-like setup:
155+
156+
```bash
157+
# Build all services
158+
docker compose build
159+
160+
# Start all services
161+
docker compose up
162+
```
163+
164+
This starts three services:
165+
166+
- **Web** (http://localhost:5173) - Frontend application
167+
- **Sync** (http://localhost:8787) - Backend API and WebSocket sync
168+
- **Iframe Outputs** (http://localhost:8000) - Sandboxed output rendering
169+
170+
See **[Docker Guide](./DOCKER.md)** for detailed instructions on building and running individual services.
171+
152172
## Documentation
153173

154174
- **[Developing](./DEVELOPMENT.md)** - Developing in this repo
155175
- **[Contributing](./CONTRIBUTING.md)** - Contribute to this project
156176
- **[Deployment Guide](./DEPLOYMENT.md)** - Production deployment instructions
177+
- **[Docker Guide](./DOCKER.md)** - Docker build and run instructions
157178
- **[Roadmap](./ROADMAP.md)** - Development priorities and future plans
158179

159180
- **[AI Development Context](./AGENTS.md)** - An AGENTS.md file for contributors and AI agents.

nginx-main.conf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Main nginx configuration for In the Loop web app
2+
# The default nginx configuration causes this warning in the logs when running in hub:
3+
# nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
4+
# So we're overriding it here.
5+
events {
6+
worker_connections 1024;
7+
}
8+
9+
http {
10+
include /etc/nginx/mime.types;
11+
default_type application/octet-stream;
12+
13+
sendfile on;
14+
keepalive_timeout 65;
15+
16+
include /etc/nginx/conf.d/*.conf;
17+
}

nginx.conf

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
server {
2+
listen 5173;
3+
root /usr/share/nginx/html;
4+
index index.html;
5+
6+
gzip on;
7+
gzip_vary on;
8+
gzip_min_length 1024;
9+
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json;
10+
11+
# Health check endpoint
12+
location /healthz {
13+
access_log off;
14+
add_header Content-Type text/plain;
15+
return 200 "healthy\n";
16+
}
17+
18+
# Proxy API requests to backend
19+
location /api {
20+
proxy_pass http://${SYNC_HOST}:8787;
21+
proxy_http_version 1.1;
22+
proxy_set_header Upgrade $http_upgrade;
23+
proxy_set_header Connection 'upgrade';
24+
proxy_set_header Host $host;
25+
proxy_set_header X-Real-IP $remote_addr;
26+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
27+
proxy_set_header X-Forwarded-Proto $scheme;
28+
proxy_cache_bypass $http_upgrade;
29+
}
30+
31+
# Serve static files
32+
location / {
33+
try_files $uri $uri/ /index.html;
34+
}
35+
}
36+

0 commit comments

Comments
 (0)